| 1 | /* |
| 2 | * LegacyClonk |
| 3 | * |
| 4 | * Copyright (c) 2016-2017, The OpenClonk Team and contributors |
| 5 | * Copyright (c) 2019-2020, The LegacyClonk Team and contributors |
| 6 | * |
| 7 | * Distributed under the terms of the ISC license; see accompanying file |
| 8 | * "COPYING" for details. |
| 9 | * |
| 10 | * "Clonk" is a registered trademark of Matthes Bender, used with permission. |
| 11 | * See accompanying file "TRADEMARK" for details. |
| 12 | * |
| 13 | * To redistribute this file separately, substitute the full license texts |
| 14 | * for the above references. |
| 15 | */ |
| 16 | |
| 17 | #include "C4Include.h" |
| 18 | #include "C4PuncherPacket.h" |
| 19 | |
| 20 | #include "C4Network2Address.h" |
| 21 | #include "StdAdaptors.h" |
| 22 | |
| 23 | #include <stdexcept> |
| 24 | |
| 25 | static constexpr char C4NetpuncherProtocolVersion{1}; |
| 26 | // Netpuncher packet header: (1 byte type "Status"), 1 byte version |
| 27 | static constexpr std::size_t {2}, {1}; |
| 28 | |
| 29 | void C4NetpuncherID::CompileFunc(StdCompiler *const comp) |
| 30 | { |
| 31 | comp->Value(rStruct: mkNamingAdapt(rValue&: v4, szName: "IPv4" , rDefault: 0u)); |
| 32 | comp->Value(rStruct: mkNamingAdapt(rValue&: v6, szName: "IPv6" , rDefault: 0u)); |
| 33 | } |
| 34 | |
| 35 | auto C4NetpuncherPacket::Construct(const C4NetIOPacket &pkt) -> uptr |
| 36 | { |
| 37 | if (!pkt.getPData() || *pkt.getPData() != C4NetpuncherProtocolVersion) return nullptr; |
| 38 | try |
| 39 | { |
| 40 | switch (pkt.getStatus()) |
| 41 | { |
| 42 | case PID_Puncher_AssID: return uptr{new C4NetpuncherPacketAssID{pkt}}; |
| 43 | case PID_Puncher_SReq: return uptr{new C4NetpuncherPacketSReq{pkt}}; |
| 44 | case PID_Puncher_CReq: return uptr{new C4NetpuncherPacketCReq{pkt}}; |
| 45 | case PID_Puncher_IDReq: return uptr{new C4NetpuncherPacketIDReq{pkt}}; |
| 46 | default: return nullptr; |
| 47 | } |
| 48 | } |
| 49 | catch (const StdCompiler::Exception &) |
| 50 | { |
| 51 | return nullptr; |
| 52 | } |
| 53 | catch (const std::runtime_error &) |
| 54 | { |
| 55 | return nullptr; |
| 56 | } |
| 57 | } |
| 58 | |
| 59 | C4NetIOPacket C4NetpuncherPacket::PackTo(const C4NetIO::addr_t &addr) const |
| 60 | { |
| 61 | C4NetIOPacket pkt; |
| 62 | pkt.SetAddr(addr); |
| 63 | StdBuf content{PackInto()}; |
| 64 | const auto &type = GetType(); |
| 65 | pkt.New(inSize: sizeof(type) + sizeof(C4NetpuncherProtocolVersion) + content.getSize()); |
| 66 | std::size_t offset{0}; |
| 67 | pkt.Write(pnData: &type, inSize: sizeof(type), iAt: offset); |
| 68 | offset += sizeof(type); |
| 69 | pkt.Write(pnData: &C4NetpuncherProtocolVersion, inSize: sizeof(C4NetpuncherProtocolVersion), iAt: offset); |
| 70 | offset += sizeof(C4NetpuncherProtocolVersion); |
| 71 | pkt.Write(Buf2: content, iAt: offset); |
| 72 | return pkt; |
| 73 | } |
| 74 | |
| 75 | C4NetpuncherPacketCReq::C4NetpuncherPacketCReq(const C4NetIOPacket &pkt) |
| 76 | { |
| 77 | if (pkt.getPSize() < HeaderPSize + 2 + 16) throw std::runtime_error{"invalid size" }; |
| 78 | const std::uint16_t port{*pkt.getPtr<std::uint16_t>(pos: HeaderSize)}; |
| 79 | addr.SetAddress(addr: C4NetIO::addr_t::Any, port); |
| 80 | std::memcpy(dest: &static_cast<sockaddr_in6 *>(&addr)->sin6_addr, src: pkt.getPtr<char>(pos: HeaderSize + sizeof(port)), n: 16); |
| 81 | } |
| 82 | |
| 83 | StdBuf C4NetpuncherPacketCReq::PackInto() const |
| 84 | { |
| 85 | StdBuf buf; |
| 86 | const auto sin6 = static_cast<sockaddr_in6>(addr.AsIPv6()); |
| 87 | const auto port = addr.GetPort(); |
| 88 | buf.New(inSize: sizeof(port) + sizeof(sin6.sin6_addr)); |
| 89 | std::size_t offset{0}; |
| 90 | buf.Write(pnData: &port, inSize: sizeof(port), iAt: offset); |
| 91 | offset += sizeof(port); |
| 92 | buf.Write(pnData: &sin6.sin6_addr, inSize: sizeof(sin6.sin6_addr), iAt: offset); |
| 93 | static_assert(sizeof(sin6.sin6_addr) == 16, "expected sin6_addr to be 16 bytes" ); |
| 94 | return buf; |
| 95 | } |
| 96 | |
| 97 | template<C4NetpuncherPacketType Type> |
| 98 | C4NetpuncherPacketID<Type>::C4NetpuncherPacketID(const C4NetIOPacket &pkt) |
| 99 | { |
| 100 | if (pkt.getPSize() < HeaderPSize + sizeof(id)) throw std::runtime_error{"invalid size" }; |
| 101 | id = *pkt.getPtr<CID>(pos: HeaderSize); |
| 102 | } |
| 103 | |
| 104 | template<C4NetpuncherPacketType Type> |
| 105 | StdBuf C4NetpuncherPacketID<Type>::PackInto() const |
| 106 | { |
| 107 | StdBuf buf; |
| 108 | const auto &id = GetID(); |
| 109 | buf.New(inSize: sizeof(id)); |
| 110 | buf.Write(&id, sizeof(id)); |
| 111 | return buf; |
| 112 | } |
| 113 | |