diff options
Diffstat (limited to 'src/net')
-rw-r--r-- | src/net/fwd.hpp | 9 | ||||
-rw-r--r-- | src/net/ip.cpp | 34 | ||||
-rw-r--r-- | src/net/ip.hpp | 8 | ||||
-rw-r--r-- | src/net/ip_test.cpp | 1 | ||||
-rw-r--r-- | src/net/packets.cpp | 106 | ||||
-rw-r--r-- | src/net/packets.hpp | 585 | ||||
-rw-r--r-- | src/net/socket.cpp | 16 | ||||
-rw-r--r-- | src/net/socket.hpp | 19 | ||||
-rw-r--r-- | src/net/timer.hpp | 3 | ||||
-rw-r--r-- | src/net/timer.py | 117 | ||||
-rw-r--r-- | src/net/timestamp-utils.cpp | 72 | ||||
-rw-r--r-- | src/net/timestamp-utils.hpp | 54 |
12 files changed, 301 insertions, 723 deletions
diff --git a/src/net/fwd.hpp b/src/net/fwd.hpp index 2097772..5de8450 100644 --- a/src/net/fwd.hpp +++ b/src/net/fwd.hpp @@ -20,6 +20,13 @@ #include "../sanity.hpp" +#include "../ints/fwd.hpp" // rank 1 +#include "../strings/fwd.hpp" // rank 1 +#include "../compat/fwd.hpp" // rank 2 +#include "../generic/fwd.hpp" // rank 3 +#include "../io/fwd.hpp" // rank 4 +// net/fwd.hpp is rank 5 + namespace tmwa { @@ -28,6 +35,4 @@ class Session; class IP4Address; class TimerData; - -enum class RecvResult; } // namespace tmwa diff --git a/src/net/ip.cpp b/src/net/ip.cpp index bfc2028..bedbca8 100644 --- a/src/net/ip.cpp +++ b/src/net/ip.cpp @@ -22,15 +22,14 @@ #include "../strings/vstring.hpp" #include "../io/cxxstdio.hpp" - -#include "../mmo/extract.hpp" +#include "../io/extract.hpp" #include "../poison.hpp" namespace tmwa { -bool extract(XString str, IP4Address *rv) +bool impl_extract(XString str, IP4Address *rv) { if (str.endswith('.')) return false; @@ -43,7 +42,7 @@ bool extract(XString str, IP4Address *rv) return false; } -bool extract(XString str, IP4Mask *rv) +bool impl_extract(XString str, IP4Mask *rv) { IP4Address a, m; unsigned b; @@ -106,6 +105,33 @@ bool extract(XString str, IP4Mask *rv) return true; } +bool impl_extract(XString str, std::vector<IP4Mask> *iv) +{ + if (str == "all"_s) + { + iv->clear(); + iv->push_back(IP4Mask()); + return true; + } + if (str == "clear"_s) + { + iv->clear(); + return true; + } + // don't add if already 'all' + if (iv->size() == 1 && iv->front().mask() == IP4Address()) + { + return true; + } + IP4Mask mask; + if (extract(str, &mask)) + { + iv->push_back(mask); + return true; + } + return false; +} + VString<15> convert_for_printf(IP4Address a_) { const uint8_t *a = a_.bytes(); diff --git a/src/net/ip.hpp b/src/net/ip.hpp index e9e71f4..7508c08 100644 --- a/src/net/ip.hpp +++ b/src/net/ip.hpp @@ -25,7 +25,7 @@ #include <cstddef> #include <cstdint> -#include "../strings/fwd.hpp" +#include <vector> namespace tmwa @@ -160,7 +160,7 @@ 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); +bool impl_extract(XString str, IP4Address *iv); +bool impl_extract(XString str, IP4Mask *iv); +bool impl_extract(XString str, std::vector<IP4Mask> *iv); } // namespace tmwa diff --git a/src/net/ip_test.cpp b/src/net/ip_test.cpp index 419dc03..2b9bcad 100644 --- a/src/net/ip_test.cpp +++ b/src/net/ip_test.cpp @@ -24,6 +24,7 @@ #include "../strings/literal.hpp" #include "../io/cxxstdio.hpp" +#include "../io/extract.hpp" #include "../poison.hpp" diff --git a/src/net/packets.cpp b/src/net/packets.cpp deleted file mode 100644 index 3cba856..0000000 --- a/src/net/packets.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include "packets.hpp" -// packets.cpp - palatable socket buffer accessors -// -// Copyright © 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 "../io/cxxstdio.hpp" -#include "../io/write.hpp" - -#include "../poison.hpp" - - -namespace tmwa -{ -size_t packet_avail(Session *s) -{ - return s->rdata_size - s->rdata_pos; -} - -bool packet_fetch(Session *s, size_t offset, Byte *data, size_t sz) -{ - if (packet_avail(s) < offset + sz) - return false; - const Byte *start = reinterpret_cast<const Byte *>(&s->rdata[s->rdata_pos + offset]); - const Byte *end = start + sz; - std::copy(start, end, data); - return true; -} -void packet_discard(Session *s, size_t sz) -{ - s->rdata_pos += sz; - - assert (s->rdata_size >= s->rdata_pos); -} -bool packet_send(Session *s, const Byte *data, size_t sz) -{ - if (s->wdata_size + sz > 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->max_wdata || !s->wdata) - { - return false; - } - s->wdata_size += sz; - - Byte *end = reinterpret_cast<Byte *>(&s->wdata[s->wdata_size + 0]); - Byte *start = end - sz; - std::copy(data, data + sz, start); - return true; -} - -void packet_dump(io::WriteFile& logfp, Session *s) -{ - FPRINTF(logfp, - "---- 00-01-02-03-04-05-06-07 08-09-0A-0B-0C-0D-0E-0F\n"_fmt); - char tmpstr[16 + 1] {}; - int i; - for (i = 0; i < packet_avail(s); i++) - { - if ((i & 15) == 0) - FPRINTF(logfp, "%04X "_fmt, i); - Byte rfifob_ib; - packet_fetch(s, i, &rfifob_ib, 1); - uint8_t rfifob_i = rfifob_ib.value; - FPRINTF(logfp, "%02x "_fmt, rfifob_i); - if (rfifob_i > 0x1f) - tmpstr[i % 16] = rfifob_i; - else - tmpstr[i % 16] = '.'; - if ((i - 7) % 16 == 0) // -8 + 1 - FPRINTF(logfp, " "_fmt); - else if ((i + 1) % 16 == 0) - { - FPRINTF(logfp, " %s\n"_fmt, tmpstr); - std::fill(tmpstr + 0, tmpstr + 17, '\0'); - } - } - if (i % 16 != 0) - { - for (int j = i; j % 16 != 0; j++) - { - FPRINTF(logfp, " "_fmt); - if ((j - 7) % 16 == 0) // -8 + 1 - FPRINTF(logfp, " "_fmt); - } - FPRINTF(logfp, " %s\n"_fmt, tmpstr); - } - FPRINTF(logfp, "\n"_fmt); -} -} // namespace tmwa diff --git a/src/net/packets.hpp b/src/net/packets.hpp deleted file mode 100644 index 5cc377c..0000000 --- a/src/net/packets.hpp +++ /dev/null @@ -1,585 +0,0 @@ -#pragma once -// packets.hpp - palatable socket buffer accessors -// -// Copyright © 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 <vector> - -#include "../compat/cast.hpp" - -#include "../ints/little.hpp" - -#include "../io/fwd.hpp" - -// TODO ordering violation, should invert -#include "../proto2/fwd.hpp" - -#include "socket.hpp" - - -namespace tmwa -{ -struct Buffer -{ - std::vector<Byte> bytes; -}; - -enum class RecvResult -{ - Incomplete, - Complete, - Error, -}; - -enum class SendResult -{ - Success, - Fail, -}; - - -size_t packet_avail(Session *s); -void packet_dump(io::WriteFile& out, Session *s); - -bool packet_fetch(Session *s, size_t offset, Byte *data, size_t sz); -void packet_discard(Session *s, size_t sz); -bool packet_send(Session *s, const Byte *data, size_t sz); - -inline -bool packet_peek_id(Session *s, uint16_t *packet_id) -{ - Little16 id; - bool okay = packet_fetch(s, 0, reinterpret_cast<Byte *>(&id), 2); - if (okay) - { - if (!network_to_native(packet_id, id)) - { - s->set_eof(); - return false; - } - } - return okay; -} - -inline -void send_buffer(Session *s, const Buffer& buffer) -{ - bool ok = !buffer.bytes.empty() && packet_send(s, buffer.bytes.data(), buffer.bytes.size()); - if (!ok) - s->set_eof(); -} - -template<uint16_t id> -__attribute__((warn_unused_result)) -RecvResult net_recv_fpacket(Session *s, NetPacket_Fixed<id>& fixed) -{ - bool ok = packet_fetch(s, 0, reinterpret_cast<Byte *>(&fixed), sizeof(NetPacket_Fixed<id>)); - if (ok) - { - packet_discard(s, sizeof(NetPacket_Fixed<id>)); - return RecvResult::Complete; - } - return RecvResult::Incomplete; -} - -template<uint16_t id> -__attribute__((warn_unused_result)) -RecvResult net_recv_ppacket(Session *s, NetPacket_Payload<id>& payload) -{ - bool ok = packet_fetch(s, 0, reinterpret_cast<Byte *>(&payload), sizeof(NetPacket_Payload<id>)); - if (ok) - { - packet_discard(s, sizeof(NetPacket_Payload<id>)); - return RecvResult::Complete; - } - return RecvResult::Incomplete; -} - -template<uint16_t id> -__attribute__((warn_unused_result)) -RecvResult net_recv_vpacket(Session *s, NetPacket_Head<id>& head, std::vector<NetPacket_Repeat<id>>& repeat) -{ - bool ok = packet_fetch(s, 0, reinterpret_cast<Byte *>(&head), sizeof(NetPacket_Head<id>)); - if (ok) - { - Packet_Head<id> nat; - if (!network_to_native(&nat, head)) - return RecvResult::Error; - if (packet_avail(s) < nat.magic_packet_length) - return RecvResult::Incomplete; - if (nat.magic_packet_length < sizeof(NetPacket_Head<id>)) - return RecvResult::Error; - size_t bytes_repeat = nat.magic_packet_length - sizeof(NetPacket_Head<id>); - if (bytes_repeat % sizeof(NetPacket_Repeat<id>)) - return RecvResult::Error; - repeat.resize(bytes_repeat / sizeof(NetPacket_Repeat<id>)); - if (packet_fetch(s, sizeof(NetPacket_Head<id>), reinterpret_cast<Byte *>(repeat.data()), bytes_repeat)) - { - packet_discard(s, nat.magic_packet_length); - return RecvResult::Complete; - } - return RecvResult::Incomplete; - } - return RecvResult::Incomplete; -} - -template<uint16_t id> -__attribute__((warn_unused_result)) -RecvResult net_recv_opacket(Session *s, NetPacket_Head<id>& head, bool *has_opt, NetPacket_Option<id>& opt) -{ - bool ok = packet_fetch(s, 0, reinterpret_cast<Byte *>(&head), sizeof(NetPacket_Head<id>)); - if (ok) - { - Packet_Head<id> nat; - if (!network_to_native(&nat, head)) - return RecvResult::Error; - if (packet_avail(s) < nat.magic_packet_length) - return RecvResult::Incomplete; - if (nat.magic_packet_length < sizeof(NetPacket_Head<id>)) - return RecvResult::Error; - size_t bytes_repeat = nat.magic_packet_length - sizeof(NetPacket_Head<id>); - if (bytes_repeat % sizeof(NetPacket_Option<id>)) - return RecvResult::Error; - size_t has_opt_pls = bytes_repeat / sizeof(NetPacket_Option<id>); - if (has_opt_pls > 1) - return RecvResult::Error; - *has_opt = has_opt_pls; - if (!*has_opt || packet_fetch(s, sizeof(NetPacket_Head<id>), reinterpret_cast<Byte *>(&opt), sizeof(NetPacket_Option<id>))) - { - packet_discard(s, nat.magic_packet_length); - return RecvResult::Complete; - } - return RecvResult::Incomplete; - } - return RecvResult::Incomplete; -} - - -template<uint16_t id, uint16_t size> -Buffer create_fpacket(const Packet_Fixed<id>& fixed) -{ - static_assert(id == Packet_Fixed<id>::PACKET_ID, "Packet_Fixed<id>::PACKET_ID"); - static_assert(size == sizeof(NetPacket_Fixed<id>), "sizeof(NetPacket_Fixed<id>)"); - - Buffer buf; - buf.bytes.resize(sizeof(NetPacket_Fixed<id>)); - auto& net_fixed = reinterpret_cast<NetPacket_Fixed<id>&>( - *(buf.bytes.begin() + 0)); - if (!native_to_network(&net_fixed, fixed)) - { - return Buffer(); - } - return buf; -} - -template<uint16_t id> -Buffer create_ppacket(Packet_Payload<id>& payload) -{ - static_assert(id == Packet_Payload<id>::PACKET_ID, "Packet_Payload<id>::PACKET_ID"); - - if (id != 0x8000) - payload.magic_packet_length = sizeof(NetPacket_Payload<id>); - - Buffer buf; - buf.bytes.resize(sizeof(NetPacket_Payload<id>)); - auto& net_payload = reinterpret_cast<NetPacket_Payload<id>&>( - *(buf.bytes.begin() + 0)); - if (!native_to_network(&net_payload, payload)) - { - return Buffer(); - } - return buf; -} - -template<uint16_t id, uint16_t headsize, uint16_t repeatsize> -Buffer create_vpacket(Packet_Head<id>& head, const std::vector<Packet_Repeat<id>>& repeat) -{ - static_assert(id == Packet_Head<id>::PACKET_ID, "Packet_Head<id>::PACKET_ID"); - static_assert(headsize == sizeof(NetPacket_Head<id>), "sizeof(NetPacket_Head<id>)"); - static_assert(id == Packet_Repeat<id>::PACKET_ID, "Packet_Repeat<id>::PACKET_ID"); - static_assert(repeatsize == sizeof(NetPacket_Repeat<id>), "sizeof(NetPacket_Repeat<id>)"); - - // since these are already allocated, can't overflow address space - size_t total_size = sizeof(NetPacket_Head<id>) + repeat.size() * sizeof(NetPacket_Repeat<id>); - // truncates - head.magic_packet_length = total_size; - if (head.magic_packet_length != total_size) - { - return Buffer(); - } - - Buffer buf; - buf.bytes.resize(total_size); - auto& net_head = reinterpret_cast<NetPacket_Head<id>&>( - *(buf.bytes.begin() + 0)); - if (!native_to_network(&net_head, head)) - { - return Buffer(); - } - for (size_t i = 0; i < repeat.size(); ++i) - { - auto& net_repeat_i = reinterpret_cast<NetPacket_Repeat<id>&>( - *(buf.bytes.begin() - + sizeof(NetPacket_Head<id>) - + i * sizeof(NetPacket_Repeat<id>))); - if (!native_to_network(&net_repeat_i, repeat[i])) - { - return Buffer(); - } - } - return buf; -} - -template<uint16_t id, uint16_t headsize, uint16_t optsize> -Buffer create_opacket(Packet_Head<id>& head, bool has_opt, const Packet_Option<id>& opt) -{ - static_assert(id == Packet_Head<id>::PACKET_ID, "Packet_Head<id>::PACKET_ID"); - static_assert(headsize == sizeof(NetPacket_Head<id>), "sizeof(NetPacket_Head<id>)"); - static_assert(id == Packet_Option<id>::PACKET_ID, "Packet_Option<id>::PACKET_ID"); - static_assert(optsize == sizeof(NetPacket_Option<id>), "sizeof(NetPacket_Option<id>)"); - - // since these are already allocated, can't overflow address space - size_t total_size = sizeof(NetPacket_Head<id>) + has_opt * sizeof(NetPacket_Option<id>); - // truncates - head.magic_packet_length = total_size; - if (head.magic_packet_length != total_size) - { - return Buffer(); - } - - Buffer buf; - buf.bytes.resize(total_size); - - auto& net_head = reinterpret_cast<NetPacket_Head<id>&>( - *(buf.bytes.begin() + 0)); - if (!native_to_network(&net_head, head)) - { - return Buffer(); - } - if (has_opt) - { - auto& net_opt = reinterpret_cast<NetPacket_Option<id>&>( - *(buf.bytes.begin() - + sizeof(NetPacket_Head<id>))); - if (!native_to_network(&net_opt, opt)) - { - return Buffer(); - } - } - - return buf; -} - -template<uint16_t id, uint16_t size> -void send_fpacket(Session *s, const Packet_Fixed<id>& fixed) -{ - Buffer pkt = create_fpacket<id, size>(fixed); - send_buffer(s, pkt); -} - -template<uint16_t id> -void send_ppacket(Session *s, Packet_Payload<id>& payload) -{ - Buffer pkt = create_ppacket<id>(payload); - send_buffer(s, pkt); -} - -template<uint16_t id, uint16_t headsize, uint16_t repeatsize> -void send_vpacket(Session *s, Packet_Head<id>& head, const std::vector<Packet_Repeat<id>>& repeat) -{ - Buffer pkt = create_vpacket<id, headsize, repeatsize>(head, repeat); - send_buffer(s, pkt); -} - -template<uint16_t id, uint16_t headsize, uint16_t optsize> -void send_opacket(Session *s, Packet_Head<id>& head, bool has_opt, const Packet_Option<id>& opt) -{ - Buffer pkt = create_opacket<id, headsize, optsize>(head, has_opt, opt); - send_buffer(s, pkt); -} - -template<uint16_t id, uint16_t size> -__attribute__((warn_unused_result)) -RecvResult recv_fpacket(Session *s, Packet_Fixed<id>& fixed) -{ - static_assert(id == Packet_Fixed<id>::PACKET_ID, "Packet_Fixed<id>::PACKET_ID"); - static_assert(size == sizeof(NetPacket_Fixed<id>), "NetPacket_Fixed<id>"); - - NetPacket_Fixed<id> net_fixed; - RecvResult rv = net_recv_fpacket(s, net_fixed); - if (rv == RecvResult::Complete) - { - if (!network_to_native(&fixed, net_fixed)) - return RecvResult::Error; - assert (fixed.magic_packet_id == Packet_Fixed<id>::PACKET_ID); - } - return rv; -} - -template<uint16_t id> -__attribute__((warn_unused_result)) -RecvResult recv_ppacket(Session *s, Packet_Payload<id>& payload) -{ - static_assert(id == Packet_Payload<id>::PACKET_ID, "Packet_Payload<id>::PACKET_ID"); - - NetPacket_Payload<id> net_payload; - RecvResult rv = net_recv_ppacket(s, net_payload); - if (rv == RecvResult::Complete) - { - if (!network_to_native(&payload, net_payload)) - return RecvResult::Error; - assert (payload.magic_packet_id == Packet_Payload<id>::PACKET_ID); - if (id == 0x8000) - { - // 0x8000 is special - if (packet_avail(s) < payload.magic_packet_length) - return RecvResult::Incomplete; - payload.magic_packet_length = 4; - return RecvResult::Complete; - } - if (payload.magic_packet_length != sizeof(net_payload)) - return RecvResult::Error; - } - return rv; -} - -template<uint16_t id, uint16_t headsize, uint16_t repeatsize> -__attribute__((warn_unused_result)) -RecvResult recv_vpacket(Session *s, Packet_Head<id>& head, std::vector<Packet_Repeat<id>>& repeat) -{ - static_assert(id == Packet_Head<id>::PACKET_ID, "Packet_Head<id>::PACKET_ID"); - static_assert(headsize == sizeof(NetPacket_Head<id>), "NetPacket_Head<id>"); - static_assert(id == Packet_Repeat<id>::PACKET_ID, "Packet_Repeat<id>::PACKET_ID"); - static_assert(repeatsize == sizeof(NetPacket_Repeat<id>), "NetPacket_Repeat<id>"); - - NetPacket_Head<id> net_head; - std::vector<NetPacket_Repeat<id>> net_repeat; - RecvResult rv = net_recv_vpacket(s, net_head, net_repeat); - if (rv == RecvResult::Complete) - { - if (!network_to_native(&head, net_head)) - return RecvResult::Error; - assert (head.magic_packet_id == Packet_Head<id>::PACKET_ID); - - repeat.resize(net_repeat.size()); - for (size_t i = 0; i < net_repeat.size(); ++i) - { - if (!network_to_native(&repeat[i], net_repeat[i])) - return RecvResult::Error; - } - } - return rv; -} - -template<uint16_t id, uint16_t headsize, uint16_t optsize> -__attribute__((warn_unused_result)) -RecvResult recv_opacket(Session *s, Packet_Head<id>& head, bool *has_opt, Packet_Option<id>& opt) -{ - static_assert(id == Packet_Head<id>::PACKET_ID, "Packet_Head<id>::PACKET_ID"); - static_assert(headsize == sizeof(NetPacket_Head<id>), "NetPacket_Head<id>"); - static_assert(id == Packet_Option<id>::PACKET_ID, "Packet_Option<id>::PACKET_ID"); - static_assert(optsize == sizeof(NetPacket_Option<id>), "NetPacket_Option<id>"); - - NetPacket_Head<id> net_head; - NetPacket_Option<id> net_opt; - RecvResult rv = net_recv_opacket(s, net_head, has_opt, net_opt); - if (rv == RecvResult::Complete) - { - if (!network_to_native(&head, net_head)) - return RecvResult::Error; - assert (head.magic_packet_id == Packet_Head<id>::PACKET_ID); - - if (*has_opt) - { - if (!network_to_native(&opt, net_opt)) - return RecvResult::Error; - } - } - return rv; -} - - -// convenience for trailing strings - -template<uint16_t id, uint16_t headsize, uint16_t repeatsize> -Buffer create_vpacket(Packet_Head<id>& head, const XString& repeat) -{ - static_assert(id == Packet_Head<id>::PACKET_ID, "Packet_Head<id>::PACKET_ID"); - static_assert(headsize == sizeof(NetPacket_Head<id>), "NetPacket_Head<id>"); - static_assert(id == Packet_Repeat<id>::PACKET_ID, "Packet_Repeat<id>::PACKET_ID"); - static_assert(repeatsize == sizeof(NetPacket_Repeat<id>), "NetPacket_Repeat<id>"); - static_assert(repeatsize == 1, "repeatsize"); - - // since it's already allocated, it can't overflow address space - size_t total_length = sizeof(NetPacket_Head<id>) + (repeat.size() + 1) * sizeof(NetPacket_Repeat<id>); - head.magic_packet_length = total_length; - if (head.magic_packet_length != total_length) - { - return Buffer(); - } - - Buffer buf; - buf.bytes.resize(total_length); - auto& net_head = reinterpret_cast<NetPacket_Head<id>&>( - *(buf.bytes.begin() + 0)); - std::vector<NetPacket_Repeat<id>> net_repeat(repeat.size() + 1); - if (!native_to_network(&net_head, head)) - { - return Buffer(); - } - for (size_t i = 0; i < repeat.size(); ++i) - { - auto& net_repeat_i = reinterpret_cast<NetPacket_Repeat<id>&>( - *(buf.bytes.begin() - + sizeof(NetPacket_Head<id>) - + i)); - net_repeat_i.c = Byte{static_cast<uint8_t>(repeat[i])}; - } - auto& net_repeat_repeat_size = reinterpret_cast<NetPacket_Repeat<id>&>( - *(buf.bytes.begin() - + sizeof(NetPacket_Head<id>) - + repeat.size())); - net_repeat_repeat_size.c = Byte{static_cast<uint8_t>('\0')}; - return buf; -} - -template<uint16_t id, uint16_t headsize, uint16_t repeatsize> -void send_vpacket(Session *s, Packet_Head<id>& head, const XString& repeat) -{ - Buffer pkt = create_vpacket<id, headsize, repeatsize>(head, repeat); - send_buffer(s, pkt); -} - -template<uint16_t id, uint16_t headsize, uint16_t repeatsize> -__attribute__((warn_unused_result)) -RecvResult recv_vpacket(Session *s, Packet_Head<id>& head, AString& repeat) -{ - static_assert(id == Packet_Head<id>::PACKET_ID, "Packet_Head<id>::PACKET_ID"); - static_assert(headsize == sizeof(NetPacket_Head<id>), "NetPacket_Head<id>"); - static_assert(id == Packet_Repeat<id>::PACKET_ID, "Packet_Repeat<id>::PACKET_ID"); - static_assert(repeatsize == sizeof(NetPacket_Repeat<id>), "NetPacket_Repeat<id>"); - static_assert(repeatsize == 1, "repeatsize"); - - NetPacket_Head<id> net_head; - std::vector<NetPacket_Repeat<id>> net_repeat; - RecvResult rv = net_recv_vpacket(s, net_head, net_repeat); - assert (head.magic_packet_id == Packet_Head<id>::PACKET_ID); - if (rv == RecvResult::Complete) - { - if (!network_to_native(&head, net_head)) - return RecvResult::Error; - // reinterpret_cast is needed to correctly handle an empty vector - const char *begin = sign_cast<const char *>(net_repeat.data()); - const char *end = begin + net_repeat.size(); - end = std::find(begin, end, '\0'); - repeat = XString(begin, end, nullptr); - } - return rv; -} - - -// if there is nothing in the head but the id and length, use the below - -template<uint16_t id, uint16_t headsize, uint16_t repeatsize> -Buffer create_packet_repeatonly(const std::vector<Packet_Repeat<id>>& v) -{ - static_assert(id == Packet_Head<id>::PACKET_ID, "Packet_Head<id>::PACKET_ID"); - static_assert(headsize == sizeof(NetPacket_Head<id>), "repeat headsize"); - static_assert(headsize == 4, "repeat headsize"); - static_assert(id == Packet_Repeat<id>::PACKET_ID, "Packet_Repeat<id>::PACKET_ID"); - static_assert(repeatsize == sizeof(NetPacket_Repeat<id>), "sizeof(NetPacket_Repeat<id>)"); - - Packet_Head<id> head; - return create_vpacket<id, 4, repeatsize>(head, v); -} - -template<uint16_t id, uint16_t headsize, uint16_t repeatsize> -void send_packet_repeatonly(Session *s, const std::vector<Packet_Repeat<id>>& v) -{ - static_assert(id == Packet_Head<id>::PACKET_ID, "Packet_Head<id>::PACKET_ID"); - static_assert(headsize == sizeof(NetPacket_Head<id>), "repeat headsize"); - static_assert(headsize == 4, "repeat headsize"); - static_assert(id == Packet_Repeat<id>::PACKET_ID, "Packet_Repeat<id>::PACKET_ID"); - static_assert(repeatsize == sizeof(NetPacket_Repeat<id>), "sizeof(NetPacket_Repeat<id>)"); - - Packet_Head<id> head; - send_vpacket<id, 4, repeatsize>(s, head, v); -} - -template<uint16_t id, uint16_t headsize, uint16_t repeatsize> -__attribute__((warn_unused_result)) -RecvResult recv_packet_repeatonly(Session *s, std::vector<Packet_Repeat<id>>& v) -{ - static_assert(id == Packet_Head<id>::PACKET_ID, "Packet_Head<id>::PACKET_ID"); - static_assert(headsize == sizeof(NetPacket_Head<id>), "repeat headsize"); - static_assert(headsize == 4, "repeat headsize"); - static_assert(id == Packet_Repeat<id>::PACKET_ID, "Packet_Repeat<id>::PACKET_ID"); - static_assert(repeatsize == sizeof(NetPacket_Repeat<id>), "sizeof(NetPacket_Repeat<id>)"); - - Packet_Head<id> head; - return recv_vpacket<id, 4, repeatsize>(s, head, v); -} - - -// and the combination of both of the above - -template<uint16_t id, uint16_t headsize, uint16_t repeatsize> -Buffer create_packet_repeatonly(const XString& repeat) -{ - static_assert(id == Packet_Head<id>::PACKET_ID, "Packet_Head<id>::PACKET_ID"); - static_assert(headsize == sizeof(NetPacket_Head<id>), "repeat headsize"); - static_assert(headsize == 4, "repeat headsize"); - static_assert(id == Packet_Repeat<id>::PACKET_ID, "Packet_Repeat<id>::PACKET_ID"); - static_assert(repeatsize == sizeof(NetPacket_Repeat<id>), "sizeof(NetPacket_Repeat<id>)"); - static_assert(repeatsize == 1, "repeatsize"); - - Packet_Head<id> head; - return create_vpacket<id, 4, repeatsize>(head, repeat); -} - -template<uint16_t id, uint16_t headsize, uint16_t repeatsize> -void send_packet_repeatonly(Session *s, const XString& repeat) -{ - static_assert(id == Packet_Head<id>::PACKET_ID, "Packet_Head<id>::PACKET_ID"); - static_assert(headsize == sizeof(NetPacket_Head<id>), "repeat headsize"); - static_assert(headsize == 4, "repeat headsize"); - static_assert(id == Packet_Repeat<id>::PACKET_ID, "Packet_Repeat<id>::PACKET_ID"); - static_assert(repeatsize == sizeof(NetPacket_Repeat<id>), "sizeof(NetPacket_Repeat<id>)"); - static_assert(repeatsize == 1, "repeatsize"); - - Packet_Head<id> head; - send_vpacket<id, 4, repeatsize>(s, head, repeat); -} - -template<uint16_t id, uint16_t headsize, uint16_t repeatsize> -__attribute__((warn_unused_result)) -RecvResult recv_packet_repeatonly(Session *s, AString& repeat) -{ - static_assert(id == Packet_Head<id>::PACKET_ID, "Packet_Head<id>::PACKET_ID"); - static_assert(headsize == sizeof(NetPacket_Head<id>), "repeat headsize"); - static_assert(headsize == 4, "repeat headsize"); - static_assert(id == Packet_Repeat<id>::PACKET_ID, "Packet_Repeat<id>::PACKET_ID"); - static_assert(repeatsize == sizeof(NetPacket_Repeat<id>), "sizeof(NetPacket_Repeat<id>)"); - static_assert(repeatsize == 1, "repeatsize"); - - Packet_Head<id> head; - return recv_vpacket<id, 4, repeatsize>(s, head, repeat); -} -} // namespace tmwa diff --git a/src/net/socket.cpp b/src/net/socket.cpp index a01cd81..fce45fb 100644 --- a/src/net/socket.cpp +++ b/src/net/socket.cpp @@ -34,10 +34,6 @@ #include "../io/cxxstdio.hpp" -// TODO get rid of ordering violations -#include "../mmo/utils.hpp" -#include "../mmo/core.hpp" - #include "timer.hpp" #include "../poison.hpp" @@ -399,7 +395,7 @@ void realloc_fifo(Session *s, size_t rfifo_size, size_t wfifo_size) } } -void do_sendrecv(interval_t next_ms) +bool do_sendrecv(interval_t next_ms) { bool any = false; io::FD_Set rfd = readfds, wfd; @@ -419,9 +415,9 @@ void do_sendrecv(interval_t next_ms) { PRINTF("Shutting down - nothing to do\n"_fmt); // TODO hoist this - runflag = false; + return false; } - return; + return true; } struct timeval timeout; { @@ -431,7 +427,7 @@ void do_sendrecv(interval_t next_ms) timeout.tv_usec = next_us.count(); } if (io::FD_Set::select(fd_max, &rfd, &wfd, nullptr, &timeout) <= 0) - return; + return true; for (io::FD i : iter_fds()) { Session *s = get_session(i); @@ -451,9 +447,10 @@ void do_sendrecv(interval_t next_ms) s->func_recv(s); } } + return true; } -void do_parsepacket(void) +bool do_parsepacket(void) { for (io::FD i : iter_fds()) { @@ -483,5 +480,6 @@ void do_parsepacket(void) /// Reclaim buffer space for what was read RFIFOFLUSH(s); } + return true; } } // namespace tmwa diff --git a/src/net/socket.hpp b/src/net/socket.hpp index 576ef85..d6caefd 100644 --- a/src/net/socket.hpp +++ b/src/net/socket.hpp @@ -22,20 +22,19 @@ #include "fwd.hpp" -#include <algorithm> - #include <sys/select.h> +#include <algorithm> #include <memory> -#include "../compat/iter.hpp" -#include "../compat/rawmem.hpp" -#include "../compat/time_t.hpp" - #include "../strings/astring.hpp" #include "../strings/vstring.hpp" #include "../strings/xstring.hpp" +#include "../compat/iter.hpp" +#include "../compat/rawmem.hpp" +#include "../compat/time_t.hpp" + #include "../generic/dumb_ptr.hpp" #include "../io/fd.hpp" @@ -125,8 +124,8 @@ public: io::FD fd; - friend void do_sendrecv(interval_t next); - friend void do_parsepacket(void); + friend bool do_sendrecv(interval_t next); + friend bool do_parsepacket(void); friend void delete_session(Session *); }; @@ -171,7 +170,7 @@ 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); +bool do_sendrecv(interval_t next); /// Call the parser function for every socket that has read data -void do_parsepacket(void); +bool do_parsepacket(void); } // namespace tmwa diff --git a/src/net/timer.hpp b/src/net/timer.hpp index 338e339..5e7cc90 100644 --- a/src/net/timer.hpp +++ b/src/net/timer.hpp @@ -21,11 +21,8 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. #include "timer.t.hpp" - #include "fwd.hpp" -#include "../strings/fwd.hpp" - namespace tmwa { diff --git a/src/net/timer.py b/src/net/timer.py new file mode 100644 index 0000000..2ccb3bb --- /dev/null +++ b/src/net/timer.py @@ -0,0 +1,117 @@ +class duration(object): + __slots__ = ('_whole', '_frac', '_units') + name = 'std::chrono::duration' + enabled = True + + def __init__(self, value): + from decimal import Decimal + + rep = int(value['__r']) + ratio = value.type.template_argument(1) + num = int(ratio.template_argument(0)) + den = int(ratio.template_argument(1)) + # this will fail on duration<float> + value = Decimal(rep) * num / den + whole = int(value) + self._whole = whole + self._frac = value - whole + units = { + (1, 1000*1000*1000): ('nanoseconds', '_ns'), + (1, 1000*1000): ('microseconds', '_us'), + (1, 1000): ('milliseconds', '_ms'), + (1, 1): ('seconds', '_s'), + (60, 1): ('minutes', '_min'), + (60*60, 1): ('hours', '_h'), + (24*60*60, 1): ('duration<int, ratio<%d, %d>>', '_d'), + # days don't exist (probably because of leap seconds) + } + self._units = units.get((num, den)) or ('duration<???, ratio<%d, %d>>' % (num, den), '_?') + + def to_string(self): + whole = self._whole + frac = self._frac + cu, su = self._units + if not whole and not frac: + return '0%s' % su + s = whole + min = s // 60 + s %= 60 + h = min // 60 + min %= 60 + d = h // 24 + h %= 24 + msx = frac * 1000 + ms = int(msx) + usx = (msx - ms) * 1000 + us = int(usx) + nsx = (usx - us) * 1000 + ns = int(nsx) + bits = [ + '%d_d' % d if d else None, + '%d_h' % h if h else None, + '%d_min' % min if min else None, + '%d_s' % s if s else None, + '%d_ms' % ms if ms else None, + '%d_us' % us if us else None, + '%d_ns' % ns if ns else None, + ] + body = ' + '.join(b for b in bits if b is not None) + if not body.endswith(su): + body = '%s(%s)' % (cu, body) + elif '+' in body: + body = '(%s)' % body + return body + + tests = [ + ('std::chrono::nanoseconds(0)', '0_ns'), + ('std::chrono::microseconds(0)', '0_us'), + ('std::chrono::milliseconds(0)', '0_ms'), + ('std::chrono::seconds(0)', '0_s'), + ('std::chrono::minutes(0)', '0_min'), + ('std::chrono::hours(0)', '0_h'), + ('std::chrono::duration<int, std::ratio<60*60*24>>(0)', '0_d'), + + ('std::chrono::nanoseconds(1)', '1_ns'), + ('std::chrono::microseconds(1)', '1_us'), + ('std::chrono::milliseconds(1)', '1_ms'), + ('std::chrono::seconds(1)', '1_s'), + ('std::chrono::minutes(1)', '1_min'), + ('std::chrono::hours(1)', '1_h'), + ('std::chrono::duration<int, std::ratio<60*60*24>>(1)', '1_d'), + + ('std::chrono::nanoseconds(1)', '1_ns'), + ('std::chrono::microseconds(1)', '1_us'), + ('std::chrono::milliseconds(1)', '1_ms'), + ('std::chrono::seconds(1)', '1_s'), + ('std::chrono::minutes(1)', '1_min'), + ('std::chrono::hours(1)', '1_h'), + ('std::chrono::duration<int, std::ratio<60*60*24>>(1)', '1_d'), + + ('std::chrono::nanoseconds(3)', '3_ns'), + ('std::chrono::microseconds(3)', '3_us'), + ('std::chrono::milliseconds(3)', '3_ms'), + ('std::chrono::seconds(3)', '3_s'), + ('std::chrono::minutes(3)', '3_min'), + ('std::chrono::hours(3)', '3_h'), + ('std::chrono::duration<int, std::ratio<60*60*24>>(3)', '3_d'), + + ('std::chrono::nanoseconds(1000)', 'nanoseconds(1_us)'), + ('std::chrono::microseconds(1000)', 'microseconds(1_ms)'), + ('std::chrono::milliseconds(1000)', 'milliseconds(1_s)'), + ('std::chrono::seconds(60)', 'seconds(1_min)'), + ('std::chrono::minutes(60)', 'minutes(1_h)'), + ('std::chrono::hours(24)', 'hours(1_d)'), + + ('std::chrono::nanoseconds(1001)', '(1_us + 1_ns)'), + ('std::chrono::microseconds(1001)', '(1_ms + 1_us)'), + ('std::chrono::milliseconds(1001)', '(1_s + 1_ms)'), + ('std::chrono::seconds(61)', '(1_min + 1_s)'), + ('std::chrono::minutes(61)', '(1_h + 1_min)'), + ('std::chrono::hours(25)', '(1_d + 1_h)'), + + ('std::chrono::nanoseconds(1001*1000)', 'nanoseconds(1_ms + 1_us)'), + ('std::chrono::microseconds(1001*1000)', 'microseconds(1_s + 1_ms)'), + ('std::chrono::milliseconds(61*1000)', 'milliseconds(1_min + 1_s)'), + ('std::chrono::seconds(61*60)', 'seconds(1_h + 1_min)'), + ('std::chrono::minutes(25*60)', 'minutes(1_d + 1_h)'), + ] diff --git a/src/net/timestamp-utils.cpp b/src/net/timestamp-utils.cpp new file mode 100644 index 0000000..b5873ca --- /dev/null +++ b/src/net/timestamp-utils.cpp @@ -0,0 +1,72 @@ +#include "timestamp-utils.hpp" +// timestamp-utils.cpp - Useful stuff that hasn't been categorized. +// +// 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/time.h> + +#include <algorithm> + +#include "../strings/xstring.hpp" + +#include "../compat/time_t.hpp" + +#include "../io/write.hpp" + +#include "../poison.hpp" + + +namespace tmwa +{ +static_assert(sizeof(timestamp_seconds_buffer) == 20, "seconds buffer"); +static_assert(sizeof(timestamp_milliseconds_buffer) == 24, "millis buffer"); + +void stamp_time(timestamp_seconds_buffer& out, const TimeT *t) +{ + struct tm when = t ? *t : TimeT::now(); + char buf[20]; + strftime(buf, 20, "%Y-%m-%d %H:%M:%S", &when); + out = stringish<timestamp_seconds_buffer>(VString<19>(strings::really_construct_from_a_pointer, buf)); +} +void stamp_time(timestamp_milliseconds_buffer& out) +{ + struct timeval tv; + gettimeofday(&tv, nullptr); + struct tm when = TimeT(tv.tv_sec); + char buf[24]; + strftime(buf, 20, "%Y-%m-%d %H:%M:%S", &when); + sprintf(buf + 19, ".%03d", static_cast<int>(tv.tv_usec / 1000)); + out = stringish<timestamp_milliseconds_buffer>(VString<23>(strings::really_construct_from_a_pointer, buf)); +} + +void log_with_timestamp(io::WriteFile& out, XString line) +{ + if (!line) + { + out.put('\n'); + return; + } + timestamp_milliseconds_buffer tmpstr; + stamp_time(tmpstr); + out.really_put(tmpstr.data(), tmpstr.size()); + out.really_put(": ", 2); + out.put_line(line); +} +} // namespace tmwa diff --git a/src/net/timestamp-utils.hpp b/src/net/timestamp-utils.hpp new file mode 100644 index 0000000..f5b5dce --- /dev/null +++ b/src/net/timestamp-utils.hpp @@ -0,0 +1,54 @@ +#pragma once +// timestamp-utils.hpp - Useful stuff that hasn't been categorized. +// +// 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 "../strings/vstring.hpp" + + +namespace tmwa +{ +struct timestamp_seconds_buffer : VString<19> {}; +struct timestamp_milliseconds_buffer : VString<23> {}; +void stamp_time(timestamp_seconds_buffer&, const TimeT *t=nullptr); +void stamp_time(timestamp_milliseconds_buffer&); + +void log_with_timestamp(io::WriteFile& out, XString line); + +// TODO VString? +#define TIMESTAMP_DUMMY "YYYY-MM-DD HH:MM:SS" +static_assert(sizeof(TIMESTAMP_DUMMY) == sizeof(timestamp_seconds_buffer), + "timestamp size"); +#define WITH_TIMESTAMP(str) str TIMESTAMP_DUMMY +// str: prefix: YYYY-MM-DD HH:MM:SS +// sizeof: 01234567890123456789012345678 +// str + sizeof: ^ +// -1: ^ +// there's probably a better way to do this now +#define REPLACE_TIMESTAMP(str, t) \ + stamp_time( \ + reinterpret_cast<timestamp_seconds_buffer *>( \ + str + sizeof(str) \ + )[-1], \ + &t \ + ) +} // namespace tmwa |