Index: src/realmd/Main.cpp
===================================================================
--- src/realmd/Main.cpp (revision 23)
+++ src/realmd/Main.cpp (working copy)
@@ -256,10 +256,10 @@
///- Wait for termination signal
ListenSocket<AuthSocket> authListenSocket("0.0.0.0", rmport);
- if(authListenSocket.IsListernPortOpened())
+ if(authListenSocket.IsListenPortOpened())
sSocketManager.StartSocketThreads();
///- Wait for termination signal or listen socket closing
- while (!stopEvent && authListenSocket.IsListernPortOpened())
+ while (!stopEvent && authListenSocket.IsListenPortOpened())
{
Sleep(time_to_sleep);
if (RestToPing - time_to_sleep < 0)
Index: src/realmd/realmd.conf
===================================================================
--- src/realmd/realmd.conf (revision 23)
+++ src/realmd/realmd.conf (working copy)
@@ -1,58 +1,103 @@
-# MaNGOS realmd configuration file
+############################################
+# MaNGOS realmd configuration file #
+############################################
ConfVersion=2007062001
-# Database connection settings for the realm server.
-# Default: hostname;port;username;password;database
-# .;somenumber;username;password;database - use named pipes at Windows
-# Named pipes: mySQL required adding "enable-named-pipe" to [mysqld] section my.ini
-# .;/path/to/unix_socket;username;password;database - use Unix sockets at Unix/Linux
-# Unix sockets: experimental, not tested
-LoginDatabaseInfo = "127.0.0.1;3306;mangos;mangos;realmd"
+###################################################################################################################
+# REALMD SETTINGS
+#
+# LoginDatabaseInfo
+# Database connection settings for the realm server.
+# Default: hostname;port;username;password;database
+# .;somenumber;username;password;database - use named pipes at Windows
+# Named pipes: mySQL required adding "enable-named-pipe" to [mysqld] section my.ini
+# .;/path/to/unix_socket;username;password;database - use Unix sockets at Unix/Linux
+# Unix sockets: experimental, not tested
+#
+# LogsDir
+# Logs directory setting.
+# Important: Logs dir must exists, or all logs be disable
+# Default: "" - no log directory prefix, if used log names isn't absolute path then logs will be
+# stored in current directory for run program.
+#
+# MaxPingTime
+# Settings for maximum database-ping interval (minutes between pings)
+#
+# RealmServerPort
+# Default RealmServerPort
+#
+# BindIP
+# Bind Realm Server to IP/hostname
+#
+# PidFile
+# Realmd daemon PID file
+# Default: "" - do not create PID file
+# "./realmd.pid" - create PID file (recommended name)
+#
+# LogLevel
+# Server console level of logging
+# 0 = Minimum; 1 = Error; 2 = Detail; 3 = Full/Debug
+# Default: 0
+#
+# LogTime
+# Include time in server console output [hh:mm:ss]
+# Default: 0 (no time)
+# 1 (print time)
+#
+# LogFile
+# Logfile name
+# Default: "Realmd.log"
+# "" - empty name disable creating log file
+#
+# LogTimestamp
+# Logfile with timestamp of server start in name
+# Default: 0 - no timestamp in name
+# 1 - add timestamp in name in form Logname_YYYY-MM-DD_HH-MM-SS.Ext for Logname.Ext
+#
+# LogFileLevel
+# Server file level of logging
+# 0 = Minimum; 1 = Error; 2 = Detail; 3 = Full/Debug
+# Default: 0
+#
+# LogColors
+# Color for messages (format "normal_color details_color debug_color error_color)
+# Colors: 0 - BLACK, 1 - RED, 2 - GREEN, 3 - BROWN, 4 - BLUE, 5 - MAGENTA, 6 - CYAN, 7 - GREY,
+# 8 - YELLOW, 9 - LRED, 10 - LGREEN, 11 - LBLUE, 12 - LMAGENTA, 13 - LCYAN, 14 - WHITE
+# Default: "" - none colors
+# "13 7 11 9" - for example :)
+#
+# UseProcessors
+# Used processors mask for multi-processors system (Used only at Windows)
+# Default: 0 (selected by OS)
+# number (bitmask value of selected processors)
+#
+# ProcessPriority
+# Process proirity setting (Used only at Windows)
+# Default: 1 (HIGH)
+# 0 (Normal)
+#
+# RealmsStateUpdateDelay
+# Realm list Update up delay (updated at realm list request if delay expired).
+# Default: 20
+# 0 (Disabled)
+#
+#
+#
+#
+###################################################################################################################
-# Logs directory setting.
-# Important: Logs dir must exists, or all logs be disable
-# Default: "" - no log directory prefix, if used log names isn't absolute path then logs will be stored in current directory for run program.
+LoginDatabaseInfo = "127.0.0.1;3306;root;mangos;realmd"
LogsDir = ""
-
-# Settings for maximum database-ping interval (minutes between pings)
MaxPingTime = 30
-
-# Default RealmServerPort
RealmServerPort = 3724
-
-# Server console level of logging
-# 0 = Minimum; 1 = Error; 2 = Detail; 3 = Full/Debug
-# Default: 0
+BindIP = "0.0.0.0"
+PidFile = ""
LogLevel = 0
-
-# Logfile name
-# empty name disable creating log file: LogFile =
-# Default: "Server.log" - not recommended.
+LogTime = 0
LogFile = "Realmd.log"
-
-# Logfile with timestamp of server start in name
-# Default: 0 - no timestamp in name
-# 1 - add timestamp in name in form Logname_YYYY-MM-DD_HH-MM-SS.Ext for Logname.Ext
LogTimestamp = 0
-
-# Server file level of logging
-# 0 = Minimum; 1 = Error; 2 = Detail; 3 = Full/Debug
-# Default: 0
LogFileLevel = 0
-
-# Color for messages (format "normal_color details_color debug_color error_color)
-# Colors: 0 - BLACK, 1 - RED, 2 - GREEN, 3 - BROWN, 4 - BLUE, 5 - MAGENTA, 6 - CYAN, 7 - GREY,
-# 8 - YELLOW, 9 - LRED, 10 - LGREEN, 11 - LBLUE, 12 - LMAGENTA, 13 - LCYAN, 14 - WHITE
-# Default: "" - none colors
-# "13 7 11 9" - for example :)
LogColors = ""
-
-# Used processors mask for multi-processors system (Used only at Windows)
-# Default: 0 (selected by OS)
-# number (bitmask value of selected processors)
UseProcessors = 0
-
-# Process proirity setting (Used only at Windows)
-# 0 (Normal)
-# Default: 1 (HIGH)
ProcessPriority = 1
+RealmsStateUpdateDelay = 20
Index: src/realmd/Makefile.am
===================================================================
--- src/realmd/Makefile.am (revision 23)
+++ src/realmd/Makefile.am (working copy)
@@ -30,7 +30,7 @@
RealmList.h
## Link realm list daemon against the shared library
-mangos_realmd_LDADD = ../shared/Database/libmangosdatabase.a ../shared/Config/libmangosconfig.a ../shared/Auth/libmangosauth.a ../shared/libmangosshared.a ../shared/Network/libmangosnetwork.a ../framework/libmangosframework.a ../../dep/src/zthread/libZThread.la
+mangos_realmd_LDADD = ../shared/Database/libmangosdatabase.a ../shared/Config/libmangosconfig.a ../shared/Auth/libmangosauth.a ../shared/libmangosshared.a ../shared/NetworkNew/libmangosnetwork.a ../framework/libmangosframework.a ../../dep/src/zthread/libZThread.la
mangos_realmd_LDFLAGS = -L../../dep/src/zthread $(MYSQL_LIBS) $(LEVENT_LIB) $(POSTGRE_LIBS) -L$(libdir) $(ZLIB) $(COMPATLIB) $(SSLLIB)
## Additional files to include when running 'make dist'
Index: src/shared/NetworkNew/Network.h
===================================================================
--- src/shared/NetworkNew/Network.h (revision 0)
+++ src/shared/NetworkNew/Network.h (revision 0)
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2005,2006,2007 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __NETWORK_H__
+#define __NETWORK_H__
+
+#include "Common.h"
+#include "Socket.h"
+#include "SocketManager.h"
+#endif//__NETWORK_H__
Index: src/shared/NetworkNew/Mutex.cpp
===================================================================
--- src/shared/NetworkNew/Mutex.cpp (revision 0)
+++ src/shared/NetworkNew/Mutex.cpp (revision 0)
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2005,2006,2007 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include "Common.h"
+#include "Mutex.h"
+
+#ifdef WIN32
+#include <winbase.h>
+
+Mutex::Mutex(MutexType type)
+{
+ /*The InitializeCriticalSection function initializes
+ a critical section object.*/
+ ::InitializeCriticalSection(&m_cs);
+}
+
+Mutex::~Mutex()
+{
+ /*The DeleteCriticalSection function releases all
+ resources used by an unowned critical section object.*/
+ ::DeleteCriticalSection(&m_cs);
+}
+
+void Mutex::Lock()
+{
+ /*The EnterCriticalSection function waits for ownership of
+ the specified critical section object. The function returns
+ when the calling thread is granted ownership.*/
+ ::EnterCriticalSection(&m_cs);
+}
+
+void Mutex::Unlock()
+{
+ /*The LeaveCriticalSection function releases ownership of
+ the specified critical section object.*/
+ ::LeaveCriticalSection(&m_cs);
+}
+
+bool Mutex::TryLock()
+{
+ #if(_WIN32_WINNT >= 0x0400)
+ /*The TryEnterCriticalSection function attempts to enter a
+ critical section without blocking. If the call is successful,
+ the calling thread takes ownership of the critical section.*/
+ return ::TryEnterCriticalSection(&m_cs);
+ #else
+ return false;
+ #endif
+}
+
+#else
+/*
+Was used pthreadcc Library Version 1.01
+------------------------------
+Author: Jason But
+jason.but@eng.monash.edu.au
+*/
+
+/******************************************************************************/
+/* Mutex Constructor. */
+/* */
+/* We must create the internal MutEx of the right type. Based on the setup */
+/* parameter type, we set the mutexTheMutEx variable to be initialized with */
+/* the appropriate type parameters. */
+/******************************************************************************/
+Mutex::Mutex(MutexType type)
+{
+ pthread_mutexattr_t mattrDetails;
+ pthread_mutexattr_init(&mattrDetails);
+ switch (type)
+ {
+ case fastMutEx: pthread_mutexattr_settype(&mattrDetails, PTHREAD_MUTEX_NORMAL);
+ break;
+ case recursiveMutEx: pthread_mutexattr_settype(&mattrDetails, PTHREAD_MUTEX_RECURSIVE);
+ break;
+ case errorcheckMutEx: pthread_mutexattr_settype(&mattrDetails, PTHREAD_MUTEX_ERRORCHECK);
+ break;
+ }
+ pthread_mutex_init(&m_mutex, &mattrDetails);
+ pthread_mutexattr_destroy(&mattrDetails);
+}
+
+/******************************************************************************/
+/* Mutex Destructor. */
+/* */
+/* The class cannot be destroyed until the internal MutEx is also destroyed. */
+/* We do this by calling pthread_mutex_destroy() until it returns a success */
+/* code. If the MutEx is currently locked then we attempt to lock the MutEx */
+/* to wait for it to become free, we then immediately Unlock the mutex and */
+/* try to destroy it again. */
+/******************************************************************************/
+Mutex::~Mutex()
+{
+ while (pthread_mutex_destroy(&m_mutex) == EBUSY)
+ {
+ Lock();
+ Unlock();
+ }
+}
+
+/******************************************************************************/
+/* void Lock() */
+/* */
+/* This method attempts to lock the MutEx and returns true if successful, or */
+/* throws an exception on error. If the MutEx is of an error checking type */
+/* and the MutEx is already locked by the calling thread, a MutexWouldDeadlock*/
+/* exception is thrown. The lock is done by calling the pthread_mutex_lock() */
+/* function. If 0 is returned, the MutEx is now locked and we can return, if */
+/* EDEADLK is returned then we cannot lock the error checking MutEx without */
+/* causing a deadlock and we throw the exception. Any other return values */
+/* signifies either an unknown error type or that the MutEx has not been */
+/* properly initialized, which CANNOT happen within this class, an Unknown */
+/* MutEx exception is thrown. */
+/******************************************************************************/
+void Mutex::Lock()
+{
+ pthread_mutex_lock(&m_mutex);
+ /*
+ case 0: return;
+ case EDEADLK: throw ThreadException(ThreadException::errMutexWouldDeadlock);
+ default: throw ThreadException(ThreadException::errMutexUnknown);
+ */
+}
+
+/******************************************************************************/
+/* void UnLock() */
+/* */
+/* This method attempts to unlock the MutEx and returns if successful, or */
+/* throws an exception on error. If the MutEx is of an error checking type */
+/* and the calling thread did not lock the MutEx, a MutExNotOwned exception */
+/* is thrown. This is done by calling the pthread_mutex_unlock() function. */
+/* If 0 is returned, the MutEx is now unlocked and we can return, if EPERM is */
+/* returned then we cannot unlock the error checking MutEx and we throw the */
+/* exception. Any other return values signifies either an unknown error type */
+/* or that the MutEx has not been properly initialized, which CANNOT happen */
+/* within this class, an Unknown MutEx exception is thrown. */
+/******************************************************************************/
+void Mutex::Unlock()
+{
+ pthread_mutex_unlock(&m_mutex);
+ /*
+ case 0: return;
+ case EPERM: throw ThreadException(ThreadException::errMutexNotOwned);
+ default: throw ThreadException(ThreadException::errMutexUnknown);
+ */
+}
+
+/******************************************************************************/
+/* bool TryLock() */
+/* */
+/* This method attempts to lock the MutEx and returns true if successful and */
+/* false if the MutEx is already locked. This is done by calling the */
+/* pthread_mutex_trylock() function. If 0 is returned, the MutEx is now */
+/* locked and we can return true, if EBUSY is returned then we cannot lock */
+/* the MutEx and we return false. Any other return values signifies either */
+/* an unknown error type or that the MutEx has not been properly initialized, */
+/* which CANNOT happen within this class so we report a major error and */
+/* terminate the program. */
+/******************************************************************************/
+bool Mutex::TryLock()
+{
+ return pthread_mutex_trylock(&m_mutex) == 0;
+ /*
+ case 0: return true;
+ case EBUSY: return false;
+ default: throw ThreadException(ThreadException::errMutexUnknown);
+ */
+}
+#endif //!WIN32
+
+//@
Index: src/shared/NetworkNew/SocketManager.cpp
===================================================================
--- src/shared/NetworkNew/SocketManager.cpp (revision 0)
+++ src/shared/NetworkNew/SocketManager.cpp (revision 0)
@@ -0,0 +1,233 @@
+#include "SocketManager.h"
+#include "Policies/SingletonImp.h"
+#include "Util.h"
+
+#include "evutil.h"
+typedef struct bufferevent* PBUFFEREVENT;
+
+void
+io_handle_write(int fd, short event, void *arg);
+void
+io_handle_read(int fd, short event, void *arg);
+
+#ifndef WIN32
+ #define WSAECONNRESET 104
+#endif
+
+INSTANTIATE_SINGLETON_1(SocketManager);
+INSTANTIATE_SINGLETON_1(SocketManagerCleaner);
+
+timeval tv = {0, 50000};
+
+void event_log(int severity, const char *msg)
+{
+ if(!msg)
+ return;
+ switch (severity)
+ {
+ case _EVENT_LOG_DEBUG:
+ sLog.outDebug("<Libevent> %s", msg);
+ break;
+ case _EVENT_LOG_MSG:
+ sLog.outDetail("<Libevent> %s", msg);
+ break;
+ case _EVENT_LOG_WARN:
+ sLog.outDetail("<Libevent> %s", msg);
+ break;
+ case _EVENT_LOG_ERR:
+ sLog.outError("<Libevent> %s", msg);
+ break;
+ default:
+ sLog.outDetail("<Libevent> %s", msg);
+ }
+ return;
+}
+
+void SocketReaderRunnable::run()
+{
+ if(!sSocketManager.GetEventBase())
+ {
+ sLog.outError("<Socket manager> Couldn't start Socket worker thread. Event_base is wrong!");
+ return;
+ }
+
+ sLog.outBasic("<Socket manager> Socket worker thread is started");
+
+ while(1)
+ {
+ Sleep(10);
+ if( event_base_loop(sSocketManager.GetEventBase(), 0) == -1 )
+ {
+ sLog.outError("<Socket manager> Critical error is occured in event_loot. Exit.");
+ sSocketManager.DisconnectAll();
+ return;
+ }
+ }
+ sLog.outBasic("<Socket manager> Socket worker thread is finished");
+}
+
+SocketManager::SocketManager()
+{
+ m_event_base = (event_base*)event_init();
+ if(!m_event_base)
+ sLog.outError("<Socket manager> FATAL ERROR! Couldn't start libevent!");
+ else
+ {
+ event_set_log_callback(event_log);
+ sLog.outBasic("<Socket manager> MaNGOS network uses [%s] event mechanism", event_get_method());
+ }
+ event_base_dispatch(GetEventBase());
+}
+
+SocketManager::~SocketManager()
+{
+ event_base_free(GetEventBase());
+}
+
+bool SocketManager::AddSocket(SocketBase* pSocket)
+{
+ m_Mutex.Lock();
+ m_sockets.insert(pSocket);
+ m_Mutex.Unlock();
+
+
+ event_set(&pSocket->m_ev_read, (int)pSocket->GetSocket(), EV_READ | EV_PERSIST, io_handle_read, pSocket);
+ event_base_set(GetEventBase(), &pSocket->m_ev_read);
+
+ if(event_add(&pSocket->m_ev_read, &tv) == -1)
+ return false;
+
+ event_set(&pSocket->m_ev_write, (int)pSocket->GetSocket(), EV_WRITE, io_handle_write, pSocket);
+ event_base_set(GetEventBase(), &pSocket->m_ev_write);
+
+ return true;
+}
+
+bool SocketManager::RemoveSocket(SocketBase* pSocket)
+{
+ //Don't call "delete" for socket!
+ if(!pSocket)
+ return false;
+ m_Mutex.Lock();
+ m_sockets.erase(pSocket);
+ m_Mutex.Unlock();
+ sLog.outDebug("<Socket %u> Removed from manager", pSocket->GetSocket());
+ event_del(&pSocket->m_ev_read);
+ event_del(&pSocket->m_ev_write);
+ return true;
+}
+
+void SocketManager::DisconnectAll()
+{
+ m_Mutex.Lock();
+ SocketSet _tempSocketSet(m_sockets.begin(), m_sockets.end());
+ m_Mutex.Unlock();
+ for (SocketSet::iterator _it = _tempSocketSet.begin(); _it != _tempSocketSet.end(); ++_it)
+ {
+ Socket* pSocket = (Socket*)(*_it);
+ if(pSocket)
+ pSocket->Disconnect();
+ }
+ _tempSocketSet.clear();
+}
+
+#ifdef USE_LEVENT
+
+void io_handle_read(int fd, short event, void *arg)
+{
+ if(!arg)
+ {
+ sLog.outError("<Socket unknown> Bad (null) param in read callback.");
+ return;
+ }
+
+ Socket* pSocket = (Socket*)arg;
+ if(!pSocket->IsConnected())
+ return;
+
+ if(event & EV_TIMEOUT)
+ {
+ event_add(&pSocket->m_ev_read, &tv);
+ return;
+ }
+
+ pSocket->OnReadEvent();
+ if(!pSocket->IsConnected()) //Socket can be disconnected after read callback,
+ return; //so we mast check it
+ event_add(&pSocket->m_ev_read, &tv);
+}
+
+void
+io_handle_write(int fd, short event, void *arg)
+{
+ if(!arg)
+ {
+ sLog.outError("<Socket unknown> Bad (null) param in read callback.");
+ return;
+ }
+
+ Socket* pSocket = (Socket*)arg;
+ if(!pSocket->IsConnected())
+ return;
+
+ //Lock buffer to send
+ pSocket->LockWriting();
+ int n = send(
+ pSocket->GetSocket(),
+ (char*)pSocket->WriteBuffer()->get_buffer(),
+ pSocket->WriteBuffer()->get_data_size(), 0);
+
+ if(n != SOCKET_ERROR)
+ {
+ //for DEBUG only!
+ if(n == 0)
+ sLog.outError("DEBUG.Rognar: sent in socket [%u] zero bytes!", pSocket->GetSocket());
+
+ //Remove sent data from output buffer
+ pSocket->WriteBuffer()->remove(n);
+
+ if (pSocket->WriteBuffer()->get_data_size())
+ {//We still have data. reschedule sending
+ if(event_add(&pSocket->m_ev_write, NULL) == -1)
+ {
+ sLog.outError("<Socket %u> Couldn't reschedule sending.", pSocket->GetSocket());
+ pSocket->UnlockWriting();
+ pSocket->Disconnect(true);
+ return;
+ }
+ }
+ }
+ pSocket->UnlockWriting();
+ if (n == -1)
+ {
+ if (errno == EAGAIN || errno == EINTR)
+ {
+ //"Resource temporarily unavailable"
+ //This error is returned from operations on nonblocking sockets that cannot be completed immediately,
+ //for example recv when no data is queued to be read from the socket.
+ //It is a nonfatal error, and the operation should be retried later.
+ //It is normal for WSAEWOULDBLOCK to be reported as the result from calling connect
+ //on a nonblocking SOCK_STREAM socket, since some time must elapse for the connection to be established.
+ if(event_add(&pSocket->m_ev_write, NULL) == -1)
+ {
+ pSocket->Disconnect(true);
+ return;
+ }
+ }
+ pSocket->Disconnect(true);
+ return;
+ }
+}
+
+
+void SocketManager::StartSocketThreads()
+{
+ ZThread::Thread SocketCleaner(new SocketManagerCleaner);
+ ZThread::Thread tSocketReader(new SocketReaderRunnable);
+}
+
+void SocketManager::StopSocketThreads()
+{
+ //event_base_loopbreak(GetEventBase());
+}
+#endif //USE_LEVENT
Index: src/shared/NetworkNew/Mutex.h
===================================================================
--- src/shared/NetworkNew/Mutex.h (revision 0)
+++ src/shared/NetworkNew/Mutex.h (revision 0)
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2005,2006,2007 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __MUTEX_07072007__H__
+#define __MUTEX_07072007__H__
+#include "Common.h"
+class Mutex
+{
+ public:
+ friend class Condition;
+
+ //Only for Non-Win32/Non-Win64 OS !!
+ enum MutexType
+ { fastMutEx, recursiveMutEx, errorcheckMutEx };
+ //Description
+ /******************************************************************************/
+ /* class Mutax. */
+ /* */
+ /* This class encapsulates the basic MutEx functionality into a C++ class. */
+ /* The constructor is used to create the MutEx of a certain type, the default */
+ /* type being fastMutEx. The destructor will destroy the MutEx. The Lock() */
+ /* and Unlock() methods do as expected while TryLock() will lock the MutEx if */
+ /* possible but will not block if locking is not possible. Details of these */
+ /* member methods are: */
+ /* */
+ /*----------------------------------------------------------------------------*/
+ /* MutEx Type | | | */
+ /*--------- | fastMutEx | recursiveMutEx | errorcheckMutEx */
+ /* Method | | | | */
+ /*----------------------------------------------------------------------------*/
+ /* Lock() | Block until MutEx | Block until MutEx | Block until MutEx */
+ /* | is free. If MutEx | is free. If Mutex | is free. If Mutex */
+ /* | is owned by calling | is owned by calling | is owned by the */
+ /* | thread, Deadlock | thread, return true | calling thread, */
+ /* | occurs. | and increment count | throw a MutEx */
+ /* | | of number of locks. | Would Deadlock */
+ /* | | | exception. */
+ /*----------------------------------------------------------------------------*/
+ /* Unlock() | Unlock the MutEx. | Decrement count of | If the MutEx is */
+ /* | | locks, if 0, unlock | currently locked */
+ /* | | the MutEx. | by the calling */
+ /* | | | thread then */
+ /* | | | unlock the MutEx, */
+ /* | | | otherwise throw a */
+ /* | | | MutEx Not Owned */
+ /* | | | exception. */
+ /*----------------------------------------------------------------------------*/
+ /* TryLock() | Try to lock the | Same functionality | Try to lock the */
+ /* | MutEx, return true | as Lock() | MutEx, return true*/
+ /* | if successful, or | | if successful, or */
+ /* | false if MutEx is | | false if MutEx is */
+ /* | already locked. | | already locked. */
+ /*----------------------------------------------------------------------------*/
+ /* */
+ /* NOTE: The Condition Class is a friend of the MutualExclusion class since */
+ /* it needs access to the private mutexTheMutex member variable. */
+ /******************************************************************************/
+
+ Mutex(MutexType type = recursiveMutEx);
+ ~Mutex();
+
+ void Lock();
+ void Unlock();
+ bool TryLock();
+
+ protected:
+ #ifdef WIN32
+ CRITICAL_SECTION m_cs;
+ #else
+ pthread_mutex_t m_mutex;
+ #endif
+};
+
+//AutoLock _AutoLock(var)
+class AutoLock
+{
+public:
+ AutoLock(Mutex& _mutex): mMutex(_mutex) { mMutex.Lock(); }
+ ~AutoLock() { mMutex.Unlock(); }
+private:
+ Mutex& mMutex;
+};
+
+
+#endif//__MUTEX_07072007__H__
+
+//@
Index: src/shared/NetworkNew/Socket.cpp
===================================================================
--- src/shared/NetworkNew/Socket.cpp (revision 0)
+++ src/shared/NetworkNew/Socket.cpp (revision 0)
@@ -0,0 +1,483 @@
+/*
+ * Copyright (C) 2005,2006,2007 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "Socket.h"
+#include "SocketManager.h"
+#include <stdarg.h>
+
+namespace MaNGOS_Network
+{
+ std::string GetHostIP()
+ {
+ std::string sRet= "<unknown host>";
+ hostent* pThisHost = gethostbyname("");
+ if (!pThisHost)
+ return sRet;
+
+ char* pIP = inet_ntoa (*(struct in_addr *)*pThisHost->h_addr_list);
+ if (!pIP)
+ return sRet;
+
+ sRet = std::string(pIP);
+ return sRet;
+ }
+};
+
+//////////////////////////////////////////////////////////////////////////
+//DataBuffer class implementation
+DataBuffer::DataBuffer():
+m_pBuffer(NULL), m_bInitialized(false){}
+
+DataBuffer::~DataBuffer()
+{
+ if(m_bInitialized)
+ Destroy();
+}
+
+void DataBuffer::Destroy()
+{
+ m_bInitialized = false;
+ if (m_pBuffer)
+ {
+ free(m_pBuffer);
+ m_pBuffer = NULL;
+ }
+}
+
+bool DataBuffer::Initialize(IN uint32 unDefSize)
+{
+ if (m_bInitialized)
+ return true;
+
+ m_pBuffer = (uint8*)malloc(unDefSize);
+ m_unDefSize = unDefSize;
+ m_Offset = 0;
+ m_bInitialized = (m_pBuffer != NULL);
+ return m_bInitialized;
+}
+
+bool DataBuffer::append(IN const uint8* pSource, IN uint32 unSize)
+{
+ if (!m_bInitialized || !pSource)
+ return false;
+
+ if (unSize == 0)
+ return true;
+
+
+ while (unSize > get_free_size())
+ {
+ // Reallocate
+ uint8* pTempBuffer = m_pBuffer; // save pointer in case realloc fails
+
+ m_unDefSize += CHUNK*((unSize - get_free_size())/CHUNK) + CHUNK;
+
+ m_pBuffer = (uint8*)realloc(m_pBuffer, m_unDefSize);
+ if(!m_pBuffer)
+ {
+ sLog.outError("Reallocation of socket buffer is failed");
+ m_pBuffer = pTempBuffer;
+ Destroy();
+ return false;
+ }
+ }
+ //copies to destination buffer
+ memcpy(m_pBuffer + m_Offset, (void*)pSource, unSize);
+ m_Offset += unSize;
+ return true;
+}
+
+// Retrieves and removes data from the buffer.
+void DataBuffer::extract(OUT uint8* pDest, IN uint32 unSize)
+{
+ if (!m_bInitialized || !pDest || unSize == 0)
+ {
+ unSize = 0;
+ return;
+ }
+
+ uint32 unBytes = std::min(unSize, m_Offset);
+
+ //copies to destination buffer
+ memcpy(pDest, (void*)m_pBuffer, unBytes);
+ // ASSERT(unBytes <= m_Offset);
+
+ //moves the rest to the begin
+ memmove(m_pBuffer, m_pBuffer + unBytes, m_Offset - unBytes);
+
+ //change offset according to count of copied bytes
+ m_Offset -= unBytes;
+}
+
+void DataBuffer::peek(OUT uint8* pDest, INOUT uint32 unSize)
+{
+ if (!m_bInitialized || !pDest || unSize == 0)
+ {
+ unSize = 0;
+ return;
+ }
+
+ uint32 unBytes = std::min(unSize, m_Offset);
+ //copies to destination buffer
+ memcpy(pDest, (void*)m_pBuffer, unBytes);
+}
+
+uint32 DataBuffer::get_data_size() const
+{
+ return m_Offset;
+}
+
+uint32 DataBuffer::get_free_size() const
+{
+ return m_unDefSize - m_Offset;
+}
+
+void DataBuffer::remove(IN uint32 unSize)
+{
+ if (!m_bInitialized || unSize == 0)
+ return;
+
+ uint32 unBytes = std::min(unSize, m_Offset);
+ if (unBytes == m_Offset)
+ {
+ m_Offset = 0;
+ return;
+ }
+ memmove(m_pBuffer, m_pBuffer + unBytes, m_Offset - unBytes);
+ m_Offset -= unBytes;
+}
+
+bool DataBuffer::has_data() const
+{
+ return get_data_size() != 0;
+}
+
+uint8* DataBuffer::get_buffer()
+{
+ return m_pBuffer;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//Socket base class implementation
+Socket::Socket(SOCKET hSocket, uint32 unInputBufferSize, uint32 unOutputBufferSize):
+ SocketBase(hSocket), m_bAbleToSend(true)
+{
+ WriteBuffer()->Initialize(unOutputBufferSize);
+ ReadBuffer()->Initialize(unInputBufferSize);
+
+ if (m_SocketHandle == INVALID_SOCKET)
+ m_SocketHandle = socket(AF_INET, SOCK_STREAM, 0);
+
+ u_long arg = 1;
+ if(ioctlsocket(GetSocket(), FIONBIO, &arg) == SOCKET_ERROR)
+ sLog.outError("<Socket %u> Couldn't set nonblocking mode.", GetSocket());
+}
+
+Socket::~Socket()
+{
+ sLog.outDebug("Calls Socket::~Socket()\n");
+ WriteBuffer()->Destroy();
+ ReadBuffer()->Destroy();
+ if (m_bConnected)
+ {
+ m_bConnected = false;
+ if(m_SocketHandle != INVALID_SOCKET)
+ {
+ ::shutdown(m_SocketHandle, SD_BOTH);
+ ::closesocket(m_SocketHandle);
+ }
+ m_SocketHandle = INVALID_SOCKET;
+ sSocketManager.RemoveSocket(this);
+ }
+}
+
+bool Socket::Connect(const char* szAddress, uint32 unPort)
+{
+ //Function retrieves host information corresponding to a host name from a host database
+ struct hostent* pHostInfo = ::gethostbyname(szAddress);
+ if(!pHostInfo)
+ {
+ //Log "Could'n connect to [%s:%u], szAddress, unPort"
+ return false;
+ }
+
+ m_client.sin_family = pHostInfo->h_addrtype;
+ m_client.sin_port = ntohs((u_short)unPort);
+ memcpy(&m_client.sin_addr.s_addr, pHostInfo->h_addr_list[0], pHostInfo->h_length);
+
+ //Function establishes a connection to a specified socket
+ if(connect(GetSocket(), (const sockaddr*)&m_client, sizeof(m_client)) == SOCKET_ERROR)
+ {
+ #ifdef WIN32
+ sLog.outError("<Socket %u> Couldn't connect to [%s]. Error [%u]", GetSocket(), GetRemoteAddress().c_str(), ::WSAGetLastError());
+ #else
+ sLog.outError("<Socket %u> Couldn't connect to [%s].", GetSocket(), GetRemoteAddress().c_str());
+ #endif//WIN32
+ return false;
+ }
+
+ sLog.outDebug("<Socket %u> Connected to [%s:%u] successfully", (uint32)GetSocket(), szAddress, unPort);
+ SetOptions();
+ m_bConnected = true;
+ if(!sSocketManager.AddSocket(this))
+ return false;
+ //Notify "child"
+ OnConnect();
+ return true;
+}
+
+//New socket connection accepted
+bool Socket::Accept(IN sockaddr_in* psAddress)
+{
+ if (!psAddress)
+ return false;
+
+ sLog.outDebug("<Socket %u> New connection accepted.", GetSocket());
+
+ //Assign client information
+ memcpy(&m_client, psAddress, sizeof(*psAddress));
+ //SetOptions();
+ m_bConnected = true;
+ if(!sSocketManager.AddSocket(this))
+ return false;
+ //Notify "child"
+ OnConnect();
+ return true;
+}
+
+void Socket::SetOptions()
+{
+ //////////////////////////////////////////////////////////////////////////
+ // "Microsoft Press - 1999 - Network Programming For MS Windows"
+ //
+ //In order to increase performance and throughput by minimizing overhead,
+ //the system implements the Nagle algorithm. When an application requests
+ //to send a chunk of data, the system might hold on to that data for a while
+ //and wait for other data to accumulate before actually sending it on the wire.
+ //Of course, if no other data accumulates in a given period of time, the data
+ //will be sent regardless. This results in more data in a single TCP packet,
+ //as opposed to smaller chunks of data in multiple TCP packets.
+ //The overhead is that the TCP header for each packet is 20 bytes long.
+ //Sending a couple bytes here and there with a 20-byte header is wasteful.
+ //The other part of this algorithm is the delayed acknowledgments.
+ //Once a system receives TCP data it must send an ACK to the peer.
+ //However, the host will wait to see whether it has data it is sending to
+ //the peer so that it can piggyback the ACK on the data to be sent resulting in one less packet on the network.
+ //The purpose of this option is to disable the Nagle algorithm, as its behavior can be detrimental in a few cases.
+ //This algorithm can adversely affect any network application that sends relatively small amounts of data and expects
+ //a timely response. A classic example is Telnet. Telnet is an interactive application that allows the user
+ //to log on to a remote machine and send it commands. Typically the user hits only a few keystrokes per second.
+ //The Nagle algorithm would make such a session seem sluggish and unresponsive.
+ int arg2 = 1;
+ if(setsockopt(GetSocket(), IPPROTO_TCP, TCP_NODELAY, (char*)&arg2, sizeof(arg2)) == SOCKET_ERROR)
+#ifdef WIN32
+ sLog.outError("<Socket %u> Couldn't set option TCP_NODELAY. Error [%u]", GetSocket(), WSAGetLastError());
+#else
+ sLog.outError("<Socket %u> Couldn't set option TCP_NODELAY", GetSocket());
+#endif//WIN32
+}
+
+void Socket::Disconnect(bool bAbort)
+{
+ if(!m_bConnected)
+ return;
+ if(bAbort)
+ sLog.outError("<Socket %u> Abortively disconnected.", GetSocket());
+ else
+ sLog.outDetail("<Socket %u> Gracefully disconnected.", GetSocket());
+ m_bConnected = false;
+ if(m_SocketHandle != INVALID_SOCKET)
+ {
+ //////////////////////////////////////////////////////////////////////////
+ //shutdown
+ //To ensure that all data an application sends is received by the peer,
+ //a well-written application should notify the receiver that no more data is to be sent.
+ //SD_BOTH disables both sends and receives
+ ::shutdown(m_SocketHandle, SD_BOTH);
+
+ //////////////////////////////////////////////////////////////////////////
+ //closesocket
+ //The closesocket function closes a socket
+ //Calling closesocket releases the socket descriptor and any further calls using the socket fail with WSAENOTSOCK.
+ //If there are no other references to this socket, all resources associated with the descriptor are released.
+ //This includes discarding any queued data.
+ ::closesocket(m_SocketHandle);
+ }
+ sSocketManager.RemoveSocket(this);
+ m_SocketHandle = INVALID_SOCKET;
+ OnDisconnect();
+}
+
+//////////////////////////////////////////////////////////////////////////
+//LibEvent implementation
+#ifdef USE_LEVENT
+
+bool Socket::Send(IN const uint8* pSrc, INOUT uint32 unSize)
+{
+ if(!m_bConnected)
+ return false;
+
+ LockWriting();
+ WriteBuffer()->append(pSrc, unSize);
+ int res = event_add(&m_ev_write, NULL);
+ UnlockWriting();
+ if(res == -1)
+ {
+ sLog.outError("Socket::Send couldn't add write event");
+ }
+ return (res != -1);
+}
+
+void Socket::OnReadEvent()
+{
+ if(!m_bConnected)
+ return;
+
+ //TODO peak MSG_PEEK
+ LockReading();
+ uint32 iosize = recv(GetSocket(),
+ (char*)(ReadBuffer()->get_buffer() + ReadBuffer()->get_data_size()),
+ ReadBuffer()->get_free_size(), 0);
+
+ if (iosize == 0 || iosize == -1)
+ {//If the connection has been gracefully closed, the return value is zero.
+ //If the connection has been abortively closed, the return value is SOCKET_ERROR.
+ UnlockReading();
+ Disconnect(iosize == -1);
+ return;
+ }
+
+ ReadBuffer()->get_offset() += iosize;
+ UnlockReading();
+ OnRead();
+}
+
+#endif//USE_LEVENT
+//////////////////////////////////////////////////////////////////////////
+
+void Socket::Sendf(const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ char slask[5000]; // vsprintf / vsnprintf temporary
+#ifdef _WIN32
+ vsprintf(slask, format, ap);
+#else
+ vsnprintf(slask, 5000, format, ap);
+#endif
+ va_end(ap);
+ Send((uint8*)slask, strlen(slask));
+}
+
+
+std::string Socket::GetRemoteAddress()
+{
+ char* szIP = (char*)inet_ntoa(m_client.sin_addr);
+ std::string sRemoteAddress = "<unknown>";
+ if (szIP)
+ sRemoteAddress = std::string(szIP);
+ return sRemoteAddress;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//IOCP implementation
+#ifdef USE_IOCP
+bool Socket::Send(IN const uint8* pSrc, INOUT uint32 unSize)
+{
+ if(!unSize)
+ return false;
+
+ LockWriting();
+ if(!WriteBuffer()->append(pSrc, unSize))
+ {
+ UnlockWriting();
+ return false;
+ }
+
+ if (!m_bAbleToSend)
+ {
+ UnlockWriting();
+ return true;
+ }
+ m_bAbleToSend = false;
+ bool bres = SendBuffer();
+ UnlockWriting();
+ return bres;
+}
+
+void Socket::SendComplete(uint32 dwIoSize)
+{
+ if (!dwIoSize)
+ {
+ Disconnect(true);
+ return;
+ }
+
+ LockWriting();
+ WriteBuffer()->remove(dwIoSize);
+ if (WriteBuffer()->get_data_size())
+ SendBuffer();
+ else
+ m_bAbleToSend = true;
+ UnlockWriting();
+}
+
+void Socket::ReadComplete(uint32 dwIoSize)
+{
+ if (dwIoSize > ReadBuffer()->get_free_size())
+ {
+ sLog.outError("<Socket %u> Read buffer is overflowed", GetSocket());
+ Disconnect(true);
+ return;
+ }
+ ReadBuffer()->get_offset() += dwIoSize;
+ OnRead();
+}
+
+bool Socket::SendBuffer()
+{
+ if(WriteBuffer()->get_data_size())
+ {
+ ULONG ulFlags = 0;
+ DWORD dwSendNumBytes = 0;
+ IOCPBuffer *pOverlapBuff = new IOCPBuffer();
+ pOverlapBuff->SetupWrite((char*)WriteBuffer()->get_buffer(), WriteBuffer()->get_data_size());
+ int err = WSA_IO_PENDING;
+ if(::WSASend(GetSocket(), pOverlapBuff->GetWSABuffer(), 1, &dwSendNumBytes, ulFlags, &pOverlapBuff->m_ol, NULL) == SOCKET_ERROR &&
+ WSAGetLastError() != WSA_IO_PENDING
+ //The error code WSA_IO_PENDING indicates that the overlapped
+ //operation has been successfully initiated and that completion
+ //will be indicated at a later time. Any other error code
+ //indicates that the overlapped operation was not successfully
+ //initiated and no completion indication will occur.
+ )
+ {
+ Disconnect();
+ delete pOverlapBuff;
+ pOverlapBuff = NULL;
+ }
+ return true;
+ }
+ else
+ {
+ IOCPBuffer *pOverlapBuff = new IOCPBuffer(IOWriteCompleted);
+ return TRUE == ::PostQueuedCompletionStatus(GetIOCompletionPort(), 0, (DWORD)this, &pOverlapBuff->m_ol);
+ }
+}
+#endif//USE_IOCP
+//////////////////////////////////////////////////////////////////////////
Index: src/shared/NetworkNew/SocketManager.h
===================================================================
--- src/shared/NetworkNew/SocketManager.h (revision 0)
+++ src/shared/NetworkNew/SocketManager.h (revision 0)
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2005,2006,2007 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __SOCKET_MANAGER_H__
+#define __SOCKET_MANAGER_H__
+
+#include "Mutex.h"
+#include "Policies/Singleton.h"
+#include "Network.h"
+#include "../Log.h"
+
+#define WORKER_THREADS_PER_PROCESSOR 2
+typedef std::set<SocketBase*> SocketSet;
+
+class SocketManager : public MaNGOS::Singleton<SocketManager, MaNGOS::ClassLevelLockable<SocketManager, ZThread::FastMutex> >
+{
+ public:
+ SocketManager();
+ ~SocketManager();
+
+ public:
+ bool AddSocket(SocketBase* pSocket);
+ bool RemoveSocket(SocketBase* pSocket);
+ void DisconnectAll();
+
+ void StartSocketThreads();
+ void StopSocketThreads();
+
+ public:
+ event_base* GetEventBase() {return m_event_base;}
+
+ private:
+ struct event_base* m_event_base;
+ Mutex m_Mutex;
+ int m_iIOWorkersCount;
+ SocketSet m_sockets;
+};
+
+#define sSocketManager MaNGOS::Singleton<SocketManager>::Instance()
+
+class SocketReaderRunnable : public ZThread::Runnable
+{
+public:
+ void run();
+};
+
+class SocketWriterRunnable : public ZThread::Runnable
+{
+public:
+ void run();
+};
+//Temporary, but necessary :(
+class SocketManagerCleaner :
+ public MaNGOS::Singleton<SocketManagerCleaner, MaNGOS::ClassLevelLockable<SocketManagerCleaner, ZThread::FastMutex> >,
+ public ZThread::Runnable
+{
+ public:
+ SocketManagerCleaner()
+ {
+ m_stopEvent = false;
+ }
+ ~SocketManagerCleaner()
+ {
+ MapToClean::iterator it;
+ while (!toClean.empty())
+ {
+ it = toClean.begin();
+ delete it->first;
+ toClean.erase(it);
+ }
+ }
+
+ typedef std::map<SocketBase*, time_t> MapToClean;
+ void Add(SocketBase* pSocket)
+ {
+ if(!pSocket)
+ return;
+ if(pSocket->IsConnected())
+ {
+ sLog.outError("Abnormal!! Connected socket is marked to delete. Skipped");
+ return;
+ }
+
+ mMutex.Lock();
+ time_t _time = time(NULL);
+ toClean[pSocket] = _time + 5;
+ mMutex.Unlock();
+ }
+
+ void run() // WIN32
+ {
+ while (!m_stopEvent)
+ {
+ Sleep(100);
+ mMutex.Lock();
+ time_t _current_time = time(NULL);
+ MapToClean::iterator it1, it2;
+ for (it1 = toClean.begin(); it1 != toClean.end();)
+ {
+ it2 = it1++;
+ if (it2->second < _current_time)
+ {
+ delete it2->first;
+ toClean.erase(it2);
+ }
+ }
+ mMutex.Unlock();
+ }
+ toClean.clear();
+ }
+
+ void Stop(){ m_stopEvent = true; }
+ bool m_stopEvent;
+ Mutex mMutex;
+ MapToClean toClean;
+};
+
+#define sAuthSocketManagerCleaner MaNGOS::Singleton<SocketManagerCleaner>::Instance()
+#endif //__SOCKET_MANAGER_H__
Index: src/shared/NetworkNew/ListenSocket.h
===================================================================
--- src/shared/NetworkNew/ListenSocket.h (revision 0)
+++ src/shared/NetworkNew/ListenSocket.h (revision 0)
@@ -0,0 +1,114 @@
+#ifndef __LISTER_SOCKET_NWIN32_H__
+#define __LISTER_SOCKET_NWIN32_H__
+
+#include "Common.h"
+#include "Log.h"
+
+template<class T>
+class ListenSocket:
+ public SocketBase
+{
+public:
+ ListenSocket(const char* szListenAddress, int unPort):
+ m_bSocketCreated(false)
+ {
+ do
+ {
+ if((m_SocketHandle = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR)
+ {
+ sLog.outError("<Listen socket> Couldn't create socket");
+ break;
+ }
+
+ int on = 1;
+ if (setsockopt(m_SocketHandle, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on)) == SOCKET_ERROR)
+ {
+ sLog.outError("<Listen socket %u> Couldn't set option SO_REUSEADDR",
+ m_SocketHandle);
+ break;
+ }
+
+ u_long arg = 1;
+ if(ioctlsocket(m_SocketHandle, FIONBIO, &arg) == SOCKET_ERROR)
+ {
+ sLog.outError("<Listen socket %u> Couldn't set nonblocking mode",
+ m_SocketHandle);
+ break;
+ }
+
+ sockaddr_in address;
+ if(!strcmp(szListenAddress, "0.0.0.0"))
+ address.sin_addr.s_addr = htonl(INADDR_ANY);
+ else
+ {
+ hostent* h = gethostbyname(szListenAddress);
+ if(!h)
+ {
+ sLog.outError("<Listen socket %u> Couldn't retrieve host information corresponding "
+ "to a host name from a host database",
+ m_SocketHandle);
+ break;
+ }
+
+ memcpy(&address.sin_addr, h->h_addr_list[0], sizeof(in_addr));
+ }
+
+ address.sin_family = AF_INET;
+ address.sin_port = ntohs(unPort);
+ if (bind(m_SocketHandle, (const sockaddr*)&address, sizeof(sockaddr_in)) == SOCKET_ERROR)
+ {
+ sLog.outError("<Listen socket %u> Couldn't associate a local address with a socket",
+ m_SocketHandle);
+ break;
+ }
+
+ if (listen(m_SocketHandle, 1024) == SOCKET_ERROR)
+ {
+ sLog.outError("<Listen socket %u> Couldn't place a socket in a state in which it"
+ " is listening for an incoming connection",
+ m_SocketHandle);
+ break;
+ }
+ m_bSocketCreated = true;
+ }
+ while(false);
+
+ if (m_bSocketCreated && sSocketManager.AddSocket(this))
+ sLog.outBasic("<Listen socket %u> Listening started...", m_SocketHandle);
+ else
+ {
+ sLog.outError("<Listen socket %u> Creating failed", m_SocketHandle);
+ StopListening();
+ }
+ }
+
+ void Disconnect(bool bAbort = false) { StopListening(); }
+ bool IsConnected() { return IsListenPortOpened(); }
+ bool IsListenPortOpened() { return m_bSocketCreated;}
+
+ void OnReadEvent()
+ {
+ struct sockaddr_in ClientAddress;
+ socklen_t addrlen = sizeof(ClientAddress);
+ SOCKET client_sock;
+ if ((client_sock = accept(m_SocketHandle, (sockaddr*)&ClientAddress, &addrlen)) == INVALID_SOCKET)
+ {
+ sLog.outError("<Listen socket %u> Couldn't accept connection. Some error. Skipped.", m_SocketHandle);
+ return;
+ }
+ T* pSocket = new T(client_sock);
+ pSocket->Accept(&ClientAddress);
+ }
+
+ void StopListening()
+ {
+ sLog.outBasic("<Listen socket %u> Listen socket closed", m_SocketHandle);
+ sSocketManager.RemoveSocket(this);
+ ::closesocket(m_SocketHandle);
+ m_bSocketCreated = false;
+ }
+
+private:
+ bool m_bSocketCreated;
+};
+#endif//__LISTER_SOCKET_NWIN32_H__
Index: src/shared/NetworkNew/Socket.h
===================================================================
--- src/shared/NetworkNew/Socket.h (revision 0)
+++ src/shared/NetworkNew/Socket.h (revision 0)
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2005,2006,2007 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __SOCKET_BASE_IMPL_H__
+#define __SOCKET_BASE_IMPL_H__
+
+#include "Common.h"
+#include "Mutex.h"
+#include <fcntl.h>
+
+//Returns the local IP Address
+namespace MaNGOS_Network
+{
+ std::string GetHostIP();
+};
+
+//Input
+#define IN
+
+//Output
+#define OUT
+
+//In/Out
+#define INOUT
+
+#ifndef note
+#define _note_str(x) #x
+#define note_str(x) _note_str(x)
+#define note(desc) message(__FILE__ "(" note_str(__LINE__) ") : Note: " ##desc)
+#endif //note
+//How to use it: #pragma note("Message text")
+
+//////////////////////////////////////////////////////////////////////////
+//DataBuffer class declaration
+#define CHUNK (16384)
+class DataBuffer
+{
+ public:
+ //Constructor
+ DataBuffer();
+
+ // Destruction.
+ virtual ~DataBuffer();
+
+ // Allocates memory.
+ bool Initialize(IN uint32 unDefSize);
+
+ // Deallocates memory.
+ void Destroy();
+
+ // Appends data to the buffer.
+ bool append(IN const uint8* pSrc, IN uint32 unSize);
+
+ // Retrieves and removes data from the buffer.
+ void extract(OUT uint8* pDest, IN uint32 unSize);
+
+ // Retrieves data from the buffer, does not remove.
+ void peek(OUT uint8* pDest, INOUT uint32 unSize);
+
+ // Returns the number of bytes available for extraction.
+ uint32 get_data_size() const;
+
+ // Returns the number of bytes available for appending.
+ uint32 get_free_size() const;
+
+ // Removes a number of bytes from the buffer.
+ void remove(IN uint32 size);
+
+ // Checks whether the buffer has data.
+ bool has_data() const;
+
+ uint32& get_offset(){return m_Offset;}
+
+ // Retrieves buffer.
+ uint8* get_buffer();
+
+ private:
+ bool m_bInitialized;
+ uint8* m_pBuffer;
+ uint32 m_Offset;
+ uint32 m_unDefSize;
+};
+
+//////////////////////////////////////////////////////////////////////////
+//Socket base class declaration
+#define RECVBUF_SIZE (16384)
+#define SENDBUF_SIZE (65536)
+
+class SocketBase
+{
+public:
+ SocketBase(SOCKET hSocket = INVALID_SOCKET) : m_SocketHandle(hSocket), m_bConnected(false), m_pBufEvent(NULL)
+ {}
+ ~SocketBase()
+ {
+ m_SocketHandle = INVALID_SOCKET;
+ m_bConnected = false;
+ m_pBufEvent =NULL;
+ }
+ SOCKET GetSocket() { return m_SocketHandle; }
+ virtual void OnReadEvent() = 0;
+ virtual bool IsConnected() = 0;
+ virtual void Disconnect(bool bAbort = false) = 0;
+
+
+ SOCKET m_SocketHandle; //Socket handler
+ bool m_bConnected; //Is socket connected
+
+ struct event m_ev_read;
+ struct event m_ev_write;
+ struct bufferevent* m_pBufEvent;
+};
+
+class Socket : public SocketBase
+{
+ public:
+ //////////////////////////////////////////////////////////////////////////
+ // Constructor/Destructor
+ Socket(SOCKET hSocket = INVALID_SOCKET,
+ uint32 unInputBufferSize = RECVBUF_SIZE,
+ uint32 unOutputBufferSize = SENDBUF_SIZE);
+ ~Socket();
+ //////////////////////////////////////////////////////////////////////////
+
+ //////////////////////////////////////////////////////////////////////////
+ // Operations
+ bool Connect(const char* szAddress, uint32 unPort);
+ bool Accept(sockaddr_in* address);
+ void Disconnect(bool bAbort = false);
+ bool Send(IN const uint8* pSrc, INOUT uint32 unSize);
+ void Sendf(const char *format, ...);
+ //////////////////////////////////////////////////////////////////////////
+
+ //IOCP "Callback"
+#ifdef USE_IOCP
+ void ReadComplete(uint32 dwIoSize);
+ void SendComplete(uint32 dwIoSize);
+#endif//USE_IOCP
+
+ //////////////////////////////////////////////////////////////////////////
+ // Virtual notification methods for Socket's "child"
+ virtual void OnRead() {}
+ virtual void OnConnect() {}
+ virtual void OnDisconnect() {}
+ //////////////////////////////////////////////////////////////////////////
+
+#ifdef USE_LEVENT
+ void OnReadEvent();
+
+#endif//USE_LEVENT
+
+ //////////////////////////////////////////////////////////////////////////
+ // Socket's buffers
+ DataBuffer* WriteBuffer() {return &m_WriteBuffer;}
+ DataBuffer* ReadBuffer() {return &m_ReadBuffer;}
+ //////////////////////////////////////////////////////////////////////////
+ void SetOptions();
+ //////////////////////////////////////////////////////////////////////////
+ //Win32 specific functional
+ #ifdef WIN32
+ void AssignIOCompletionPort(HANDLE hIOCP)
+ {
+ m_IOCompletitionPort = hIOCP;
+ }
+
+ HANDLE GetIOCompletionPort()
+ {
+ return m_IOCompletitionPort;
+ }
+ private:
+ HANDLE m_IOCompletitionPort;
+ public:
+ #endif //WIN32
+ bool m_bAbleToSend;
+ //////////////////////////////////////////////////////////////////////////
+
+ //////////////////////////////////////////////////////////////////////////
+ //Socket's helpers
+ std::string GetRemoteAddress(); //Retrieves connected client IP address
+ bool IsConnected() // Retrieves connection status
+ {
+ return m_bConnected;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+
+ //////////////////////////////////////////////////////////////////////////
+ // Socket mutex helper
+ void LockWriting() //Locks writing
+ {
+ m_WriteMutex.Lock();
+ }
+ void UnlockWriting() //Unlocks writing
+ {
+ m_WriteMutex.Unlock();
+ }
+
+ void LockReading() //Locks reading
+ {
+ m_ReadMutex.Lock();
+ }
+ void UnlockReading() //Unlocks reading
+ {
+ m_ReadMutex.Unlock();
+ }
+ //////////////////////////////////////////////////////////////////////////
+
+ private:
+ bool SendBuffer();
+
+ //Mutex for send/recv operation
+ Mutex m_WriteMutex;
+ Mutex m_ReadMutex;
+
+ sockaddr_in m_client; //Name of the socket in the sockaddr structure to which the connection should be established.
+
+ //////////////////////////////////////////////////////////////////////////
+ //Socket data buffers
+ DataBuffer m_ReadBuffer; //Input buffer
+ DataBuffer m_WriteBuffer; //Output buffer
+};
+#endif //__SOCKET_BASE_IMPL_H__
Index: src/mangosd/Makefile.am
===================================================================
--- src/mangosd/Makefile.am (revision 23)
+++ src/mangosd/Makefile.am (working copy)
@@ -33,7 +33,7 @@
WorldRunnable.h
## Link world daemon against the shared library
-mangos_worldd_LDADD = ../bindings/universal/libmangosscript.la ../game/libmangosgame.a ../shared/Database/libmangosdatabase.a ../shared/Config/libmangosconfig.a ../shared/Auth/libmangosauth.a ../shared/libmangosshared.a ../shared/vmap/libmangosvmaps.a ../shared/Network/libmangosnetwork.a ../framework/libmangosframework.a ../../dep/src/zthread/libZThread.la ../../dep/src/g3dlite/libg3dlite.a
+mangos_worldd_LDADD = ../bindings/universal/libmangosscript.la ../game/libmangosgame.a ../shared/Database/libmangosdatabase.a ../shared/Config/libmangosconfig.a ../shared/Auth/libmangosauth.a ../shared/libmangosshared.a ../shared/vmap/libmangosvmaps.a ../shared/NetworkNew/libmangosnetwork.a ../framework/libmangosframework.a ../../dep/src/zthread/libZThread.la ../../dep/src/g3dlite/libg3dlite.a
mangos_worldd_LDFLAGS = -L../../dep/src/zthread -L../../dep/src/g3dlite -L../bindings/universal/ $(MYSQL_LIBS) $(LEVENT_LIB) $(POSTGRE_LIBS) -L$(libdir) $(ZLIB) $(COMPATLIB) $(SSLLIB) -export-dynamic
## Additional files to include when running 'make dist'
Index: src/mangosd/Master.cpp
===================================================================
--- src/mangosd/Master.cpp (revision 23)
+++ src/mangosd/Master.cpp (working copy)
@@ -136,7 +136,7 @@
uint32 raport = sConfig.GetIntDefault( "Ra.Port", 3443 );
std::string stringip = sConfig.GetStringDefault( "Ra.IP", "0.0.0.0" );
pRAListenSocket = new ListenSocket<RASocket>(stringip.c_str(), raport);
- if (!pRAListenSocket->IsListernPortOpened())
+ if (!pRAListenSocket->IsListenPortOpened())
sLog.outString("Remote access lister on port %d on %s - FAILED", raport, stringip.c_str());
else
sLog.outString("Starting Remote access lister on port %d on %s", raport, stringip.c_str());
@@ -191,7 +191,7 @@
uint32 wsport = sWorld.getConfig(CONFIG_PORT_WORLD);
ListenSocket<WorldSocket> worldListenSocket("0.0.0.0", wsport);
- if(worldListenSocket.IsListernPortOpened())
+ if(worldListenSocket.IsListenPortOpened())
sSocketManager.StartSocketThreads();
// maximum counter for next ping
@@ -200,7 +200,7 @@
uint32 time_to_sleep = 100;
///- Wait for termination signal
- while (!World::m_stopEvent && worldListenSocket.IsListernPortOpened())
+ while (!World::m_stopEvent && worldListenSocket.IsListenPortOpened())
{
#ifdef WIN32
if (m_ServiceStatus == 0) World::m_stopEvent = true;
Index: src/game/Makefile.am
===================================================================
--- src/game/Makefile.am (revision 23)
+++ src/game/Makefile.am (working copy)
@@ -256,7 +256,7 @@
GroupRefManager.h
## Link against shared library
-libmangosgame_a_LIBADD = ../shared/libmangosshared.a ../shared/Auth/libmangosauth.a ../shared/Config/libmangosconfig.a ../shared/Database/libmangosdatabase.a ../shared/Network/libmangosnetwork.a ../shared/vmap/libmangosvmaps.a
+libmangosgame_a_LIBADD = ../shared/libmangosshared.a ../shared/Auth/libmangosauth.a ../shared/Config/libmangosconfig.a ../shared/Database/libmangosdatabase.a ../shared/NetworkNew/libmangosnetwork.a ../shared/vmap/libmangosvmaps.a
## Additional files to include when running 'make dist'
# Nothing yet.