diff options
Diffstat (limited to 'src/mmo')
-rw-r--r-- | src/mmo/core.cpp | 4 | ||||
-rw-r--r-- | src/mmo/dumb_ptr.cpp | 21 | ||||
-rw-r--r-- | src/mmo/dumb_ptr.hpp | 271 | ||||
-rw-r--r-- | src/mmo/fwd.hpp | 5 | ||||
-rw-r--r-- | src/mmo/ip.cpp | 116 | ||||
-rw-r--r-- | src/mmo/ip.hpp | 165 | ||||
-rw-r--r-- | src/mmo/ip.py | 14 | ||||
-rw-r--r-- | src/mmo/ip_test.cpp | 355 | ||||
-rw-r--r-- | src/mmo/md5more.cpp | 3 | ||||
-rw-r--r-- | src/mmo/md5more.hpp | 2 | ||||
-rw-r--r-- | src/mmo/mmo.hpp | 3 | ||||
-rw-r--r-- | src/mmo/socket.cpp | 509 | ||||
-rw-r--r-- | src/mmo/socket.hpp | 424 | ||||
-rw-r--r-- | src/mmo/timer.cpp | 217 | ||||
-rw-r--r-- | src/mmo/timer.hpp | 50 | ||||
-rw-r--r-- | src/mmo/timer.t.hpp | 88 |
16 files changed, 8 insertions, 2239 deletions
diff --git a/src/mmo/core.cpp b/src/mmo/core.cpp index 68b5863..21aa5f7 100644 --- a/src/mmo/core.cpp +++ b/src/mmo/core.cpp @@ -32,8 +32,8 @@ #include "../io/cxxstdio.hpp" -#include "socket.hpp" -#include "timer.hpp" +#include "../net/socket.hpp" +#include "../net/timer.hpp" #include "../poison.hpp" diff --git a/src/mmo/dumb_ptr.cpp b/src/mmo/dumb_ptr.cpp deleted file mode 100644 index 77e3080..0000000 --- a/src/mmo/dumb_ptr.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "dumb_ptr.hpp" -// dumb_ptr.cpp - dummy file to make Make dependencies work -// -// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> -// -// This file is part of The Mana World (Athena server) -// -// 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 3 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, see <http://www.gnu.org/licenses/>. - -#include "../poison.hpp" diff --git a/src/mmo/dumb_ptr.hpp b/src/mmo/dumb_ptr.hpp deleted file mode 100644 index 3472d8b..0000000 --- a/src/mmo/dumb_ptr.hpp +++ /dev/null @@ -1,271 +0,0 @@ -#ifndef TMWA_MMO_DUMB_PTR_HPP -#define TMWA_MMO_DUMB_PTR_HPP -// dumb_ptr.hpp - temporary new/delete wrappers -// -// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> -// -// This file is part of The Mana World (Athena server) -// -// 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 3 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, see <http://www.gnu.org/licenses/>. - -# include "fwd.hpp" - -# include <cstring> - -# include <algorithm> -# include <utility> - -# include "../strings/astring.hpp" -# include "../strings/zstring.hpp" -# include "../strings/xstring.hpp" - -// unmanaged new/delete-able pointer -// should be replaced by std::unique_ptr<T> -template<class T> -class dumb_ptr -{ - template<class U> - friend class dumb_ptr; - T *impl; -public: - explicit - dumb_ptr(T *p=nullptr) - : impl(p) - {} - template<class U> - dumb_ptr(dumb_ptr<U> p) - : impl(p.impl) - {} - dumb_ptr(std::nullptr_t) - : impl(nullptr) - {} - - void delete_() - { - delete impl; - *this = nullptr; - } - template<class... A> - void new_(A&&... a) - { - impl = new T(std::forward<A>(a)...); - } - template<class... A> - static - dumb_ptr<T> make(A&&... a) - { - return dumb_ptr<T>(new T(std::forward<A>(a)...)); - } - dumb_ptr& operator = (std::nullptr_t) - { - impl = nullptr; - return *this; - } - - T& operator *() const - { - return *impl; - } - T *operator->() const - { - return impl; - } - - explicit - operator bool() const - { - return impl; - } - bool operator !() const - { - return !impl; - } - - friend bool operator == (dumb_ptr l, dumb_ptr r) - { - return l.impl == r.impl; - } - friend bool operator != (dumb_ptr l, dumb_ptr r) - { - return !(l == r); - } -}; - -// unmanaged new/delete-able pointer -// should be replaced by std::unique_ptr<T[]> or std::vector<T> -template<class T> -class dumb_ptr<T[]> -{ - T *impl; - size_t sz; -public: - dumb_ptr() : impl(), sz() {} - dumb_ptr(std::nullptr_t) - : impl(nullptr), sz(0) {} - dumb_ptr(T *p, size_t z) - : impl(p) - , sz(z) - {} - - void delete_() - { - delete[] impl; - *this = nullptr; - } - void new_(size_t z) - { - impl = new T[z](); - sz = z; - } - static - dumb_ptr<T[]> make(size_t z) - { - return dumb_ptr<T[]>(new T[z](), z); - } - dumb_ptr& operator = (std::nullptr_t) - { - impl = nullptr; - sz = 0; - return *this; - } - - size_t size() const - { - return sz; - } - void resize(size_t z) - { - if (z == sz) - return; - T *np = new T[z](); - // not exception-safe, but we don't have a dtor anyway - size_t i = std::min(z, sz); - while (i-->0) - np[i] = std::move(impl[i]); - delete[] impl; - impl = np; - sz = z; - } - - T& operator[](size_t i) const - { - return impl[i]; - } - - explicit - operator bool() const - { - return impl; - } - bool operator !() const - { - return !impl; - } - - friend bool operator == (dumb_ptr l, dumb_ptr r) - { - return l.impl == r.impl; - } - friend bool operator != (dumb_ptr l, dumb_ptr r) - { - return !(l == r); - } -}; - -struct dumb_string -{ - dumb_ptr<char[]> impl; - - dumb_string() - : impl() - {} - dumb_string(char *) = delete; - // copy ctor, copy assign, and dtor are all default - - static dumb_string copy(const char *b, const char *e) - { - dumb_string rv; - rv.impl.new_((e - b) + 1); - std::copy(b, e, &rv.impl[0]); - return rv; - } - static dumb_string copys(XString s) - { - return dumb_string::copy(&*s.begin(), &*s.end()); - } - static -# ifndef __clang__ - __attribute__((warning("shouldn't use this - slice instead"))) -# endif - dumb_string copyn(const char *sn, size_t n) - { - return dumb_string::copy(sn, sn + strnlen(sn, n)); - } - - static - dumb_string fake(ZString p) - { - dumb_string rv; - size_t len = p.size(); - rv.impl = dumb_ptr<char[]>(const_cast<char *>(p.c_str()), len); - return rv; - } - - dumb_string dup() const - { - return dumb_string::copy(&impl[0], &impl[0] + impl.size()); - } - void delete_() - { - impl.delete_(); - } - - const char *c_str() const - { - return &impl[0]; - } - - operator ZString() const - { - return ZString(strings::really_construct_from_a_pointer, c_str(), nullptr); - } - - AString str() const - { - return ZString(*this); - } - - char& operator[](size_t i) const - { - return impl[i]; - } - - explicit - operator bool() const - { - return bool(impl); - } - bool operator !() const - { - return !impl; - } -}; - -inline -const char *convert_for_printf(dumb_string ds) -{ - return ds.c_str(); -} - -#endif // TMWA_MMO_DUMB_PTR_HPP diff --git a/src/mmo/fwd.hpp b/src/mmo/fwd.hpp index 65e8dfe..eb8bc05 100644 --- a/src/mmo/fwd.hpp +++ b/src/mmo/fwd.hpp @@ -26,10 +26,7 @@ class MapName; class CharName; class CharPair; -class Session; - class HumanTimeDiff; -class IP4Address; class AccountId; class CharId; @@ -48,6 +45,4 @@ class VarName; class MapName; class CharName; -class TimerData; - #endif // TMWA_MMO_FWD_HPP diff --git a/src/mmo/ip.cpp b/src/mmo/ip.cpp deleted file mode 100644 index 7c243ea..0000000 --- a/src/mmo/ip.cpp +++ /dev/null @@ -1,116 +0,0 @@ -#include "ip.hpp" -// ip.cpp - Implementation of IP address functions. -// -// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> -// -// This file is part of The Mana World (Athena server) -// -// 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 3 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, see <http://www.gnu.org/licenses/>. - -#include "../strings/xstring.hpp" -#include "../strings/vstring.hpp" - -#include "../io/cxxstdio.hpp" - -#include "extract.hpp" - -#include "../poison.hpp" - -bool extract(XString str, IP4Address *rv) -{ - if (str.endswith('.')) - return false; - uint8_t buf[4]; - if (extract(str, record<'.'>(&buf[0], &buf[1], &buf[2], &buf[3]))) - { - *rv = IP4Address(buf); - return true; - } - return false; -} - -bool extract(XString str, IP4Mask *rv) -{ - IP4Address a, m; - unsigned b; - XString l, r; - if (str.endswith('/')) - return false; - if (extract(str, record<'/'>(&l, &r))) - { - // a.b.c.d/e.f.g.h or a.b.c.d/n - if (!extract(l, &a)) - return false; - if (extract(r, &m)) - { - *rv = IP4Mask(a, m); - return true; - } - if (!extract(r, &b) || b > 32) - return false; - } - else - { - // a.b.c.d or a.b.c.d. or a.b.c. or a.b. or a. - if (extract(str, &a)) - { - *rv = IP4Mask(a, IP4_BROADCAST); - return true; - } - if (!str.endswith('.')) - return false; - uint8_t d[4] {}; - if (extract(str, record<'.'>(&d[0], &d[1], &d[2], &d[3]))) - b = 32; - else if (extract(str, record<'.'>(&d[0], &d[1], &d[2]))) - b = 24; - else if (extract(str, record<'.'>(&d[0], &d[1]))) - b = 16; - else if (extract(str, record<'.'>(&d[0]))) - b = 8; - else - return false; - a = IP4Address(d); - } - // a is set; need to construct m from b - if (b == 0) - m = IP4Address(); - else if (b == 32) - m = IP4_BROADCAST; - else - { - uint32_t s = -1; - s <<= (32 - b); - m = IP4Address({ - static_cast<uint8_t>(s >> 24), - static_cast<uint8_t>(s >> 16), - static_cast<uint8_t>(s >> 8), - static_cast<uint8_t>(s >> 0), - }); - } - *rv = IP4Mask(a, m); - return true; -} - -VString<15> convert_for_printf(IP4Address a_) -{ - const uint8_t *a = a_.bytes(); - return STRNPRINTF(16, "%hhu.%hhu.%hhu.%hhu"_fmt, a[0], a[1], a[2], a[3]); -} - -VString<31> convert_for_printf(IP4Mask a) -{ - return STRNPRINTF(32, "%s/%s"_fmt, - a.addr(), a.mask()); -} diff --git a/src/mmo/ip.hpp b/src/mmo/ip.hpp deleted file mode 100644 index 88ad965..0000000 --- a/src/mmo/ip.hpp +++ /dev/null @@ -1,165 +0,0 @@ -#ifndef TMWA_MMO_IP_HPP -#define TMWA_MMO_IP_HPP -// ip.hpp - classes to deal with IP addresses. -// -// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> -// -// This file is part of The Mana World (Athena server) -// -// 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 3 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, see <http://www.gnu.org/licenses/>. - -# include "fwd.hpp" - -# include <netinet/in.h> - -# include <cstddef> -# include <cstdint> - -# include "../strings/fwd.hpp" - -// TODO - in the long run ports belong here also -// and of course, IPv6 stuff. -// But what about unix socket addresses? - -/// Helper function -template<class T, size_t n> -constexpr -bool _ce_a_lt(T (&a)[n], T (&b)[n], size_t i=0) -{ - return (i != n - && (a[i] < b[i] - || (a[i] == b[i] - && _ce_a_lt(a, b, i + 1)))); -} - -/// A 32-bit Ipv4 address. Does not include a port. -/// Guaranteed to be laid out like the network wants. -class IP4Address -{ - uint8_t _addr[4]; -public: - constexpr - IP4Address() - : _addr{} - {} - constexpr explicit - IP4Address(const uint8_t (&a)[4]) - : _addr{a[0], a[1], a[2], a[3]} - {} - explicit - IP4Address(struct in_addr addr) - { - static_assert(sizeof(addr) == sizeof(_addr), "4 bytes"); - *this = IP4Address(reinterpret_cast<const uint8_t (&)[4]>(addr)); - } - explicit - operator struct in_addr() const - { - return reinterpret_cast<const struct in_addr&>(_addr); - } - - constexpr friend - IP4Address operator & (IP4Address l, IP4Address r) - { - return IP4Address({ - static_cast<uint8_t>(l._addr[0] & r._addr[0]), - static_cast<uint8_t>(l._addr[1] & r._addr[1]), - static_cast<uint8_t>(l._addr[2] & r._addr[2]), - static_cast<uint8_t>(l._addr[3] & r._addr[3]), - }); - } - - IP4Address& operator &= (IP4Address m) - { return *this = *this & m; } - - const uint8_t *bytes() const - { return _addr; } - - constexpr friend - bool operator < (IP4Address l, IP4Address r) - { - return _ce_a_lt(l._addr, r._addr); - } - - constexpr friend - bool operator > (IP4Address l, IP4Address r) - { - return _ce_a_lt(r._addr, l._addr); - } - - constexpr friend - bool operator >= (IP4Address l, IP4Address r) - { - return !_ce_a_lt(l._addr, r._addr); - } - - constexpr friend - bool operator <= (IP4Address l, IP4Address r) - { - return !_ce_a_lt(r._addr, l._addr); - } - - constexpr friend - bool operator == (IP4Address l, IP4Address r) - { - return !(l < r || r < l); - } - - constexpr friend - bool operator != (IP4Address l, IP4Address r) - { - return (l < r || r < l); - } -}; - -class IP4Mask -{ - IP4Address _addr, _mask; -public: - constexpr - IP4Mask() : _addr(), _mask() - {} - constexpr - IP4Mask(IP4Address a, IP4Address m) : _addr(a & m), _mask(m) - {} - - constexpr - IP4Address addr() const - { return _addr; } - constexpr - IP4Address mask() const - { return _mask; } - - constexpr - bool covers(IP4Address a) const - { - return (a & _mask) == _addr; - } -}; - - -constexpr -IP4Address IP4_LOCALHOST({127, 0, 0, 1}); -constexpr -IP4Address IP4_BROADCAST({255, 255, 255, 255}); - - -VString<15> convert_for_printf(IP4Address a); -VString<31> convert_for_printf(IP4Mask m); - -bool extract(XString str, IP4Address *iv); - -bool extract(XString str, IP4Mask *iv); - -#endif // TMWA_MMO_IP_HPP diff --git a/src/mmo/ip.py b/src/mmo/ip.py deleted file mode 100644 index e6a8183..0000000 --- a/src/mmo/ip.py +++ /dev/null @@ -1,14 +0,0 @@ -class IP4Address(object): - ''' print an IP4Address - ''' - __slots__ = ('_value') - name = 'IP4Address' - enabled = True - - def __init__(self, value): - self._value = value - - def to_string(self): - addr = self._value['_addr'] - addr = tuple(int(addr[i]) for i in range(4)) - return '%d.%d.%d.%d' % addr diff --git a/src/mmo/ip_test.cpp b/src/mmo/ip_test.cpp deleted file mode 100644 index 3c4d2ef..0000000 --- a/src/mmo/ip_test.cpp +++ /dev/null @@ -1,355 +0,0 @@ -#include "ip.hpp" -// ip_test.cpp - Testsuite for implementation of IP address functions. -// -// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> -// -// This file is part of The Mana World (Athena server) -// -// 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 3 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, see <http://www.gnu.org/licenses/>. - -#include <gtest/gtest.h> - -#include "../strings/vstring.hpp" -#include "../strings/literal.hpp" - -#include "../io/cxxstdio.hpp" - -#include "../poison.hpp" - -#define CB(X) (std::integral_constant<bool, (X)>::value) -TEST(ip4addr, cmp) -{ - constexpr static - IP4Address a = IP4_LOCALHOST; - constexpr static - IP4Address b = IP4_BROADCAST; - - EXPECT_FALSE(CB(a < a)); - EXPECT_TRUE (CB(a < b)); - EXPECT_FALSE(CB(b < a)); - EXPECT_FALSE(CB(b < b)); - - EXPECT_FALSE(CB(a > a)); - EXPECT_FALSE(CB(a > b)); - EXPECT_TRUE (CB(b > a)); - EXPECT_FALSE(CB(b > b)); - - EXPECT_TRUE (CB(a <= a)); - EXPECT_TRUE (CB(a <= b)); - EXPECT_FALSE(CB(b <= a)); - EXPECT_TRUE (CB(b <= b)); - - EXPECT_TRUE (CB(a >= a)); - EXPECT_FALSE(CB(a >= b)); - EXPECT_TRUE (CB(b >= a)); - EXPECT_TRUE (CB(b >= b)); - - EXPECT_TRUE (CB(a == a)); - EXPECT_FALSE(CB(a == b)); - EXPECT_FALSE(CB(b == a)); - EXPECT_TRUE (CB(b == b)); - - EXPECT_FALSE(CB(a != a)); - EXPECT_TRUE (CB(a != b)); - EXPECT_TRUE (CB(b != a)); - EXPECT_FALSE(CB(b != b)); -} - -TEST(ip4addr, str) -{ - IP4Address a; - EXPECT_EQ("0.0.0.0"_s, STRNPRINTF(17, "%s"_fmt, a)); - EXPECT_EQ("127.0.0.1"_s, STRNPRINTF(17, "%s"_fmt, IP4_LOCALHOST)); - EXPECT_EQ("255.255.255.255"_s, STRNPRINTF(17, "%s"_fmt, IP4_BROADCAST)); -} - -TEST(ip4addr, extract) -{ - IP4Address a; - EXPECT_TRUE(extract("0.0.0.0"_s, &a)); - EXPECT_EQ("0.0.0.0"_s, STRNPRINTF(16, "%s"_fmt, a)); - EXPECT_TRUE(extract("127.0.0.1"_s, &a)); - EXPECT_EQ("127.0.0.1"_s, STRNPRINTF(16, "%s"_fmt, a)); - EXPECT_TRUE(extract("255.255.255.255"_s, &a)); - EXPECT_EQ("255.255.255.255"_s, STRNPRINTF(16, "%s"_fmt, a)); - EXPECT_TRUE(extract("1.2.3.4"_s, &a)); - EXPECT_EQ("1.2.3.4"_s, STRNPRINTF(16, "%s"_fmt, a)); - - EXPECT_FALSE(extract("1.2.3.4.5"_s, &a)); - EXPECT_FALSE(extract("1.2.3.4."_s, &a)); - EXPECT_FALSE(extract("1.2.3."_s, &a)); - EXPECT_FALSE(extract("1.2.3"_s, &a)); - EXPECT_FALSE(extract("1.2."_s, &a)); - EXPECT_FALSE(extract("1.2"_s, &a)); - EXPECT_FALSE(extract("1."_s, &a)); - EXPECT_FALSE(extract("1"_s, &a)); - EXPECT_FALSE(extract(""_s, &a)); -} - - -TEST(ip4mask, body) -{ - IP4Mask m; - EXPECT_EQ(IP4Address(), m.addr()); - EXPECT_EQ(IP4Address(), m.mask()); - m = IP4Mask(IP4_LOCALHOST, IP4_BROADCAST); - EXPECT_EQ(IP4_LOCALHOST, m.addr()); - EXPECT_EQ(IP4_BROADCAST, m.mask()); -} - -TEST(ip4mask, str) -{ - IP4Mask m; - EXPECT_EQ("0.0.0.0/0.0.0.0"_s, STRNPRINTF(33, "%s"_fmt, m)); - m = IP4Mask(IP4_LOCALHOST, IP4_BROADCAST); - EXPECT_EQ("127.0.0.1/255.255.255.255"_s, STRNPRINTF(33, "%s"_fmt, m)); -} - -TEST(ip4mask, extract) -{ - IP4Mask m; - EXPECT_FALSE(extract("9.8.7.6/33"_s, &m)); - EXPECT_FALSE(extract("9.8.7.6.5"_s, &m)); - EXPECT_FALSE(extract("9.8.7.6/"_s, &m)); - EXPECT_FALSE(extract("9.8.7"_s, &m)); - EXPECT_FALSE(extract("9.8"_s, &m)); - EXPECT_FALSE(extract("9"_s, &m)); - - EXPECT_TRUE(extract("127.0.0.1"_s, &m)); - EXPECT_EQ("127.0.0.1/255.255.255.255"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("127.0.0.1."_s, &m)); - EXPECT_EQ("127.0.0.1/255.255.255.255"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("127.0.0."_s, &m)); - EXPECT_EQ("127.0.0.0/255.255.255.0"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("127.0."_s, &m)); - EXPECT_EQ("127.0.0.0/255.255.0.0"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("127."_s, &m)); - EXPECT_EQ("127.0.0.0/255.0.0.0"_s, STRNPRINTF(32, "%s"_fmt, m)); - - EXPECT_TRUE(extract("1.2.3.4/255.255.255.255"_s, &m)); - EXPECT_EQ("1.2.3.4/255.255.255.255"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("1.2.3.0/255.255.255.0"_s, &m)); - EXPECT_EQ("1.2.3.0/255.255.255.0"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("1.2.0.4/255.255.0.255"_s, &m)); - EXPECT_EQ("1.2.0.4/255.255.0.255"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("1.2.0.0/255.255.0.0"_s, &m)); - EXPECT_EQ("1.2.0.0/255.255.0.0"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("1.0.3.4/255.0.255.255"_s, &m)); - EXPECT_EQ("1.0.3.4/255.0.255.255"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("1.0.3.0/255.0.255.0"_s, &m)); - EXPECT_EQ("1.0.3.0/255.0.255.0"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("1.0.0.4/255.0.0.255"_s, &m)); - EXPECT_EQ("1.0.0.4/255.0.0.255"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("1.0.0.0/255.0.0.0"_s, &m)); - EXPECT_EQ("1.0.0.0/255.0.0.0"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("0.2.3.4/0.255.255.255"_s, &m)); - EXPECT_EQ("0.2.3.4/0.255.255.255"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("0.2.3.0/0.255.255.0"_s, &m)); - EXPECT_EQ("0.2.3.0/0.255.255.0"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("0.2.0.4/0.255.0.255"_s, &m)); - EXPECT_EQ("0.2.0.4/0.255.0.255"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("0.2.0.0/0.255.0.0"_s, &m)); - EXPECT_EQ("0.2.0.0/0.255.0.0"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("0.0.3.4/0.0.255.255"_s, &m)); - EXPECT_EQ("0.0.3.4/0.0.255.255"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("0.0.3.0/0.0.255.0"_s, &m)); - EXPECT_EQ("0.0.3.0/0.0.255.0"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("0.0.0.4/0.0.0.255"_s, &m)); - EXPECT_EQ("0.0.0.4/0.0.0.255"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("0.0.0.0/0.0.0.0"_s, &m)); - EXPECT_EQ("0.0.0.0/0.0.0.0"_s, STRNPRINTF(32, "%s"_fmt, m)); - - // please don't do this - EXPECT_TRUE(extract("120.248.200.217/89.57.126.5"_s, &m)); - EXPECT_EQ("88.56.72.1/89.57.126.5"_s, STRNPRINTF(32, "%s"_fmt, m)); - - EXPECT_TRUE(extract("0.0.0.0/32"_s, &m)); - EXPECT_EQ("0.0.0.0/255.255.255.255"_s, STRNPRINTF(32, "%s"_fmt, m)); - - EXPECT_TRUE(extract("0.0.0.0/31"_s, &m)); - EXPECT_EQ("0.0.0.0/255.255.255.254"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("0.0.0.0/30"_s, &m)); - EXPECT_EQ("0.0.0.0/255.255.255.252"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("0.0.0.0/29"_s, &m)); - EXPECT_EQ("0.0.0.0/255.255.255.248"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("0.0.0.0/28"_s, &m)); - EXPECT_EQ("0.0.0.0/255.255.255.240"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("0.0.0.0/27"_s, &m)); - EXPECT_EQ("0.0.0.0/255.255.255.224"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("0.0.0.0/26"_s, &m)); - EXPECT_EQ("0.0.0.0/255.255.255.192"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("0.0.0.0/25"_s, &m)); - EXPECT_EQ("0.0.0.0/255.255.255.128"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("0.0.0.0/24"_s, &m)); - EXPECT_EQ("0.0.0.0/255.255.255.0"_s, STRNPRINTF(32, "%s"_fmt, m)); - - EXPECT_TRUE(extract("0.0.0.0/23"_s, &m)); - EXPECT_EQ("0.0.0.0/255.255.254.0"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("0.0.0.0/22"_s, &m)); - EXPECT_EQ("0.0.0.0/255.255.252.0"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("0.0.0.0/21"_s, &m)); - EXPECT_EQ("0.0.0.0/255.255.248.0"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("0.0.0.0/20"_s, &m)); - EXPECT_EQ("0.0.0.0/255.255.240.0"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("0.0.0.0/19"_s, &m)); - EXPECT_EQ("0.0.0.0/255.255.224.0"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("0.0.0.0/18"_s, &m)); - EXPECT_EQ("0.0.0.0/255.255.192.0"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("0.0.0.0/17"_s, &m)); - EXPECT_EQ("0.0.0.0/255.255.128.0"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("0.0.0.0/16"_s, &m)); - EXPECT_EQ("0.0.0.0/255.255.0.0"_s, STRNPRINTF(32, "%s"_fmt, m)); - - EXPECT_TRUE(extract("0.0.0.0/15"_s, &m)); - EXPECT_EQ("0.0.0.0/255.254.0.0"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("0.0.0.0/14"_s, &m)); - EXPECT_EQ("0.0.0.0/255.252.0.0"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("0.0.0.0/13"_s, &m)); - EXPECT_EQ("0.0.0.0/255.248.0.0"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("0.0.0.0/12"_s, &m)); - EXPECT_EQ("0.0.0.0/255.240.0.0"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("0.0.0.0/11"_s, &m)); - EXPECT_EQ("0.0.0.0/255.224.0.0"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("0.0.0.0/10"_s, &m)); - EXPECT_EQ("0.0.0.0/255.192.0.0"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("0.0.0.0/9"_s, &m)); - EXPECT_EQ("0.0.0.0/255.128.0.0"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("0.0.0.0/8"_s, &m)); - EXPECT_EQ("0.0.0.0/255.0.0.0"_s, STRNPRINTF(32, "%s"_fmt, m)); - - EXPECT_TRUE(extract("0.0.0.0/7"_s, &m)); - EXPECT_EQ("0.0.0.0/254.0.0.0"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("0.0.0.0/6"_s, &m)); - EXPECT_EQ("0.0.0.0/252.0.0.0"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("0.0.0.0/5"_s, &m)); - EXPECT_EQ("0.0.0.0/248.0.0.0"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("0.0.0.0/4"_s, &m)); - EXPECT_EQ("0.0.0.0/240.0.0.0"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("0.0.0.0/3"_s, &m)); - EXPECT_EQ("0.0.0.0/224.0.0.0"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("0.0.0.0/2"_s, &m)); - EXPECT_EQ("0.0.0.0/192.0.0.0"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("0.0.0.0/1"_s, &m)); - EXPECT_EQ("0.0.0.0/128.0.0.0"_s, STRNPRINTF(32, "%s"_fmt, m)); - EXPECT_TRUE(extract("0.0.0.0/0"_s, &m)); - EXPECT_EQ("0.0.0.0/0.0.0.0"_s, STRNPRINTF(32, "%s"_fmt, m)); -} - -TEST(ip4mask, cover) -{ - IP4Address a; - IP4Address b = IP4_BROADCAST; - IP4Address l = IP4_LOCALHOST; - IP4Address h({127, 255, 255, 255}); - IP4Address p24l({10, 0, 0, 0}); - IP4Address p24h({10, 255, 255, 255}); - IP4Address p20l({172, 16, 0, 0}); - IP4Address p20h({172, 31, 255, 255}); - IP4Address p16l({192, 168, 0, 0}); - IP4Address p16h({192, 168, 255, 255}); - IP4Mask m; - EXPECT_TRUE(m.covers(a)); - EXPECT_TRUE(m.covers(b)); - EXPECT_TRUE(m.covers(l)); - EXPECT_TRUE(m.covers(h)); - EXPECT_TRUE(m.covers(p24l)); - EXPECT_TRUE(m.covers(p24h)); - EXPECT_TRUE(m.covers(p20l)); - EXPECT_TRUE(m.covers(p20h)); - EXPECT_TRUE(m.covers(p16l)); - EXPECT_TRUE(m.covers(p16h)); - m = IP4Mask(l, a); - EXPECT_TRUE(m.covers(a)); - EXPECT_TRUE(m.covers(b)); - EXPECT_TRUE(m.covers(l)); - EXPECT_TRUE(m.covers(h)); - EXPECT_TRUE(m.covers(p24l)); - EXPECT_TRUE(m.covers(p24h)); - EXPECT_TRUE(m.covers(p20l)); - EXPECT_TRUE(m.covers(p20h)); - EXPECT_TRUE(m.covers(p16l)); - EXPECT_TRUE(m.covers(p16h)); - m = IP4Mask(l, b); - EXPECT_FALSE(m.covers(a)); - EXPECT_FALSE(m.covers(b)); - EXPECT_TRUE(m.covers(l)); - EXPECT_FALSE(m.covers(h)); - EXPECT_FALSE(m.covers(p24l)); - EXPECT_FALSE(m.covers(p24h)); - EXPECT_FALSE(m.covers(p20l)); - EXPECT_FALSE(m.covers(p20h)); - EXPECT_FALSE(m.covers(p16l)); - EXPECT_FALSE(m.covers(p16h)); - - // but the really useful ones are with partial masks - m = IP4Mask(IP4Address({10, 0, 0, 0}), IP4Address({255, 0, 0, 0})); - EXPECT_FALSE(m.covers(a)); - EXPECT_FALSE(m.covers(b)); - EXPECT_FALSE(m.covers(l)); - EXPECT_FALSE(m.covers(h)); - EXPECT_TRUE(m.covers(p24l)); - EXPECT_TRUE(m.covers(p24h)); - EXPECT_FALSE(m.covers(p20l)); - EXPECT_FALSE(m.covers(p20h)); - EXPECT_FALSE(m.covers(p16l)); - EXPECT_FALSE(m.covers(p16h)); - EXPECT_FALSE(m.covers(IP4Address({9, 255, 255, 255}))); - EXPECT_FALSE(m.covers(IP4Address({11, 0, 0, 0}))); - m = IP4Mask(IP4Address({127, 0, 0, 0}), IP4Address({255, 0, 0, 0})); - EXPECT_FALSE(m.covers(a)); - EXPECT_FALSE(m.covers(b)); - EXPECT_TRUE(m.covers(l)); - EXPECT_TRUE(m.covers(h)); - EXPECT_FALSE(m.covers(p24l)); - EXPECT_FALSE(m.covers(p24h)); - EXPECT_FALSE(m.covers(p20l)); - EXPECT_FALSE(m.covers(p20h)); - EXPECT_FALSE(m.covers(p16l)); - EXPECT_FALSE(m.covers(p16h)); - EXPECT_FALSE(m.covers(IP4Address({126, 255, 255, 255}))); - EXPECT_FALSE(m.covers(IP4Address({128, 0, 0, 0}))); - m = IP4Mask(IP4Address({172, 16, 0, 0}), IP4Address({255, 240, 0, 0})); - EXPECT_FALSE(m.covers(a)); - EXPECT_FALSE(m.covers(b)); - EXPECT_FALSE(m.covers(l)); - EXPECT_FALSE(m.covers(h)); - EXPECT_FALSE(m.covers(p24l)); - EXPECT_FALSE(m.covers(p24h)); - EXPECT_TRUE(m.covers(p20l)); - EXPECT_TRUE(m.covers(p20h)); - EXPECT_FALSE(m.covers(p16l)); - EXPECT_FALSE(m.covers(p16h)); - EXPECT_FALSE(m.covers(IP4Address({172, 15, 255, 255}))); - EXPECT_FALSE(m.covers(IP4Address({172, 32, 0, 0}))); - m = IP4Mask(IP4Address({192, 168, 0, 0}), IP4Address({255, 255, 0, 0})); - EXPECT_FALSE(m.covers(a)); - EXPECT_FALSE(m.covers(b)); - EXPECT_FALSE(m.covers(l)); - EXPECT_FALSE(m.covers(h)); - EXPECT_FALSE(m.covers(p24l)); - EXPECT_FALSE(m.covers(p24h)); - EXPECT_FALSE(m.covers(p20l)); - EXPECT_FALSE(m.covers(p20h)); - EXPECT_TRUE(m.covers(p16l)); - EXPECT_TRUE(m.covers(p16h)); - EXPECT_FALSE(m.covers(IP4Address({192, 167, 255, 255}))); - EXPECT_FALSE(m.covers(IP4Address({192, 169, 0, 0}))); - - // OTOH this is crazy - EXPECT_TRUE(extract("120.248.200.217/89.57.126.5"_s, &m)); - EXPECT_TRUE(m.covers(IP4Address({120, 248, 200, 217}))); - EXPECT_TRUE(m.covers(IP4Address({88, 56, 72, 1}))); - EXPECT_FALSE(m.covers(IP4Address({88, 56, 72, 0}))); - EXPECT_FALSE(m.covers(IP4Address({88, 56, 72, 255}))); -} diff --git a/src/mmo/md5more.cpp b/src/mmo/md5more.cpp index c311583..96b12a7 100644 --- a/src/mmo/md5more.cpp +++ b/src/mmo/md5more.cpp @@ -29,7 +29,8 @@ #include "../io/cxxstdio.hpp" #include "../io/read.hpp" -#include "../mmo/ip.hpp" +#include "../net/ip.hpp" + #include "../mmo/mmo.hpp" #include "../poison.hpp" diff --git a/src/mmo/md5more.hpp b/src/mmo/md5more.hpp index 4b9895d..f3ab363 100644 --- a/src/mmo/md5more.hpp +++ b/src/mmo/md5more.hpp @@ -27,6 +27,8 @@ # include "../io/fwd.hpp" +# include "../net/fwd.hpp" + MD5_state MD5_from_FILE(io::ReadFile& in); // whoever wrote this fails basic understanding of diff --git a/src/mmo/mmo.hpp b/src/mmo/mmo.hpp index 15c3fa5..c72d815 100644 --- a/src/mmo/mmo.hpp +++ b/src/mmo/mmo.hpp @@ -32,8 +32,9 @@ # include "../generic/array.hpp" # include "../generic/enum.hpp" +# include "../net/timer.t.hpp" + # include "ids.hpp" -# include "timer.t.hpp" // affects CharName # define NAME_IGNORING_CASE 1 diff --git a/src/mmo/socket.cpp b/src/mmo/socket.cpp deleted file mode 100644 index 1d6094c..0000000 --- a/src/mmo/socket.cpp +++ /dev/null @@ -1,509 +0,0 @@ -#include "socket.hpp" -// socket.cpp - Network event system. -// -// Copyright © ????-2004 Athena Dev Teams -// Copyright © 2004-2011 The Mana World Development Team -// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com> -// Copyright © 2013 MadCamel -// -// This file is part of The Mana World (Athena server) -// -// 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 3 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, see <http://www.gnu.org/licenses/>. - -#include <netinet/tcp.h> -#include <sys/socket.h> - -#include <fcntl.h> - -#include <cstdlib> - -#include <array> - -#include "../compat/memory.hpp" - -#include "../io/cxxstdio.hpp" - -#include "../mmo/utils.hpp" - -#include "core.hpp" -#include "timer.hpp" - -#include "../poison.hpp" - -static -io::FD_Set readfds; -static -int fd_max; - -static -const uint32_t RFIFO_SIZE = 65536; -static -const uint32_t WFIFO_SIZE = 65536; - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wold-style-cast" -static -std::array<std::unique_ptr<Session>, FD_SETSIZE> session; -#pragma GCC diagnostic pop - -Session::Session(SessionIO io, SessionParsers p) -: created() -, connected() -, eof() -, timed_close() -, rdata(), wdata() -, max_rdata(), max_wdata() -, rdata_size(), wdata_size() -, rdata_pos() -, client_ip() -, func_recv() -, func_send() -, func_parse() -, func_delete() -, for_inferior() -, session_data() -, fd() -{ - set_io(io); - set_parsers(p); -} -void Session::set_io(SessionIO io) -{ - func_send = io.func_send; - func_recv = io.func_recv; -} -void Session::set_parsers(SessionParsers p) -{ - func_parse = p.func_parse; - func_delete = p.func_delete; -} - - -void set_session(io::FD fd, std::unique_ptr<Session> sess) -{ - int f = fd.uncast_dammit(); - assert (0 <= f && f < FD_SETSIZE); - session[f] = std::move(sess); -} -Session *get_session(io::FD fd) -{ - int f = fd.uncast_dammit(); - if (0 <= f && f < FD_SETSIZE) - return session[f].get(); - return nullptr; -} -void reset_session(io::FD fd) -{ - int f = fd.uncast_dammit(); - assert (0 <= f && f < FD_SETSIZE); - session[f] = nullptr; -} -int get_fd_max() { return fd_max; } -IteratorPair<ValueIterator<io::FD, IncrFD>> iter_fds() -{ - return {io::FD::cast_dammit(0), io::FD::cast_dammit(fd_max)}; -} - -/// clean up by discarding handled bytes -inline -void RFIFOFLUSH(Session *s) -{ - really_memmove(&s->rdata[0], &s->rdata[s->rdata_pos], RFIFOREST(s)); - s->rdata_size = RFIFOREST(s); - s->rdata_pos = 0; -} - -/// how much room there is to read more data -inline -size_t RFIFOSPACE(Session *s) -{ - return s->max_rdata - s->rdata_size; -} - - -/// Read from socket to the queue -static -void recv_to_fifo(Session *s) -{ - ssize_t len = s->fd.read(&s->rdata[s->rdata_size], - RFIFOSPACE(s)); - - if (len > 0) - { - s->rdata_size += len; - s->connected = 1; - } - else - { - s->set_eof(); - } -} - -static -void send_from_fifo(Session *s) -{ - ssize_t len = s->fd.write(&s->wdata[0], s->wdata_size); - - if (len > 0) - { - s->wdata_size -= len; - if (s->wdata_size) - { - really_memmove(&s->wdata[0], &s->wdata[len], - s->wdata_size); - } - s->connected = 1; - } - else - { - s->set_eof(); - } -} - -static -void nothing_delete(Session *s) -{ - (void)s; -} - -static -void connect_client(Session *ls) -{ - struct sockaddr_in client_address; - socklen_t len = sizeof(client_address); - - io::FD fd = ls->fd.accept(reinterpret_cast<struct sockaddr *>(&client_address), &len); - if (fd == io::FD()) - { - perror("accept"); - return; - } - if (fd.uncast_dammit() >= SOFT_LIMIT) - { - FPRINTF(stderr, "softlimit reached, disconnecting : %d\n"_fmt, fd.uncast_dammit()); - fd.shutdown(SHUT_RDWR); - fd.close(); - return; - } - if (fd_max <= fd.uncast_dammit()) - { - fd_max = fd.uncast_dammit() + 1; - } - - const int yes = 1; - /// Allow to bind() again after the server restarts. - // Since the socket is still in the TIME_WAIT, there's a possibility - // that formerly lost packets might be delivered and confuse the server. - fd.setsockopt(SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); - /// Send packets as soon as possible - /// even if the kernel thinks there is too little for it to be worth it! - /// Testing shows this is indeed a good idea. - fd.setsockopt(IPPROTO_TCP, TCP_NODELAY, &yes, sizeof yes); - - // Linux-ism: Set socket options to optimize for thin streams - // See http://lwn.net/Articles/308919/ and - // Documentation/networking/tcp-thin.txt .. Kernel 3.2+ -#ifdef TCP_THIN_LINEAR_TIMEOUTS - fd.setsockopt(IPPROTO_TCP, TCP_THIN_LINEAR_TIMEOUTS, &yes, sizeof yes); -#endif -#ifdef TCP_THIN_DUPACK - fd.setsockopt(IPPROTO_TCP, TCP_THIN_DUPACK, &yes, sizeof yes); -#endif - - readfds.set(fd); - - fd.fcntl(F_SETFL, O_NONBLOCK); - - set_session(fd, make_unique<Session>( - SessionIO{.func_recv= recv_to_fifo, .func_send= send_from_fifo}, - ls->for_inferior)); - Session *s = get_session(fd); - s->fd = fd; - s->rdata.new_(RFIFO_SIZE); - s->wdata.new_(WFIFO_SIZE); - s->max_rdata = RFIFO_SIZE; - s->max_wdata = WFIFO_SIZE; - s->client_ip = IP4Address(client_address.sin_addr); - s->created = TimeT::now(); - s->connected = 0; -} - -Session *make_listen_port(uint16_t port, SessionParsers inferior) -{ - struct sockaddr_in server_address; - io::FD fd = io::FD::socket(AF_INET, SOCK_STREAM, 0); - if (fd == io::FD()) - { - perror("socket"); - return nullptr; - } - if (fd_max <= fd.uncast_dammit()) - fd_max = fd.uncast_dammit() + 1; - - fd.fcntl(F_SETFL, O_NONBLOCK); - - const int yes = 1; - /// Allow to bind() again after the server restarts. - // Since the socket is still in the TIME_WAIT, there's a possibility - // that formerly lost packets might be delivered and confuse the server. - fd.setsockopt(SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); - /// Send packets as soon as possible - /// even if the kernel thinks there is too little for it to be worth it! - // I'm not convinced this is a good idea; although in minimizes the - // latency for an individual write, it increases traffic in general. - fd.setsockopt(IPPROTO_TCP, TCP_NODELAY, &yes, sizeof yes); - - server_address.sin_family = AF_INET; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wold-style-cast" -#if __GNUC__ > 4 || __GNUC_MINOR__ >= 8 -# pragma GCC diagnostic ignored "-Wuseless-cast" -#endif - server_address.sin_addr.s_addr = htonl(INADDR_ANY); - server_address.sin_port = htons(port); -#pragma GCC diagnostic pop - - if (fd.bind(reinterpret_cast<struct sockaddr *>(&server_address), - sizeof(server_address)) == -1) - { - perror("bind"); - exit(1); - } - if (fd.listen(5) == -1) - { /* error */ - perror("listen"); - exit(1); - } - - readfds.set(fd); - - set_session(fd, make_unique<Session>( - SessionIO{.func_recv= connect_client, .func_send= nullptr}, - SessionParsers{.func_parse= nullptr, .func_delete= nothing_delete})); - Session *s = get_session(fd); - s->for_inferior = inferior; - s->fd = fd; - - s->created = TimeT::now(); - s->connected = 1; - - return s; -} - -Session *make_connection(IP4Address ip, uint16_t port, SessionParsers parsers) -{ - struct sockaddr_in server_address; - io::FD fd = io::FD::socket(AF_INET, SOCK_STREAM, 0); - if (fd == io::FD()) - { - perror("socket"); - return nullptr; - } - if (fd_max <= fd.uncast_dammit()) - fd_max = fd.uncast_dammit() + 1; - - const int yes = 1; - /// Allow to bind() again after the server restarts. - // Since the socket is still in the TIME_WAIT, there's a possibility - // that formerly lost packets might be delivered and confuse the server. - fd.setsockopt(SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); - /// Send packets as soon as possible - /// even if the kernel thinks there is too little for it to be worth it! - // I'm not convinced this is a good idea; although in minimizes the - // latency for an individual write, it increases traffic in general. - fd.setsockopt(IPPROTO_TCP, TCP_NODELAY, &yes, sizeof yes); - - server_address.sin_family = AF_INET; - server_address.sin_addr = in_addr(ip); -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wold-style-cast" -#if __GNUC__ > 4 || __GNUC_MINOR__ >= 8 -# pragma GCC diagnostic ignored "-Wuseless-cast" -#endif - server_address.sin_port = htons(port); -#pragma GCC diagnostic pop - - fd.fcntl(F_SETFL, O_NONBLOCK); - - /// Errors not caught - we must not block - /// Let the main select() loop detect when we know the state - fd.connect(reinterpret_cast<struct sockaddr *>(&server_address), - sizeof(struct sockaddr_in)); - - readfds.set(fd); - - set_session(fd, make_unique<Session>( - SessionIO{.func_recv= recv_to_fifo, .func_send= send_from_fifo}, - parsers)); - Session *s = get_session(fd); - s->fd = fd; - s->rdata.new_(RFIFO_SIZE); - s->wdata.new_(WFIFO_SIZE); - - s->max_rdata = RFIFO_SIZE; - s->max_wdata = WFIFO_SIZE; - s->created = TimeT::now(); - s->connected = 1; - - return s; -} - -void delete_session(Session *s) -{ - if (!s) - return; - // this needs to be before the fd_max-- - s->func_delete(s); - - io::FD fd = s->fd; - // If this was the highest fd, decrease it - // We could add a loop to decrement fd_max further for every null session, - // but this is cheap and good enough for the typical case - if (fd.uncast_dammit() == fd_max - 1) - fd_max--; - readfds.clr(fd); - { - s->rdata.delete_(); - s->wdata.delete_(); - s->session_data.reset(); - reset_session(fd); - } - - // just close() would try to keep sending buffers - fd.shutdown(SHUT_RDWR); - fd.close(); -} - -void realloc_fifo(Session *s, size_t rfifo_size, size_t wfifo_size) -{ - if (s->max_rdata != rfifo_size && s->rdata_size < rfifo_size) - { - s->rdata.resize(rfifo_size); - s->max_rdata = rfifo_size; - } - if (s->max_wdata != wfifo_size && s->wdata_size < wfifo_size) - { - s->wdata.resize(wfifo_size); - s->max_wdata = wfifo_size; - } -} - -void WFIFOSET(Session *s, size_t len) -{ - if (s->wdata_size + len + 16384 > s->max_wdata) - { - realloc_fifo(s, s->max_rdata, s->max_wdata << 1); - PRINTF("socket: %d wdata expanded to %zu bytes.\n"_fmt, s, s->max_wdata); - } - if (s->wdata_size + len + 2048 < s->max_wdata) - s->wdata_size += len; - else - FPRINTF(stderr, "socket: %d wdata lost !!\n"_fmt, s), abort(); -} - -void do_sendrecv(interval_t next_ms) -{ - bool any = false; - io::FD_Set rfd = readfds, wfd; - for (io::FD i : iter_fds()) - { - Session *s = get_session(i); - if (s) - { - any = true; - if (s->wdata_size) - wfd.set(i); - } - } - if (!any) - { - if (!has_timers()) - { - PRINTF("Shutting down - nothing to do\n"_fmt); - runflag = false; - } - return; - } - struct timeval timeout; - { - std::chrono::seconds next_s = std::chrono::duration_cast<std::chrono::seconds>(next_ms); - std::chrono::microseconds next_us = next_ms - next_s; - timeout.tv_sec = next_s.count(); - timeout.tv_usec = next_us.count(); - } - if (io::FD_Set::select(fd_max, &rfd, &wfd, NULL, &timeout) <= 0) - return; - for (io::FD i : iter_fds()) - { - Session *s = get_session(i); - if (!s) - continue; - if (wfd.isset(i) && !s->eof) - { - if (s->func_send) - //send_from_fifo(i); - s->func_send(s); - } - if (rfd.isset(i) && !s->eof) - { - if (s->func_recv) - //recv_to_fifo(i); - //or connect_client(i); - s->func_recv(s); - } - } -} - -void do_parsepacket(void) -{ - for (io::FD i : iter_fds()) - { - Session *s = get_session(i); - if (!s) - continue; - if (!s->connected - && static_cast<time_t>(TimeT::now()) - static_cast<time_t>(s->created) > CONNECT_TIMEOUT) - { - PRINTF("Session #%d timed out\n"_fmt, s); - s->set_eof(); - } - if (s->rdata_size && !s->eof && s->func_parse) - { - s->func_parse(s); - /// some func_parse may call delete_session - // (that's kind of evil) - s = get_session(i); - if (!s) - continue; - } - if (s->eof) - { - delete_session(s); - continue; - } - /// Reclaim buffer space for what was read - RFIFOFLUSH(s); - } -} - -void RFIFOSKIP(Session *s, size_t len) -{ - s->rdata_pos += len; - - if (s->rdata_size < s->rdata_pos) - { - FPRINTF(stderr, "too many skip\n"_fmt); - abort(); - } -} diff --git a/src/mmo/socket.hpp b/src/mmo/socket.hpp deleted file mode 100644 index ff10c64..0000000 --- a/src/mmo/socket.hpp +++ /dev/null @@ -1,424 +0,0 @@ -#ifndef TMWA_MMO_SOCKET_HPP -#define TMWA_MMO_SOCKET_HPP -// socket.hpp - Network event system. -// -// Copyright © ????-2004 Athena Dev Teams -// Copyright © 2004-2011 The Mana World Development Team -// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com> -// -// This file is part of The Mana World (Athena server) -// -// 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 3 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, see <http://www.gnu.org/licenses/>. - -# include "fwd.hpp" - -# include <algorithm> - -# include <sys/select.h> - -# include <memory> - -# include "../compat/iter.hpp" -# include "../compat/rawmem.hpp" - -# include "../strings/astring.hpp" -# include "../strings/vstring.hpp" -# include "../strings/xstring.hpp" - -# include "../io/fd.hpp" - -# include "dumb_ptr.hpp" -# include "ip.hpp" -# include "utils.hpp" -# include "timer.t.hpp" - -struct SessionData -{ -}; -struct SessionDeleter -{ - // defined per-server - void operator()(SessionData *sd); -}; - -struct SessionIO -{ - void (*func_recv)(Session *); - void (*func_send)(Session *); -}; - -struct SessionParsers -{ - void (*func_parse)(Session *); - void (*func_delete)(Session *); -}; - -struct Session -{ - Session(SessionIO, SessionParsers); - Session(Session&&) = delete; - Session& operator = (Session&&) = delete; - - void set_io(SessionIO); - void set_parsers(SessionParsers); - - /// Checks whether a newly-connected socket actually does anything - TimeT created; - bool connected; - -private: - /// Flag needed since structure must be freed in a server-dependent manner - bool eof; -public: - void set_eof() { eof = true; } - - /// Currently used by clif_setwaitclose - Timer timed_close; - - /// Since this is a single-threaded application, it can't block - /// These are the read/write queues - dumb_ptr<uint8_t[]> rdata, wdata; - size_t max_rdata, max_wdata; - /// How much is actually in the queue - size_t rdata_size, wdata_size; - /// How much has already been read from the queue - /// Note that there is no need for a wdata_pos - size_t rdata_pos; - - IP4Address client_ip; - -private: - /// Send or recieve - /// Only called when select() indicates the socket is ready - /// If, after that, nothing is read, it sets eof - // These could probably be hard-coded with a little work - void (*func_recv)(Session *); - void (*func_send)(Session *); - /// This is the important one - /// Set to different functions depending on whether the connection - /// is a player or a server/ladmin - void (*func_parse)(Session *); - /// Cleanup function since we're not fully RAII yet - void (*func_delete)(Session *); - -public: - // this really ought to be part of session_data, once that gets sane - SessionParsers for_inferior; - - /// Server-specific data type - // (this really should include the deleter, but ...) - std::unique_ptr<SessionData, SessionDeleter> session_data; - - io::FD fd; - - friend void do_sendrecv(interval_t next); - friend void do_parsepacket(void); - friend void delete_session(Session *); -}; - -inline -int convert_for_printf(Session *s) -{ - return s->fd.uncast_dammit(); -} - -// save file descriptors for important stuff -constexpr int SOFT_LIMIT = FD_SETSIZE - 50; - -// socket timeout to establish a full connection in seconds -constexpr int CONNECT_TIMEOUT = 15; - - -void set_session(io::FD fd, std::unique_ptr<Session> sess); -Session *get_session(io::FD fd); -void reset_session(io::FD fd); -int get_fd_max(); - -class IncrFD -{ -public: - static - io::FD inced(io::FD v) - { - return io::FD::cast_dammit(v.uncast_dammit() + 1); - } -}; -IteratorPair<ValueIterator<io::FD, IncrFD>> iter_fds(); - - -/// open a socket, bind, and listen. Return an fd, or -1 if socket() fails, -/// but exit if bind() or listen() fails -Session *make_listen_port(uint16_t port, SessionParsers inferior); -/// Connect to an address, return a connected socket or -1 -// FIXME - this is IPv4 only! -Session *make_connection(IP4Address ip, uint16_t port, SessionParsers); -/// free() the structure and close() the fd -void delete_session(Session *); -/// Make a the internal queues bigger -void realloc_fifo(Session *s, size_t rfifo_size, size_t wfifo_size); -/// Update all sockets that can be read/written from the queues -void do_sendrecv(interval_t next); -/// Call the parser function for every socket that has read data -void do_parsepacket(void); - -template<class T> -uint8_t *pod_addressof_m(T& structure) -{ - static_assert(is_trivially_copyable<T>::value, "Can only byte-copy POD-ish structs"); - return &reinterpret_cast<uint8_t&>(structure); -} - -template<class T> -const uint8_t *pod_addressof_c(const T& structure) -{ - static_assert(is_trivially_copyable<T>::value, "Can only byte-copy POD-ish structs"); - return &reinterpret_cast<const uint8_t&>(structure); -} - - -/// Check how much can be read -inline -size_t RFIFOREST(Session *s) -{ - return s->rdata_size - s->rdata_pos; -} -/// Read from the queue -inline -const void *RFIFOP(Session *s, size_t pos) -{ - return &s->rdata[s->rdata_pos + pos]; -} -inline -uint8_t RFIFOB(Session *s, size_t pos) -{ - return *static_cast<const uint8_t *>(RFIFOP(s, pos)); -} -inline -uint16_t RFIFOW(Session *s, size_t pos) -{ - return *static_cast<const uint16_t *>(RFIFOP(s, pos)); -} -inline -uint32_t RFIFOL(Session *s, size_t pos) -{ - return *static_cast<const uint32_t *>(RFIFOP(s, pos)); -} -template<class T> -void RFIFO_STRUCT(Session *s, size_t pos, T& structure) -{ - really_memcpy(pod_addressof_m(structure), static_cast<const uint8_t *>(RFIFOP(s, pos)), sizeof(T)); -} -inline -IP4Address RFIFOIP(Session *s, size_t pos) -{ - IP4Address o; - RFIFO_STRUCT(s, pos, o); - return o; -} -template<uint8_t len> -inline -VString<len-1> RFIFO_STRING(Session *s, size_t pos) -{ - const char *const begin = static_cast<const char *>(RFIFOP(s, pos)); - const char *const end = begin + len-1; - const char *const mid = std::find(begin, end, '\0'); - return XString(begin, mid, nullptr); -} -inline -AString RFIFO_STRING(Session *s, size_t pos, size_t len) -{ - const char *const begin = static_cast<const char *>(RFIFOP(s, pos)); - const char *const end = begin + len; - const char *const mid = std::find(begin, end, '\0'); - return XString(begin, mid, nullptr); -} -inline -void RFIFO_BUF_CLONE(Session *s, uint8_t *buf, size_t len) -{ - really_memcpy(buf, static_cast<const uint8_t *>(RFIFOP(s, 0)), len); -} - -/// Done reading -void RFIFOSKIP(Session *s, size_t len); - -/// Read from an arbitrary buffer -inline -const void *RBUFP(const uint8_t *p, size_t pos) -{ - return p + pos; -} -inline -uint8_t RBUFB(const uint8_t *p, size_t pos) -{ - return *static_cast<const uint8_t *>(RBUFP(p, pos)); -} -inline -uint16_t RBUFW(const uint8_t *p, size_t pos) -{ - return *static_cast<const uint16_t *>(RBUFP(p, pos)); -} -inline -uint32_t RBUFL(const uint8_t *p, size_t pos) -{ - return *static_cast<const uint32_t *>(RBUFP(p, pos)); -} -template<class T> -void RBUF_STRUCT(const uint8_t *p, size_t pos, T& structure) -{ - really_memcpy(pod_addressof_m(structure), p + pos, sizeof(T)); -} -inline -IP4Address RBUFIP(const uint8_t *p, size_t pos) -{ - IP4Address o; - RBUF_STRUCT(p, pos, o); - return o; -} -template<uint8_t len> -inline -VString<len-1> RBUF_STRING(const uint8_t *p, size_t pos) -{ - const char *const begin = static_cast<const char *>(RBUFP(p, pos)); - const char *const end = begin + len-1; - const char *const mid = std::find(begin, end, '\0'); - return XString(begin, mid, nullptr); -} -inline -AString RBUF_STRING(const uint8_t *p, size_t pos, size_t len) -{ - const char *const begin = static_cast<const char *>(RBUFP(p, pos)); - const char *const end = begin + len; - const char *const mid = std::find(begin, end, '\0'); - return XString(begin, mid, nullptr); -} - - -/// Unused - check how much data can be written -// the existence of this seems scary -inline -size_t WFIFOSPACE(Session *s) -{ - return s->max_wdata - s->wdata_size; -} -/// Write to the queue -inline -void *WFIFOP(Session *s, size_t pos) -{ - return &s->wdata[s->wdata_size + pos]; -} -inline -uint8_t& WFIFOB(Session *s, size_t pos) -{ - return *static_cast<uint8_t *>(WFIFOP(s, pos)); -} -inline -uint16_t& WFIFOW(Session *s, size_t pos) -{ - return *static_cast<uint16_t *>(WFIFOP(s, pos)); -} -inline -uint32_t& WFIFOL(Session *s, size_t pos) -{ - return *static_cast<uint32_t *>(WFIFOP(s, pos)); -} -template<class T> -void WFIFO_STRUCT(Session *s, size_t pos, T& structure) -{ - really_memcpy(static_cast<uint8_t *>(WFIFOP(s, pos)), pod_addressof_c(structure), sizeof(T)); -} -inline -IP4Address& WFIFOIP(Session *s, size_t pos) -{ - static_assert(is_trivially_copyable<IP4Address>::value, "That was the whole point"); - return *static_cast<IP4Address *>(WFIFOP(s, pos)); -} -inline -void WFIFO_STRING(Session *s, size_t pos, XString str, size_t len) -{ - char *const begin = static_cast<char *>(WFIFOP(s, pos)); - char *const end = begin + len; - char *const mid = std::copy(str.begin(), str.end(), begin); - std::fill(mid, end, '\0'); -} -inline -void WFIFO_ZERO(Session *s, size_t pos, size_t len) -{ - uint8_t *b = static_cast<uint8_t *>(WFIFOP(s, pos)); - uint8_t *e = b + len; - std::fill(b, e, '\0'); -} -inline -void WFIFO_BUF_CLONE(Session *s, const uint8_t *buf, size_t len) -{ - really_memcpy(static_cast<uint8_t *>(WFIFOP(s, 0)), buf, len); -} - -/// Finish writing -void WFIFOSET(Session *s, size_t len); - -/// Write to an arbitrary buffer -inline -void *WBUFP(uint8_t *p, size_t pos) -{ - return p + pos; -} -inline -uint8_t& WBUFB(uint8_t *p, size_t pos) -{ - return *static_cast<uint8_t *>(WBUFP(p, pos)); -} -inline -uint16_t& WBUFW(uint8_t *p, size_t pos) -{ - return *static_cast<uint16_t *>(WBUFP(p, pos)); -} -inline -uint32_t& WBUFL(uint8_t *p, size_t pos) -{ - return *static_cast<uint32_t *>(WBUFP(p, pos)); -} -template<class T> -void WBUF_STRUCT(uint8_t *p, size_t pos, T& structure) -{ - really_memcpy(p + pos, pod_addressof_c(structure), sizeof(T)); -} -inline -IP4Address& WBUFIP(uint8_t *p, size_t pos) -{ - return *static_cast<IP4Address *>(WBUFP(p, pos)); -} -inline -void WBUF_STRING(uint8_t *p, size_t pos, XString s, size_t len) -{ - char *const begin = static_cast<char *>(WBUFP(p, pos)); - char *const end = begin + len; - char *const mid = std::copy(s.begin(), s.end(), begin); - std::fill(mid, end, '\0'); -} -inline -void WBUF_ZERO(uint8_t *p, size_t pos, size_t len) -{ - uint8_t *b = static_cast<uint8_t *>(WBUFP(p, pos)); - uint8_t *e = b + len; - std::fill(b, e, '\0'); -} - -inline -void RFIFO_WFIFO_CLONE(Session *rs, Session *ws, size_t len) -{ - really_memcpy(static_cast<uint8_t *>(WFIFOP(ws, 0)), - static_cast<const uint8_t *>(RFIFOP(rs, 0)), len); -} - -#endif // TMWA_MMO_SOCKET_HPP diff --git a/src/mmo/timer.cpp b/src/mmo/timer.cpp deleted file mode 100644 index a85b8be..0000000 --- a/src/mmo/timer.cpp +++ /dev/null @@ -1,217 +0,0 @@ -#include "timer.hpp" -// timer.cpp - Future event scheduler. -// -// Copyright © ????-2004 Athena Dev Teams -// Copyright © 2004-2011 The Mana World Development Team -// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com> -// -// This file is part of The Mana World (Athena server) -// -// 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 3 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, see <http://www.gnu.org/licenses/>. - -#include <sys/stat.h> -#include <sys/time.h> - -#include <cassert> - -#include <algorithm> -#include <queue> - -#include "../strings/zstring.hpp" - -#include "../poison.hpp" - -struct TimerData -{ - /// This will be reset on call, to avoid problems. - Timer *owner; - - /// When it will be triggered - tick_t tick; - /// What will be done - timer_func func; - /// Repeat rate - 0 for oneshot - interval_t interval; - - TimerData(Timer *o, tick_t t, timer_func f, interval_t i) - : owner(o) - , tick(t) - , func(std::move(f)) - , interval(i) - {} -}; - -struct TimerCompare -{ - /// implement "less than" - bool operator() (dumb_ptr<TimerData> l, dumb_ptr<TimerData> r) - { - // C++ provides a max-heap, but we want - // the smallest tick to be the head (a min-heap). - return l->tick > r->tick; - } -}; - -static -std::priority_queue<dumb_ptr<TimerData>, std::vector<dumb_ptr<TimerData>>, TimerCompare> timer_heap; - - -tick_t gettick_cache; - -tick_t milli_clock::now(void) noexcept -{ - struct timeval tval; - // BUG: This will cause strange behavior if the system clock is changed! - // it should be reimplemented in terms of clock_gettime(CLOCK_MONOTONIC, ) - gettimeofday(&tval, NULL); - return gettick_cache = tick_t(std::chrono::seconds(tval.tv_sec) - + std::chrono::duration_cast<std::chrono::milliseconds>( - std::chrono::microseconds(tval.tv_usec))); -} - -static -void do_nothing(TimerData *, tick_t) -{ -} - -void Timer::cancel() -{ - if (!td) - return; - - assert (this == td->owner); - td->owner = nullptr; - td->func = do_nothing; - td->interval = interval_t::zero(); - td = nullptr; -} - -void Timer::detach() -{ - assert (this == td->owner); - td->owner = nullptr; - td = nullptr; -} - -static -void push_timer_heap(dumb_ptr<TimerData> td) -{ - timer_heap.push(td); -} - -static -dumb_ptr<TimerData> top_timer_heap(void) -{ - if (timer_heap.empty()) - return dumb_ptr<TimerData>(); - return timer_heap.top(); -} - -static -void pop_timer_heap(void) -{ - timer_heap.pop(); -} - -Timer::Timer(tick_t tick, timer_func func, interval_t interval) -: td(dumb_ptr<TimerData>::make(this, tick, std::move(func), interval)) -{ - assert (interval >= interval_t::zero()); - - push_timer_heap(td); -} - -Timer::Timer(Timer&& t) -: td(t.td) -{ - t.td = nullptr; - if (td) - { - assert (td->owner == &t); - td->owner = this; - } -} - -Timer& Timer::operator = (Timer&& t) -{ - std::swap(td, t.td); - if (td) - { - assert (td->owner == &t); - td->owner = this; - } - if (t.td) - { - assert (t.td->owner == this); - t.td->owner = &t; - } - return *this; -} - -interval_t do_timer(tick_t tick) -{ - /// Number of milliseconds until it calls this again - // this says to wait 1 sec if all timers get popped - interval_t nextmin = std::chrono::seconds(1); - - while (dumb_ptr<TimerData> td = top_timer_heap()) - { - // while the heap is not empty and - if (td->tick > tick) - { - /// Return the time until the next timer needs to goes off - nextmin = td->tick - tick; - break; - } - pop_timer_heap(); - - // Prevent destroying the object we're in. - // Note: this would be surprising in an interval timer, - // but all interval timers do an immediate explicit detach(). - if (td->owner) - td->owner->detach(); - // If we are too far past the requested tick, call with - // the current tick instead to fix reregistration problems - if (td->tick + std::chrono::seconds(1) < tick) - td->func(td.operator->(), tick); - else - td->func(td.operator->(), td->tick); - - if (td->interval == interval_t::zero()) - { - td.delete_(); - continue; - } - if (td->tick + std::chrono::seconds(1) < tick) - td->tick = tick + td->interval; - else - td->tick += td->interval; - push_timer_heap(td); - } - - return std::max(nextmin, std::chrono::milliseconds(10)); -} - -tick_t file_modified(ZString name) -{ - struct stat buf; - if (stat(name.c_str(), &buf)) - return tick_t(); - return tick_t(std::chrono::seconds(buf.st_mtime)); -} - -bool has_timers() -{ - return !timer_heap.empty(); -} diff --git a/src/mmo/timer.hpp b/src/mmo/timer.hpp deleted file mode 100644 index ddb559f..0000000 --- a/src/mmo/timer.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef TMWA_MMO_TIMER_HPP -#define TMWA_MMO_TIMER_HPP -// timer.hpp - Future event scheduler. -// -// Copyright © ????-2004 Athena Dev Teams -// Copyright © 2004-2011 The Mana World Development Team -// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com> -// -// This file is part of The Mana World (Athena server) -// -// 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 3 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, see <http://www.gnu.org/licenses/>. - -# include "timer.t.hpp" - -# include "fwd.hpp" - -# include "../strings/fwd.hpp" - -// updated automatically when using milli_clock::now() -// which is done only by core.cpp -extern tick_t gettick_cache; - -inline -tick_t gettick(void) -{ - return gettick_cache; -} - -/// Do all timers scheduled before tick, and return the number of -/// milliseconds until the next timer happens -interval_t do_timer(tick_t tick); - -/// Stat a file, and return its modification time, truncated to seconds. -tick_t file_modified(ZString name); - -/// Check if there are any events at all scheduled. -bool has_timers(); - -#endif // TMWA_MMO_TIMER_HPP diff --git a/src/mmo/timer.t.hpp b/src/mmo/timer.t.hpp deleted file mode 100644 index 549959a..0000000 --- a/src/mmo/timer.t.hpp +++ /dev/null @@ -1,88 +0,0 @@ -#ifndef TMWA_MMO_TIMER_T_HPP -#define TMWA_MMO_TIMER_T_HPP -// timer.t.hpp - Future event scheduler. -// -// Copyright © ????-2004 Athena Dev Teams -// Copyright © 2004-2011 The Mana World Development Team -// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com> -// -// This file is part of The Mana World (Athena server) -// -// 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 3 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, see <http://www.gnu.org/licenses/>. - -# include "fwd.hpp" - -# include <chrono> -# include <functional> - -# include "dumb_ptr.hpp" - -/// An implementation of the C++ "clock" concept, exposing -/// durations in milliseconds. -class milli_clock -{ -public: - typedef std::chrono::milliseconds duration; - typedef duration::rep rep; - typedef duration::period period; - typedef std::chrono::time_point<milli_clock, duration> time_point; - static const bool is_steady = true; // assumed - not necessarily true - - static time_point now() noexcept; -}; - -/// A point in time. -typedef milli_clock::time_point tick_t; -/// The difference between two points in time. -typedef milli_clock::duration interval_t; -/// (to get additional arguments, use std::bind or a lambda). -typedef std::function<void (TimerData *, tick_t)> timer_func; - -class Timer -{ - friend struct TimerData; - dumb_ptr<TimerData> td; - - Timer(const Timer&) = delete; - Timer& operator = (const Timer&) = delete; -public: - /// Don't own anything yet. - Timer() = default; - /// Schedule a timer for the given tick. - /// If you do not wish to keep track of it, call disconnect(). - /// Otherwise, you may cancel() or replace (operator =) it later. - /// - /// If the interval argument is given, the timer will reschedule - /// itself again forever. Otherwise, it will disconnect() itself - /// just BEFORE it is called. - Timer(tick_t tick, timer_func func, interval_t interval=interval_t::zero()); - - Timer(Timer&& t); - Timer& operator = (Timer&& t); - ~Timer() { cancel(); } - - /// Cancel the delivery of this timer's function, and make it falsy. - /// Implementation note: this doesn't actually remove it, just sets - /// the functor to do_nothing, and waits for the tick before removing. - void cancel(); - /// Make it falsy without cancelling the timer, - void detach(); - - /// Check if there is a timer connected. - explicit operator bool() { return bool(td); } - /// Check if there is no connected timer. - bool operator !() { return !td; } -}; - -#endif // TMWA_MMO_TIMER_T_HPP |