From 82b5392ff530ce1ab0f4ddd8ab99a65081df1ab6 Mon Sep 17 00:00:00 2001 From: lotodore Date: Sat, 5 May 2007 21:14:23 +0000 Subject: [PATCH] Added new boost timer. Prepared fixes for removing players. --- docs/net_protocol.txt | 5 +- src/core/boost/timer.hpp | 22 +++ src/core/boost/timer/devices.hpp | 31 +++++ .../timer/devices/GetSystemTimeAsFileTime.hpp | 96 +++++++++++++ src/core/boost/timer/devices/GetTickCount.hpp | 92 +++++++++++++ .../timer/devices/QueryPerformanceCounter.hpp | 130 ++++++++++++++++++ src/core/boost/timer/devices/clock.hpp | 85 ++++++++++++ src/core/boost/timer/devices/date_time.hpp | 84 +++++++++++ src/core/boost/timer/devices/gettimeofday.hpp | 98 +++++++++++++ src/core/boost/timer/devices/timeGetTime.hpp | 94 +++++++++++++ src/core/boost/timer/implementation.hpp | 107 ++++++++++++++ src/core/boost/timer/typedefs.hpp | 55 ++++++++ src/net/common/netpacket.cpp | 4 +- src/net/common/serverrecvstate.cpp | 53 ++++--- src/net/common/serverrecvthread.cpp | 54 +++++--- src/net/common/sessiondata.cpp | 6 +- src/net/serverrecvthread.h | 7 +- src/net/sessiondata.h | 20 ++- 18 files changed, 989 insertions(+), 54 deletions(-) create mode 100644 src/core/boost/timer.hpp create mode 100644 src/core/boost/timer/devices.hpp create mode 100644 src/core/boost/timer/devices/GetSystemTimeAsFileTime.hpp create mode 100644 src/core/boost/timer/devices/GetTickCount.hpp create mode 100644 src/core/boost/timer/devices/QueryPerformanceCounter.hpp create mode 100644 src/core/boost/timer/devices/clock.hpp create mode 100644 src/core/boost/timer/devices/date_time.hpp create mode 100644 src/core/boost/timer/devices/gettimeofday.hpp create mode 100644 src/core/boost/timer/devices/timeGetTime.hpp create mode 100644 src/core/boost/timer/implementation.hpp create mode 100644 src/core/boost/timer/typedefs.hpp diff --git a/docs/net_protocol.txt b/docs/net_protocol.txt index 29c0fa29..b9256599 100644 --- a/docs/net_protocol.txt +++ b/docs/net_protocol.txt @@ -62,7 +62,7 @@ Server Reply: Join Game ACK +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Number of Players | Small Blind | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Hands before raise | Reserved | + | Hands before raise | Proposed GUI Speed | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Start Cash | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -71,7 +71,8 @@ Player Number: 0 to (NumberOfPlayers - 1), "position". Player ID: Unique Player ID - +Proposed GUI Speed: + 1-11 Server Notification: Player Joined diff --git a/src/core/boost/timer.hpp b/src/core/boost/timer.hpp new file mode 100644 index 00000000..583d4c47 --- /dev/null +++ b/src/core/boost/timer.hpp @@ -0,0 +1,22 @@ +#ifndef BOOST_TIMER_HPP +#define BOOST_TIMER_HPP + +// (C) Copyright Vaucher Philippe 2006 + +// Use, modification and distribution is subject to the +// Boost Software License, Version 1.0. (See accompanying +// file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0) +// Author: Vaucher Philippe 2006 + +// Speeds up compilation a bit on msvc +#if (defined _MSC_VER) && (_MSC_VER >= 1200) +#pragma once +#endif + +// -------------------------- Includes -------------------------- + +#include "boost/timer/implementation.hpp" +#include "boost/timer/devices.hpp" +#include "boost/timer/typedefs.hpp" + +#endif // BOOST_TIMER_HPP diff --git a/src/core/boost/timer/devices.hpp b/src/core/boost/timer/devices.hpp new file mode 100644 index 00000000..7f1fe14c --- /dev/null +++ b/src/core/boost/timer/devices.hpp @@ -0,0 +1,31 @@ +#ifndef BOOST_TIMER_DEVICES_HPP +#define BOOST_TIMER_DEVICES_HPP + +// (C) Copyright Vaucher Philippe 2006 + +// Use, modification and distribution is subject to the +// Boost Software License, Version 1.0. (See accompanying +// file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0) +// Author: Vaucher Philippe 2006 + + +// -------------------------- Devices -------------------------- + +//! A device has 3 main member functions: start(), elapsed() & reset(). + + +// -------------------------- Includes -------------------------- + +#include "boost/timer/devices/clock.hpp" +#include "boost/timer/devices/date_time.hpp" + +#ifndef BOOST_WINDOWS + #include "boost/timer/devices/gettimeofday.hpp" +#else + #include "boost/timer/devices/QueryPerformanceCounter.hpp" + #include "boost/timer/devices/timeGetTime.hpp" + #include "boost/timer/devices/GetSystemTimeAsFileTime.hpp" + #include "boost/timer/devices/GetTickCount.hpp" +#endif + +#endif // BOOST_TIMER_DEVICES_HPP diff --git a/src/core/boost/timer/devices/GetSystemTimeAsFileTime.hpp b/src/core/boost/timer/devices/GetSystemTimeAsFileTime.hpp new file mode 100644 index 00000000..f995d65f --- /dev/null +++ b/src/core/boost/timer/devices/GetSystemTimeAsFileTime.hpp @@ -0,0 +1,96 @@ +#ifndef BOOST_TIMER_DEVICES_GSTAFT_HPP +#define BOOST_TIMER_DEVICES_GSTAFT_HPP + +// (C) Copyright Vaucher Philippe 2006 + +// Use, modification and distribution is subject to the +// Boost Software License, Version 1.0. (See accompanying +// file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0) +// Author: Vaucher Philippe 2006 + + +// -------------------------- GetSystemTimeAsFileTime() -------------------------- + +// Properties: +// - ??? ns resolution. +// - ??? ns overhead (6 clocks (64-bit load/store + synchronization (4))). +// +// Pros: +// - Low overhead. +// +// Cons: +// - Low resolution. + + +// -------------------------- Includes -------------------------- + +#ifndef BOOST_WINDOWS + #error "GetSystemTimeAsFileTime() can only be used on windows" +#else + +// Boost headers +#include +#include + +// Windows headers +#define WIN32_LEAN_AND_MEAN +#include + + +// -------------------------- Code -------------------------- + +namespace boost +{ + +//! The gstaft_device class is based on GetSystemTimeAsFileTime() to compute the time +class gstaft_device +{ + + public: + + typedef posix_time::ptime time_type; + typedef time_type::time_duration_type time_duration_type; + + explicit gstaft_device() : m_elapsed(0, 0, 0) + { + std::memset(&m_start, 0, sizeof(ULARGE_INTEGER)); + } + + void start() + { + if(!m_start.QuadPart) + GetSystemTimeAsFileTime(reinterpret_cast(&m_start)); + } + + const time_duration_type& elapsed() const + { + if(m_start.QuadPart) + { + ULARGE_INTEGER current; + GetSystemTimeAsFileTime(reinterpret_cast(¤t)); + uint64_t tmp = current.QuadPart - m_start.QuadPart; + m_elapsed += posix_time::milliseconds(tmp / 10000.0); + m_start = current; + } + return m_elapsed; + } + + void reset() + { + m_elapsed = time_duration_type(0,0,0); + std::memset(&m_start, 0, sizeof(ULARGE_INTEGER)); + } + + + private: + + mutable ULARGE_INTEGER m_start; + mutable time_duration_type m_elapsed; + +}; + +} // namespace boost + +#endif // BOOST_WINDOWS + +#endif // BOOST_TIMER_DEVICES_GSTAFT_HPP diff --git a/src/core/boost/timer/devices/GetTickCount.hpp b/src/core/boost/timer/devices/GetTickCount.hpp new file mode 100644 index 00000000..28739fd5 --- /dev/null +++ b/src/core/boost/timer/devices/GetTickCount.hpp @@ -0,0 +1,92 @@ +#ifndef BOOST_TIMER_DEVICES_GTC_HPP +#define BOOST_TIMER_DEVICES_GTC_HPP + +// (C) Copyright Vaucher Philippe 2006 + +// Use, modification and distribution is subject to the +// Boost Software License, Version 1.0. (See accompanying +// file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0) +// Author: Vaucher Philippe 2006 + +// -------------------------- GetTickCount() -------------------------- + +// Properties: +// - 5 to 55 ms resolution. +// - ??? ns overhead (8 clock (load, mul, shift)). +// +// Pros: +// - Very low overhead. +// +// Cons: +// - Very low resolution. + + +// -------------------------- Includes -------------------------- + +#ifndef BOOST_WINDOWS + #error "GetTickCount() can only be used on windows" +#else + +// Boost headers +#include +#include + +// Windows headers +#define WIN32_LEAN_AND_MEAN +#include + + +// -------------------------- Code -------------------------- + +namespace boost +{ + +//! The gtc_device class is based on GetTickCount() to compute the time +class gtc_device +{ + + public: + + typedef posix_time::ptime time_type; + typedef time_type::time_duration_type time_duration_type; + + explicit gtc_device() : m_start(0), m_elapsed(0, 0, 0) + { + } + + void start() + { + if(!m_start) + m_start = GetTickCount(); + } + + const time_duration_type& elapsed() const + { + if(m_start) + { + uint32_t current = GetTickCount(); + m_elapsed += posix_time::milliseconds(current - m_start); + m_start = current; + } + return m_elapsed; + } + + void reset() + { + m_elapsed = time_duration_type(0,0,0); + m_start = 0; + } + + + private: + + mutable uint32_t m_start; + mutable time_duration_type m_elapsed; + +}; + +} // namespace boost + +#endif // BOOST_WINDOWS + +#endif // BOOST_TIMER_DEVICES_GTC_HPP diff --git a/src/core/boost/timer/devices/QueryPerformanceCounter.hpp b/src/core/boost/timer/devices/QueryPerformanceCounter.hpp new file mode 100644 index 00000000..bf95aef3 --- /dev/null +++ b/src/core/boost/timer/devices/QueryPerformanceCounter.hpp @@ -0,0 +1,130 @@ +#ifndef BOOST_TIMER_DEVICES_QPC_HPP +#define BOOST_TIMER_DEVICES_QPC_HPP + +// (C) Copyright Vaucher Philippe 2006 + +// Use, modification and distribution is subject to the +// Boost Software License, Version 1.0. (See accompanying +// file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0) +// Author: Vaucher Philippe 2006 + + +// -------------------------- QueryPerformanceCounter() -------------------------- + +// Properties: +// Win2k (PIT): +// - 838 ns resolution. +// - ~3000 ns overhead. +// WinXP (PMT): +// - 279 ns resolution. +// - 700 ns overhead. +// +// Pros: +// - High resolution (usually the best one). +// +// Cons: +// - High overhead. +// - Not thread safe. +// - Multi core problems. To solve the issue you can #define BOOST_QPC_SET_AFFINITY which will call SetThreadAffinityMask() for you. +// +// Issues: +// 1) Q274323: may jump several seconds under heavy PCI bus load. +// not a problem, because the older systems on which this occurs +// have safe TSCs, so that is used instead. +// 2) "System clock problem can inflate benchmark scores": +// incorrect value if not polled every 4.5 seconds? + + +// -------------------------- Includes -------------------------- + +#ifndef BOOST_WINDOWS + #error "QueryPerformanceCounter() can only be used on windows" +#else + +// Boost headers +#include +#include + +// Windows headers +#define WIN32_LEAN_AND_MEAN +#include + + +// -------------------------- Code -------------------------- + +namespace boost +{ + +class qpc_device +{ + + public: + + typedef posix_time::ptime time_type; + typedef time_type::time_duration_type time_duration_type; + + explicit qpc_device() : m_elapsed(0, 0, 0) + { + #ifdef BOOST_QPC_SET_AFFINITY + m_affinity = SetThreadAffinityMask(GetCurrentThread(), 1); + #endif + + m_start.QuadPart = 0; + if(!QueryPerformanceFrequency(&m_frequency)) + throw_exception(std::runtime_error("qpc_device: QueryPerformanceFrequency() indicated there's no high-resolution performance counter")); + + // Make it so we have the future results directly in milliseconds + m_frequency.QuadPart /= 1000; + } + + ~qpc_device() + { + #ifdef BOOST_QPC_SET_AFFINITY + SetThreadAffinityMask(GetCurrentThread(), m_affinity); + #endif + } + + void start() + { + if(!m_start.QuadPart && !QueryPerformanceCounter(&m_start)) + throw_exception(std::runtime_error("qpc_device: QueryPerformanceCounter() failed")); + } + + const time_duration_type& elapsed() const + { + if(m_start.QuadPart) + { + LARGE_INTEGER current; + if(!QueryPerformanceCounter(¤t)) + throw_exception(std::runtime_error("qpc_device: QueryPerformanceCounter() failed")); + uint64_t milliseconds = (current.QuadPart - m_start.QuadPart) / m_frequency.QuadPart; + m_elapsed += posix_time::milliseconds(milliseconds); + m_start = current; + } + return m_elapsed; + } + + void reset() + { + m_elapsed = time_duration_type(0,0,0); + m_start.QuadPart = 0; + } + + + private: + + LARGE_INTEGER m_frequency; + mutable LARGE_INTEGER m_start; + mutable time_duration_type m_elapsed; + + #ifdef BOOST_QPC_SET_AFFINITY + DWORD_PTR m_affinity; + #endif + +}; + +} // namespace boost + +#endif // BOOST_WINDOWS + +#endif // BOOST_TIMER_DEVICES_QPC_HPP diff --git a/src/core/boost/timer/devices/clock.hpp b/src/core/boost/timer/devices/clock.hpp new file mode 100644 index 00000000..739bcd23 --- /dev/null +++ b/src/core/boost/timer/devices/clock.hpp @@ -0,0 +1,85 @@ +#ifndef BOOST_TIMER_DEVICES_CLOCK_HPP +#define BOOST_TIMER_DEVICES_CLOCK_HPP + +// (C) Copyright Vaucher Philippe 2006 + +// Use, modification and distribution is subject to the +// Boost Software License, Version 1.0. (See accompanying +// file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0) +// Author: Vaucher Philippe 2006 + +// -------------------------- std::clock() -------------------------- + +// Properties: +// - ??? ns resolution. +// - ??? ns overhead. +// - Is implemented with GetSystemTimeAsFileTime on windows. +// +// Pros: +// - Portable. +// +// Cons: +// - High resolution. + + +// -------------------------- Includes -------------------------- + +// Standard headers +#include + +// Boost headers +#include + + +// -------------------------- Code -------------------------- + +namespace boost +{ + +//! The clock_device class is based on std::clock() to compute the time +class clock_device +{ + + public: + + typedef posix_time::ptime time_type; + typedef time_type::time_duration_type time_duration_type; + + explicit clock_device() : m_start(0), m_elapsed(0, 0, 0) + { + } + + void start() + { + if(!m_start) + m_start = std::clock(); + } + + const time_duration_type& elapsed() const + { + if(m_start) + { + std::clock_t current = std::clock(); + m_elapsed += posix_time::milliseconds(static_cast(current-m_start) / CLOCKS_PER_SEC * 1000.0); + m_start = current; + } + return m_elapsed; + } + + void reset() + { + m_elapsed = time_duration_type(0,0,0); + m_start = 0; + } + + + private: + + mutable std::clock_t m_start; + mutable time_duration_type m_elapsed; + +}; + +} // namespace boost + +#endif // BOOST_TIMER_DEVICES_CLOCK_HPP diff --git a/src/core/boost/timer/devices/date_time.hpp b/src/core/boost/timer/devices/date_time.hpp new file mode 100644 index 00000000..c311263b --- /dev/null +++ b/src/core/boost/timer/devices/date_time.hpp @@ -0,0 +1,84 @@ +#ifndef BOOST_TIMER_DEVICES_DATE_TIME_HPP +#define BOOST_TIMER_DEVICES_DATE_TIME_HPP + +// (C) Copyright Vaucher Philippe 2006 + +// Use, modification and distribution is subject to the +// Boost Software License, Version 1.0. (See accompanying +// file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0) +// Author: Vaucher Philippe 2006 + + +// -------------------------- date_time devices -------------------------- + +// Properties: +// - windows: uses GetSystemTimeAsFileTime() +// - POSIX: uses gettimeofday() +// +// Pros: +// - Portable. + + +// -------------------------- Includes -------------------------- + +#include + + +// -------------------------- Code -------------------------- + +namespace boost +{ + +//! The date_time device +template +class date_time_device +{ + + public: + + typedef Clock clock_type; + typedef Time time_type; + typedef typename clock_type::time_duration_type time_duration_type; + + explicit date_time_device() : m_start(date_time::not_a_date_time), m_elapsed(0, 0, 0) + { + } + + void start() + { + if(m_start.is_not_a_date_time()) + m_start = clock_type::local_time(); + } + + const time_duration_type& elapsed() const + { + if(!m_start.is_not_a_date_time()) + { + time_type current(clock_type::local_time()); + m_elapsed += (current - m_start); + m_start = current; + } + return m_elapsed; + } + + void reset() + { + m_start = date_time::not_a_date_time; + m_elapsed = time_duration_type(0,0,0); + } + + + private: + + mutable time_type m_start; + mutable time_duration_type m_elapsed; + +}; + +// Convenience typedefs +typedef date_time_device microsec_device; +typedef date_time_device second_device; + +} // namespace boost + +#endif // BOOST_TIMER_DEVICES_DATE_TIME_HPP diff --git a/src/core/boost/timer/devices/gettimeofday.hpp b/src/core/boost/timer/devices/gettimeofday.hpp new file mode 100644 index 00000000..ae57959e --- /dev/null +++ b/src/core/boost/timer/devices/gettimeofday.hpp @@ -0,0 +1,98 @@ +#ifndef BOOST_TIMER_DEVICES_GTOD_HPP +#define BOOST_TIMER_DEVICES_GTOD_HPP + +// (C) Copyright Vaucher Philippe 2006 + +// Use, modification and distribution is subject to the +// Boost Software License, Version 1.0. (See accompanying +// file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0) +// Author: Vaucher Philippe 2006 + +// -------------------------- gettimeofday() -------------------------- + +// Properties: +// - ??? ns resolution. +// - ??? ns overhead. +// +// Pros: +// - Low overhead. +// - High resolution. + + +// -------------------------- Includes -------------------------- + +// Get config +#include + +// Check we have gettimeofday() +#ifndef BOOST_HAS_GETTIMEOFDAY + #error "gettimeofday() can only be used on POSIX systems" +#else + +// Boost headers +#include + +// Linux headers +#include + +// -------------------------- Code -------------------------- + +namespace boost +{ + +//! The gtod_device class is based on gettimeofday() to compute the time +class gtod_device +{ + + public: + + typedef posix_time::ptime time_type; + typedef time_type::time_duration_type time_duration_type; + + explicit gtod_device() : m_elapsed(0, 0, 0) + { + std::memset(&m_start, 0, sizeof(timeval)); + } + + void start() + { + if(!is_time(m_start)) + gettimeofday(&m_start, 0); + } + + const time_duration_type& elapsed() const + { + if(is_time(m_start)) + { + timeval current; + gettimeofday(¤t, 0); + m_elapsed += posix_time::milliseconds((current.tv_sec-m_start.tv_sec) * 1000 + ((current.tv_usec-m_start.tv_usec) / 1000.0)); + m_start = current; + } + return m_elapsed; + } + + void reset() + { + m_elapsed = time_duration_type(0,0,0); + std::memset(&m_start, 0, sizeof(timeval)); + } + + + private: + + bool is_time(const timeval& value) const + { + return value.tv_sec || value.tv_usec; + } + + mutable timeval m_start; + mutable time_duration_type m_elapsed; + +}; + +} // namespace boost + +#endif // BOOST_HAS_GETTIMEOFDAY + +#endif // BOOST_TIMER_DEVICES_GTOD_HPP diff --git a/src/core/boost/timer/devices/timeGetTime.hpp b/src/core/boost/timer/devices/timeGetTime.hpp new file mode 100644 index 00000000..a7c9f517 --- /dev/null +++ b/src/core/boost/timer/devices/timeGetTime.hpp @@ -0,0 +1,94 @@ +#ifndef BOOST_TIMER_DEVICES_TGT_HPP +#define BOOST_TIMER_DEVICES_TGT_HPP + +// (C) Copyright Vaucher Philippe 2006 + +// Use, modification and distribution is subject to the +// Boost Software License, Version 1.0. (See accompanying +// file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0) +// Author: Vaucher Philippe 2006 + +// -------------------------- std::clock() -------------------------- + +// Properties: +// - 1 ms resolution. +// - ??? ns overhead. +// +// Pros: +// - Low overhead. +// +// Cons: +// - Low resolution. + +// -------------------------- Includes -------------------------- + +#ifndef BOOST_WINDOWS + #error "timeGetTime() can only be used on windows" +#else + +// Boost headers +#include +#include + +// Windows headers +#define WIN32_LEAN_AND_MEAN +#include + +// Automagically link winmm.lib if we can +#pragma comment(lib, "winmm.lib") + + +// -------------------------- Code -------------------------- + +namespace boost +{ + +//! The tgt_device class is based on timeGetTime() to compute the time +class tgt_device +{ + + public: + + typedef posix_time::ptime time_type; + typedef time_type::time_duration_type time_duration_type; + + explicit tgt_device() : m_start(0), m_elapsed(0, 0, 0) + { + } + + void start() + { + if(!m_start) + m_start = timeGetTime(); + } + + const time_duration_type& elapsed() const + { + if(m_start) + { + uint32_t current = timeGetTime(); + m_elapsed += posix_time::milliseconds(current - m_start); + m_start = current; + } + return m_elapsed; + } + + void reset() + { + m_elapsed = time_duration_type(0,0,0); + m_start = 0; + } + + + private: + + mutable uint32_t m_start; + mutable time_duration_type m_elapsed; + +}; + +} // namespace boost + +#endif // BOOST_WINDOWS + +#endif // BOOST_TIMER_DEVICES_TGT_HPP diff --git a/src/core/boost/timer/implementation.hpp b/src/core/boost/timer/implementation.hpp new file mode 100644 index 00000000..b1404776 --- /dev/null +++ b/src/core/boost/timer/implementation.hpp @@ -0,0 +1,107 @@ +#ifndef BOOST_TIMER_IMPLEMENTATION_HPP +#define BOOST_TIMER_IMPLEMENTATION_HPP + +// (C) Copyright Vaucher Philippe 2006 + +// Use, modification and distribution is subject to the +// Boost Software License, Version 1.0. (See accompanying +// file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0) +// Author: Vaucher Philippe 2006 + + +// -------------------------- Code -------------------------- + +namespace boost +{ + + //! The timer class takes a device type that's used for the elapsed time computation. + //! Calling start(), pause() or resume() twice has no special effects. + template + class timer + { + + public: + + typedef Device device_type; + typedef typename device_type::time_duration_type time_duration_type; + + enum start_options { auto_start = 1, manual_start }; + + //! By default, start the timer without any time offset + explicit timer(time_duration_type initial_duration = time_duration_type(0, 0, 0), start_options start_op = auto_start) + : m_elapsed(initial_duration), m_running(false) + { + if(start_op == auto_start) + start(); + } + + //! Starts the timer + void start() + { + if(!m_running) + { + m_device.start(); + m_running = true; + } + } + + //! Restarts the timer + void restart() + { + reset(); + start(); + } + + //! Returns the elapsed time + time_duration_type elapsed() const + { + return m_running ? (m_device.elapsed() + m_elapsed) : m_elapsed; + } + + //! Pauses the timer + void pause() + { + if(m_running) + { + m_elapsed += m_device.elapsed(); + m_device.reset(); + m_running = false; + } + } + + //! Resumes the timer + void resume() + { + if(!m_running) + { + m_device.start(); + m_running = true; + } + } + + //! Resets the timer + void reset() + { + m_elapsed = time_duration_type(0,0,0); + m_device.reset(); + m_running = false; + } + + //! Tells wether the timer is currently running or not + bool is_running() const + { + return m_running; + } + + + private: + + mutable device_type m_device; + mutable time_duration_type m_elapsed; + bool m_running; + + }; + +} // namespace boost + +#endif // BOOST_TIMER_IMPLEMENTATION_HPP diff --git a/src/core/boost/timer/typedefs.hpp b/src/core/boost/timer/typedefs.hpp new file mode 100644 index 00000000..391f8faf --- /dev/null +++ b/src/core/boost/timer/typedefs.hpp @@ -0,0 +1,55 @@ +#ifndef BOOST_TIMER_TYPEDEFS_HPP +#define BOOST_TIMER_TYPEDEFS_HPP + +// (C) Copyright Vaucher Philippe 2006 + +// Use, modification and distribution is subject to the +// Boost Software License, Version 1.0. (See accompanying +// file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0) +// Author: Vaucher Philippe 2006 + + +// -------------------------- Includes -------------------------- + +#include + +#include "boost/timer/implementation.hpp" +#include "boost/timer/devices.hpp" + + +// -------------------------- Devices -------------------------- + +namespace boost +{ + +// boost::date_time devices +typedef timer microsec_timer; +typedef timer second_timer; + +// std::clock() device +typedef timer clock_timer; + +#ifndef BOOST_WINDOWS + + // gettimeofday() device + typedef timer gtod_timer; + +#else + + // QueryPerformanceCounter() device + typedef timer qpc_timer; + + // timeGetTime() device + typedef timer tgt_timer; + + // GetSystemTimeAsFileTime() device + typedef timer gstaft_timer; + + // GetTickCount() device + typedef timer gtc_timer; + +#endif + +} // namespace boost + +#endif // BOOST_TIMER_TYPEDEFS_HPP diff --git a/src/net/common/netpacket.cpp b/src/net/common/netpacket.cpp index 94eaccc1..ed57efaa 100644 --- a/src/net/common/netpacket.cpp +++ b/src/net/common/netpacket.cpp @@ -80,7 +80,7 @@ struct NetPacketJoinGameAckData u_int16_t numberOfPlayers; u_int16_t smallBlind; u_int16_t handsBeforeRaise; - u_int16_t reserved; + u_int16_t proposedGuiSpeed; u_int32_t startCash; }; @@ -443,6 +443,7 @@ NetPacketJoinGameAck::SetData(const NetPacketJoinGameAck::Data &inData) tmpData->numberOfPlayers = htons(inData.gameData.numberOfPlayers); tmpData->smallBlind = htons(inData.gameData.smallBlind); tmpData->handsBeforeRaise = htons(inData.gameData.handsBeforeRaise); + tmpData->proposedGuiSpeed = htons(inData.gameData.guiSpeed); tmpData->startCash = htonl(inData.gameData.startCash); } @@ -458,6 +459,7 @@ NetPacketJoinGameAck::GetData(NetPacketJoinGameAck::Data &outData) const outData.gameData.numberOfPlayers = ntohs(tmpData->numberOfPlayers); outData.gameData.smallBlind = ntohs(tmpData->smallBlind); outData.gameData.handsBeforeRaise = ntohs(tmpData->handsBeforeRaise); + outData.gameData.guiSpeed = ntohs(tmpData->proposedGuiSpeed); outData.gameData.startCash = ntohl(tmpData->startCash); } diff --git a/src/net/common/serverrecvstate.cpp b/src/net/common/serverrecvstate.cpp index 02f96b5f..618929b8 100644 --- a/src/net/common/serverrecvstate.cpp +++ b/src/net/common/serverrecvstate.cpp @@ -23,9 +23,12 @@ #include #include #include +#include #include #include +#include + using namespace std; #define SERVER_WAIT_TIMEOUT_MSEC 50 @@ -47,6 +50,9 @@ ServerRecvStateInit::Instance() ServerRecvStateInit::ServerRecvStateInit() : m_curUniquePlayerId(0) { + boost::microsec_timer::time_duration_type dur; + boost::microsec_timer t(dur); + t.start(); } ServerRecvStateInit::~ServerRecvStateInit() @@ -62,8 +68,8 @@ ServerRecvStateInit::HandleNewConnection(ServerRecvThread &server, boost::shared RandomBytes((unsigned char *)&sessionId, sizeof(sessionId)); // TODO: check for collisions. // Create a new session. - boost::shared_ptr sessionData(new SessionData(sessionId)); - server.AddSession(connData, sessionData); + boost::shared_ptr sessionData(new SessionData(connData->ReleaseSocket(), sessionId)); + server.AddSession(sessionData); } int @@ -74,8 +80,19 @@ ServerRecvStateInit::Process(ServerRecvThread &server) if (recvSock != INVALID_SOCKET) { - boost::shared_ptr packet = server.GetReceiver().Recv(recvSock); boost::shared_ptr session = server.GetSession(recvSock); + boost::shared_ptr packet; + try + { + packet = server.GetReceiver().Recv(recvSock); + } catch (const NetException &e) + { + if (session.get()) + { + //server.CloseSessionDelayed(session); + return retVal; + } + } // Ignore if no session / no packet. if (packet.get() && session.get()) @@ -83,7 +100,7 @@ ServerRecvStateInit::Process(ServerRecvThread &server) // Session should be in initial state. if (session->GetState() != SessionData::Init) { - server.SendError(ERR_SOCK_INVALID_STATE, recvSock); + //server.SessionError(session, ERR_SOCK_INVALID_STATE); return retVal; } @@ -91,7 +108,7 @@ ServerRecvStateInit::Process(ServerRecvThread &server) const NetPacketJoinGame *tmpPacket = packet->ToNetPacketJoinGame(); if (!tmpPacket) { - server.SendError(ERR_SOCK_INVALID_PACKET, recvSock); + //server.SessionError(session, ERR_SOCK_INVALID_PACKET); return retVal; } @@ -101,38 +118,30 @@ ServerRecvStateInit::Process(ServerRecvThread &server) // Check the protocol version. if (joinGameData.versionMajor != NET_VERSION_MAJOR) { - server.SendError(ERR_NET_VERSION_NOT_SUPPORTED, recvSock); + //server.SessionError(session, ERR_NET_VERSION_NOT_SUPPORTED); return retVal; } // Check the server password. if (!server.CheckPassword(joinGameData.password)) { - server.SendError(ERR_NET_INVALID_PASSWORD, recvSock); + //server.SessionError(session, ERR_NET_INVALID_PASSWORD); return retVal; } - PlayerDataList &playerDataList = server.GetPlayerDataList(); + size_t curNumPlayers = server.GetCurNumberOfPlayers(); // Check the number of players. - if (playerDataList.size() >= (size_t)server.GetGameData().numberOfPlayers) + if (curNumPlayers >= (size_t)server.GetGameData().numberOfPlayers) { - server.SendError(ERR_NET_SERVER_FULL, recvSock); + //server.SessionError(session, ERR_NET_SERVER_FULL); return retVal; } // Check whether this player is already connected. - PlayerDataList::const_iterator player_i = playerDataList.begin(); - PlayerDataList::const_iterator player_end = playerDataList.end(); - while (player_i != player_end) + if (server.IsPlayerConnected(joinGameData.playerName)) { - if ((*player_i)->GetName() == joinGameData.playerName) - break; - ++player_i; - } - if (player_i != player_end) - { - server.SendError(ERR_NET_PLAYER_NAME_IN_USE, recvSock); + //server.SessionError(session, ERR_NET_PLAYER_NAME_IN_USE); return retVal; } @@ -148,7 +157,7 @@ ServerRecvStateInit::Process(ServerRecvThread &server) boost::shared_ptr answer(new NetPacketJoinGameAck); NetPacketJoinGameAck::Data joinGameAckData; joinGameAckData.playerId = tmpPlayerData->GetUniqueId(); - joinGameAckData.playerNumber = playerDataList.size(); + joinGameAckData.playerNumber = 0;//playerDataList.size(); joinGameAckData.sessionId = session->GetId(); // TODO: currently unused. joinGameAckData.gameData = server.GetGameData(); static_cast(answer.get())->SetData(joinGameAckData); @@ -156,7 +165,7 @@ ServerRecvStateInit::Process(ServerRecvThread &server) session->SetState(SessionData::Established); // Store player data in list. - playerDataList.push_back(tmpPlayerData); + //playerDataList.push_back(tmpPlayerData); } } return retVal; diff --git a/src/net/common/serverrecvthread.cpp b/src/net/common/serverrecvthread.cpp index 0294db8a..c3820efe 100644 --- a/src/net/common/serverrecvthread.cpp +++ b/src/net/common/serverrecvthread.cpp @@ -36,7 +36,9 @@ public: virtual void SignalNetError(SOCKET sock, int errorID, int osErrorID) { - // TODO + // We just ignore send errors for now, on server side. + // A send error should trigger a read error or a read + // returning 0 afterwards, and we will handle this error. } private: @@ -247,17 +249,7 @@ ServerRecvThread::CleanupSessionMap() { boost::mutex::scoped_lock lock(m_sessionMapMutex); - // We need to manually close all sockets for the sessions. - // This is "not great", but there are some issues when - // automatically closing them. - SocketSessionMap::iterator i = m_sessionMap.begin(); - SocketSessionMap::iterator end = m_sessionMap.end(); - - while (i != end) - { - CLOSESOCKET(i->first); - ++i; - } + // Sockets will be closed automatically. m_sessionMap.clear(); } @@ -289,19 +281,19 @@ ServerRecvThread::GetSession(SOCKET sock) } void -ServerRecvThread::AddSession(boost::shared_ptr connData, boost::shared_ptr sessionData) +ServerRecvThread::AddSession(boost::shared_ptr sessionData) { boost::mutex::scoped_lock lock(m_sessionMapMutex); - SocketSessionMap::iterator pos = m_sessionMap.lower_bound(connData->GetSocket()); + SocketSessionMap::iterator pos = m_sessionMap.lower_bound(sessionData->GetSocket()); // If pos points to a pair whose key is equivalent to the socket, this handle // already exists within the list. - if (pos != m_sessionMap.end() && connData->GetSocket() == pos->first) + if (pos != m_sessionMap.end() && sessionData->GetSocket() == pos->first) { throw ServerException(ERR_SOCK_CONN_EXISTS, 0); } - m_sessionMap.insert(pos, SocketSessionMap::value_type(connData->ReleaseSocket(), sessionData)); + m_sessionMap.insert(pos, SocketSessionMap::value_type(sessionData->GetSocket(), sessionData)); } SenderThread & @@ -331,10 +323,34 @@ ServerRecvThread::CheckPassword(const std::string &password) const return (password == m_password); } -PlayerDataList & -ServerRecvThread::GetPlayerDataList() +size_t +ServerRecvThread::GetCurNumberOfPlayers() const { - return m_playerDataList; + boost::mutex::scoped_lock lock(m_sessionMapMutex); + return m_sessionMap.size(); +} + +bool +ServerRecvThread::IsPlayerConnected(const std::string &playerName) const +{ + bool retVal = false; + boost::mutex::scoped_lock lock(m_sessionMapMutex); + + SocketSessionMap::const_iterator session_i = m_sessionMap.begin(); + SocketSessionMap::const_iterator session_end = m_sessionMap.end(); + + while (session_i != session_end) + { + const boost::shared_ptr tmpPlayerData = session_i->second->GetPlayerData(); + if (tmpPlayerData.get() && tmpPlayerData->GetName() == playerName) + { + retVal = true; + break; + } + + ++session_i; + } + return retVal; } ServerSenderCallback & diff --git a/src/net/common/sessiondata.cpp b/src/net/common/sessiondata.cpp index 459b3abd..030175ed 100644 --- a/src/net/common/sessiondata.cpp +++ b/src/net/common/sessiondata.cpp @@ -19,12 +19,14 @@ #include -SessionData::SessionData(unsigned id) -: m_id(id), m_state(SessionData::Init) +SessionData::SessionData(SOCKET sockfd, unsigned id) +: m_sockfd(sockfd), m_id(id), m_state(SessionData::Init) { } SessionData::~SessionData() { + if (m_sockfd != INVALID_SOCKET) + CLOSESOCKET(m_sockfd); } diff --git a/src/net/serverrecvthread.h b/src/net/serverrecvthread.h index c777533a..acd83c82 100644 --- a/src/net/serverrecvthread.h +++ b/src/net/serverrecvthread.h @@ -30,7 +30,6 @@ #include #include #include -#include #define RECEIVER_THREAD_TERMINATE_TIMEOUT 200 @@ -79,7 +78,7 @@ protected: void SetState(ServerRecvState &newState); boost::shared_ptr GetSession(SOCKET sock); - void AddSession(boost::shared_ptr connData, boost::shared_ptr sessionData); + void AddSession(boost::shared_ptr sessionData); SenderThread &GetSender(); ReceiverHelper &GetReceiver(); @@ -87,7 +86,8 @@ protected: const GameData &GetGameData() const; bool CheckPassword(const std::string &password) const; - PlayerDataList &GetPlayerDataList(); + size_t GetCurNumberOfPlayers() const; + bool IsPlayerConnected(const std::string &playerName) const; ServerSenderCallback &GetSenderCallback(); @@ -109,7 +109,6 @@ private: std::auto_ptr m_senderCallback; std::auto_ptr m_gameData; - PlayerDataList m_playerDataList; std::string m_password; ServerCallback &m_callback; diff --git a/src/net/sessiondata.h b/src/net/sessiondata.h index f7c157e4..ef47e59c 100644 --- a/src/net/sessiondata.h +++ b/src/net/sessiondata.h @@ -21,6 +21,8 @@ #ifndef _SESSIONDATA_H_ #define _SESSIONDATA_H_ +#include +#include #include #define SESSION_ID_INIT 0 @@ -30,7 +32,7 @@ class SessionData public: enum State { Init, Established }; - SessionData(unsigned id); + SessionData(SOCKET sockfd, unsigned id); ~SessionData(); unsigned GetId() const @@ -40,15 +42,25 @@ public: void SetState(State state) {m_state = state;} + const boost::shared_ptr GetPlayerData() const + {return m_playerData;} + void SetPlayerData(boost::shared_ptr playerData) + {m_playerData = playerData;} + + SOCKET GetSocket() const + {return m_sockfd;} + const std::string &GetClientAddr() const {return m_clientAddr;} void SetClientAddr(const std::string &addr) {m_clientAddr = addr;} private: - unsigned m_id; - State m_state; - std::string m_clientAddr; + SOCKET m_sockfd; + unsigned m_id; + State m_state; + std::string m_clientAddr; + boost::shared_ptr m_playerData; }; #endif