1 //**************************************************************************
3 //** ## ## ## ## ## #### #### ### ###
4 //** ## ## ## ## ## ## ## ## ## ## #### ####
5 //** ## ## ## ## ## ## ## ## ## ## ## ## ## ##
6 //** ## ## ######## ## ## ## ## ## ## ## ### ##
7 //** ### ## ## ### ## ## ## ## ## ##
8 //** # ## ## # #### #### ## ##
10 //** Copyright (C) 1999-2006 Jānis Legzdiņš
11 //** Copyright (C) 2018-2023 Ketmar Dark
13 //** This program is free software: you can redistribute it and/or modify
14 //** it under the terms of the GNU General Public License as published by
15 //** the Free Software Foundation, version 3 of the License ONLY.
17 //** This program is distributed in the hope that it will be useful,
18 //** but WITHOUT ANY WARRANTY; without even the implied warranty of
19 //** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 //** GNU General Public License for more details.
22 //** You should have received a copy of the GNU General Public License
23 //** along with this program. If not, see <http://www.gnu.org/licenses/>.
25 //**************************************************************************
26 #include "../gamedefs.h"
27 #include "../server/server.h"
28 #include "net_local.h"
31 // ////////////////////////////////////////////////////////////////////////// //
32 struct VLoopbackMessage
{
37 // ////////////////////////////////////////////////////////////////////////// //
38 class VLoopbackSocket
: public VSocket
{
40 VLoopbackSocket
*OtherSock
;
41 TArray
<VLoopbackMessage
> LoopbackMessages
;
44 VLoopbackSocket (VNetDriver
*Drv
) : VSocket(Drv
), OtherSock(nullptr) {}
45 virtual ~VLoopbackSocket () override
;
47 virtual int GetMessage (void *dest
, size_t destSize
) override
;
48 virtual int SendMessage (const vuint8
*, vuint32
) override
;
49 virtual bool IsLocalConnection () const noexcept override
;
53 // ////////////////////////////////////////////////////////////////////////// //
54 class VLoopbackDriver
: public VNetDriver
{
56 bool localconnectpending
;
57 VLoopbackSocket
*loop_client
;
58 VLoopbackSocket
*loop_server
;
63 virtual int Init () override
;
64 virtual void Listen (bool) override
;
65 virtual void SearchForHosts (bool, bool) override
;
66 virtual VSocket
*Connect (const char *) override
;
67 virtual VSocket
*CheckNewConnections (bool rconOnly
) override
;
68 virtual void UpdateMaster () override
;
69 virtual void QuitMaster () override
;
70 virtual bool QueryMaster (bool) override
;
71 virtual void EndQueryMaster () override
;
72 virtual void Shutdown () override
;
74 static int IntAlign (int);
78 static VLoopbackDriver Impl
;
81 //==========================================================================
83 // VLoopbackDriver::VLoopbackDriver
85 //==========================================================================
86 VLoopbackDriver::VLoopbackDriver ()
87 : VNetDriver(0, "Loopback")
88 , localconnectpending(false)
89 , loop_client(nullptr)
90 , loop_server(nullptr)
95 //==========================================================================
97 // VLoopbackDriver::Init
99 //==========================================================================
100 int VLoopbackDriver::Init () {
102 if (GGameInfo
&& GGameInfo
->NetMode
== NM_DedicatedServer
) return -1;
110 //==========================================================================
112 // VLoopbackDriver::Listen
114 //==========================================================================
115 void VLoopbackDriver::Listen (bool) {
119 //==========================================================================
121 // VLoopbackDriver::SearchForHosts
123 //==========================================================================
124 void VLoopbackDriver::SearchForHosts (bool, bool ForMaster
) {
126 if (GGameInfo
->NetMode
== NM_None
|| GGameInfo
->NetMode
== NM_Client
|| ForMaster
) return;
127 Net
->HostCacheCount
= 1;
128 if (VStr::Cmp(Net
->HostName
, "UNNAMED") == 0) {
129 Net
->HostCache
[0].Name
= "local";
131 Net
->HostCache
[0].Name
= Net
->HostName
;
133 Net
->HostCache
[0].Map
= VStr(GLevel
->MapName
);
134 Net
->HostCache
[0].Users
= svs
.num_connected
;
135 Net
->HostCache
[0].MaxUsers
= svs
.max_clients
;
136 Net
->HostCache
[0].CName
= "local";
141 //==========================================================================
143 // VLoopbackDriver::Connect
145 //==========================================================================
146 VSocket
*VLoopbackDriver::Connect (const char *host
) {
147 if (VStr::Cmp(host
, "local") != 0) return nullptr;
149 localconnectpending
= true;
152 loop_client
= new VLoopbackSocket(this);
153 loop_client
->Address
= "localhost";
157 loop_server
= new VLoopbackSocket(this);
158 loop_server
->Address
= "LOCAL";
161 vuint8 origkey
[VNetUtils::ChaCha20KeySize
];
162 VNetUtils::GenerateKey(origkey
);
164 memcpy(loop_client
->AuthKey
, origkey
, VNetUtils::ChaCha20KeySize
);
165 memcpy(loop_client
->ClientKey
, origkey
, VNetUtils::ChaCha20KeySize
);
166 memcpy(loop_server
->AuthKey
, origkey
, VNetUtils::ChaCha20KeySize
);
167 memcpy(loop_server
->ClientKey
, origkey
, VNetUtils::ChaCha20KeySize
);
169 loop_client
->OtherSock
= loop_server
;
170 loop_server
->OtherSock
= loop_client
;
176 //==========================================================================
178 // VLoopbackDriver::CheckNewConnections
180 //==========================================================================
181 VSocket
*VLoopbackDriver::CheckNewConnections (bool rconOnly
) {
182 if (rconOnly
) return nullptr;
183 if (!localconnectpending
) return nullptr;
184 localconnectpending
= false;
189 //==========================================================================
191 // VLoopbackDriver::IntAlign
193 //==========================================================================
194 int VLoopbackDriver::IntAlign (int value
) {
195 return (value
+(sizeof(int)-1))&(~(sizeof(int)-1));
199 //==========================================================================
201 // VLoopbackDriver::UpdateMaster
203 //==========================================================================
204 void VLoopbackDriver::UpdateMaster () {
208 //==========================================================================
210 // VLoopbackDriver::QuitMaster
212 //==========================================================================
213 void VLoopbackDriver::QuitMaster () {
217 //==========================================================================
219 // VLoopbackDriver::QueryMaster
221 //==========================================================================
222 bool VLoopbackDriver::QueryMaster (bool) {
227 //==========================================================================
229 // VLoopbackDriver::EndQueryMaster
231 //==========================================================================
232 void VLoopbackDriver::EndQueryMaster () {
236 //==========================================================================
238 // VLoopbackDriver::Shutdown
240 //==========================================================================
241 void VLoopbackDriver::Shutdown () {
245 //==========================================================================
247 // VLoopbackSocket::~VLoopbackSocket
249 //==========================================================================
250 VLoopbackSocket::~VLoopbackSocket () {
251 if (OtherSock
) OtherSock
->OtherSock
= nullptr;
252 if (this == ((VLoopbackDriver
*)Driver
)->loop_client
) {
253 ((VLoopbackDriver
*)Driver
)->loop_client
= nullptr;
255 ((VLoopbackDriver
*)Driver
)->loop_server
= nullptr;
260 //==========================================================================
262 // VLoopbackSocket::GetMessage
264 //==========================================================================
265 int VLoopbackSocket::GetMessage (void *dest
, size_t destSize
) {
266 if (!LoopbackMessages
.length()) return 0;
267 int res
= LoopbackMessages
[0].Data
.length();
268 if (res
> (int)destSize
) return -1;
269 if (res
) memcpy(dest
, LoopbackMessages
[0].Data
.ptr(), res
);
270 LoopbackMessages
.RemoveIndex(0);
275 //==========================================================================
277 // VLoopbackSocket::SendMessage
279 // Send a packet over the net connection.
280 // returns 1 if the packet was sent properly
281 // returns -1 if the connection died
283 //==========================================================================
284 int VLoopbackSocket::SendMessage (const vuint8
*Data
, vuint32 Length
) {
285 if (!OtherSock
) return -1;
286 VLoopbackMessage
&Msg
= OtherSock
->LoopbackMessages
.Alloc();
287 Msg
.Data
.setLength(Length
);
288 if (Length
) memcpy(Msg
.Data
.Ptr(), Data
, Length
);
293 //==========================================================================
295 // VLoopbackSocket::IsLocalConnection
297 //==========================================================================
298 bool VLoopbackSocket::IsLocalConnection () const noexcept
{