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 "../psim/p_thinker.h"
29 #include "net_message.h"
31 extern VCvarB net_debug_dump_recv_packets
;
32 static VCvarB
net_debug_rpc("net_debug_rpc", false, "Dump RPC info?", CVAR_NoShadow
);
35 //==========================================================================
39 //==========================================================================
40 VChannel::VChannel (VNetConnection
*AConnection
, EChannelType AType
, vint32 AIndex
, bool AOpenedLocally
)
41 : Connection(AConnection
)
44 , OpenedLocally(AOpenedLocally
)
45 , OpenAcked(AIndex
>= 0 && AIndex
< CHANIDX_ObjectMap
) // those channels are automatically opened
53 , bSentAnyMessages(false)
55 vassert(Index
>= 0 && Index
< MAX_CHANNELS
);
56 vassert(!Connection
->Channels
[Index
]);
57 Connection
->Channels
[Index
] = this;
58 Connection
->OpenChannels
.append(this);
62 //==========================================================================
64 // VChannel::~VChannel
66 //==========================================================================
67 VChannel::~VChannel () {
68 // free outgoung queue
70 VMessageOut
*curr
= OutList
;
74 // free incoming queue
76 VMessageIn
*curr
= InList
;
81 // remove from connection's channel table
82 if (Connection
&& Index
>= 0 && Index
< MAX_CHANNELS
) {
83 vassert(Connection
->Channels
[Index
] == this);
84 Connection
->OpenChannels
.Remove(this);
85 Connection
->Channels
[Index
] = nullptr;
91 //==========================================================================
95 //==========================================================================
96 VStr
VChannel::GetName () const noexcept
{
97 return VStr(va("chan #%d(%s)", Index
, GetTypeName()));
101 //==========================================================================
103 // VChannel::GetDebugName
105 //==========================================================================
106 VStr
VChannel::GetDebugName () const noexcept
{
107 return (Connection
? Connection
->GetAddress() : VStr("<noip>"))+":"+(IsLocalChannel() ? "l:" : "r:")+GetName();
111 //==========================================================================
113 // VChannel::GetLastOutSeq
115 //==========================================================================
116 vuint32
VChannel::GetLastOutSeq () const noexcept
{
117 return (Connection
? Connection
->OutReliable
[Index
] : 0);
121 //==========================================================================
123 // VChannel::IsQueueFull
130 //==========================================================================
131 int VChannel::IsQueueFull () noexcept
{
132 //if (OutListCount >= MAX_RELIABLE_BUFFER-2) return false;
133 //return (OutListBits >= (MAX_RELIABLE_BUFFER-(forClose ? 1 : 2))*MAX_MSG_SIZE_BITS);
136 OutListBits
>= /*(MAX_RELIABLE_BUFFER+13)*MAX_MSG_SIZE_BITS*/14000*8 ? -1 : // oversaturated
137 OutListBits
>= /*MAX_RELIABLE_BUFFER*MAX_MSG_SIZE_BITS*/12000*8 ? 1 : // full
141 OutListCount
>= MAX_RELIABLE_BUFFER
+8 ? -1 : // oversaturated
142 OutListCount
>= MAX_RELIABLE_BUFFER
-1 ? 1 : // full
144 //return (OutListBits >= 33000*8);
148 //==========================================================================
150 // VChannel::CanSendData
152 //==========================================================================
153 bool VChannel::CanSendData () noexcept
{
154 // keep some space for close message
155 if (IsQueueFull()) return false;
156 return (Connection
? /*Connection->CanSendData()*/true : false);
160 //==========================================================================
162 // VChannel::CanSendClose
164 //==========================================================================
165 bool VChannel::CanSendClose () noexcept
{
166 //return !IsQueueFull(true);
167 return true; // always
171 //==========================================================================
173 // VChannel::SetClosing
175 //==========================================================================
176 void VChannel::SetClosing () {
181 //==========================================================================
183 // VChannel::ReceivedCloseAck
185 // this is called from `ReceivedAcks()`
186 // the channel will be automatically closed and destroyed, so don't do it here
188 //==========================================================================
189 void VChannel::ReceivedCloseAck () {
193 //==========================================================================
195 // VChannel::OutMessageAcked
197 // called by `ReceivedAcks()`, strictly in sequence
199 //==========================================================================
200 void VChannel::OutMessageAcked (VMessageOut
&/*Msg*/) {
204 //==========================================================================
208 //==========================================================================
209 void VChannel::Close () {
210 // if this channel is already closing, do nothing
212 // if the connection is dead, simply set the flag and get out
213 if (!Connection
|| Connection
->IsClosed()) {
217 vassert(Connection
->Channels
[Index
] == this);
219 if (net_debug_dump_recv_packets
) GCon
->Logf(NAME_DevNet
, "%s: sending CLOSE %s", *GetDebugName(), (IsLocalChannel() ? "request" : "ack"));
220 // send a close notify, and wait for the ack
221 // we should not have any closing message in the queue (sanity check)
222 for (VMessageOut
*Out
= OutList
; Out
; Out
= Out
->Next
) {
223 if (Out
->bClose
) GCon
->Logf(NAME_DevNet
, "%s: close flag is not set, yet we already have CLOSE message in queue (pid=%u; stime=%g; time=%g)", *GetDebugName(), Out
->PacketId
, Out
->Time
, Sys_Time());
224 vassert(!Out
->bClose
);
227 if (!bSentAnyMessages
&& !OpenAcked
) GCon
->Logf(NAME_DevNet
, "WARNING: trying to close the channel %s that wasn't used for anything!", *GetDebugName());
228 // send closing message
229 SendCloseMessageForced();
230 // WARNING! make sure that `SetClosing()` sets `Closing` first, and then does any cleanup!
231 // failing to do so may cause recursive call to `Close()` (in thinker channel, for example)
233 // closing flag should be set, check it
238 //==========================================================================
240 // VChannel::PacketLost
242 //==========================================================================
243 void VChannel::PacketLost (vuint32 PacketId
) {
244 for (VMessageOut
*Out
= OutList
; Out
; Out
= Out
->Next
) {
245 // retransmit reliable messages in the lost packet
246 if (Out
->PacketId
== PacketId
&& !Out
->bReceivedAck
) {
247 vassert(Out
->bReliable
);
248 Connection
->SendMessage(Out
);
254 //==========================================================================
256 // VChannel::ReceivedAcks
258 //==========================================================================
259 void VChannel::ReceivedAcks () {
260 vassert(Connection
->Channels
[Index
] == this);
263 for (VMessageOut
*Out
= OutList
; Out
&& Out
->Next
; Out
= Out
->Next
) vassert(Out
->Next
->ChanSequence
> Out
->ChanSequence
);
265 // release all acknowledged outgoing queued messages
266 bool doClose
= false;
267 while (OutList
&& OutList
->bReceivedAck
) {
268 doClose
= (doClose
|| OutList
->bClose
);
269 VMessageOut
*curr
= OutList
;
270 OutList
= OutList
->Next
;
271 OutListBits
-= curr
->OutEstimated
;
272 vassert(OutListBits
>= 0);
273 OutMessageAcked(*curr
);
276 vassert(OutListCount
>= 0);
279 // if a close has been acknowledged in sequence, we're done
281 // `OutList` can still contain some packets here for some reason
282 // it looks like a bug in my netcode
284 GCon
->Logf(NAME_DevNet
, "!!!! %s: acked close message, but contains some other unacked messages (%d) !!!!", *GetDebugName(), OutListCount
);
285 for (VMessageOut
*Out
= OutList
; Out
; Out
= Out
->Next
) {
286 vassert(!Out
->bReceivedAck
);
287 GCon
->Logf(NAME_DevNet
, " pid=%u; csq=%u; cidx=%u; ctype=%u; open=%d; close=%d; reliable=%d; size=%d",
288 Out
->PacketId
, Out
->ChanSequence
, Out
->ChanType
, Out
->ChanIndex
, (int)Out
->bOpen
, (int)Out
->bClose
,
289 (int)Out
->bReliable
, Out
->GetNumBits());
299 //==========================================================================
301 // VChannel::SendCloseMessageForced
303 // this unconditionally adds "close" message to the
304 // queue, and marks the channel for closing
306 // WARNING! DOES NO CHECKS!
308 //==========================================================================
309 void VChannel::SendCloseMessageForced () {
310 if (!Connection
) return;
311 VMessageOut
cnotmsg(this, true); // reliable
312 cnotmsg
.bClose
= true;
313 // this should not happen, but...
314 if (OpenedLocally
&& !bSentAnyMessages
) cnotmsg
.bOpen
= true;
315 // put into queue without any checks
316 cnotmsg
.Next
= nullptr;
317 cnotmsg
.ChanSequence
= ++Connection
->OutReliable
[Index
];
318 VMessageOut
*OutMsg
= new VMessageOut(cnotmsg
);
319 VMessageOut
**OutLink
;
320 for (OutLink
= &OutList
; *OutLink
; OutLink
= &(*OutLink
)->Next
) {}
322 OutMsg
->OutEstimated
= OutMsg
->EstimateSizeInBits();
323 OutListBits
+= OutMsg
->OutEstimated
;
325 // send the raw message
326 OutMsg
->bReceivedAck
= false;
327 Connection
->SendMessage(OutMsg
);
331 //==========================================================================
333 // VChannel::SendMessage
335 //==========================================================================
336 void VChannel::SendMessage (VMessageOut
*Msg
) {
339 vassert(Connection
->Channels
[Index
] == this);
340 vassert(!Msg
->IsError());
342 // set some additional message flags
343 if (OpenedLocally
&& !bSentAnyMessages
) {
344 // first message must be reliable
345 vassert(Msg
->bReliable
);
348 bSentAnyMessages
= true;
350 if (Msg
->bReliable
) {
351 // put outgoing message into send queue
352 //vassert(OutListCount < MAX_RELIABLE_BUFFER-1+(Msg->bClose ? 1 : 0));
353 const int satur
= IsQueueFull();
356 GCon
->Logf(NAME_DevNet
, "NETWORK ERROR: channel %s is highly oversaturated!", *GetDebugName());
357 Connection
->AbortChannel(this);
360 GCon
->Logf(NAME_DevNet
, "NETWORK ERROR: channel %s is oversaturated!", *GetDebugName());
364 Msg
->ChanSequence
= ++Connection
->OutReliable
[Index
];
365 VMessageOut
*OutMsg
= new VMessageOut(*Msg
);
366 VMessageOut
**OutLink
;
367 for (OutLink
= &OutList
; *OutLink
; OutLink
= &(*OutLink
)->Next
) {}
369 Msg
= OutMsg
; // use this new message for sending
370 Msg
->OutEstimated
= Msg
->EstimateSizeInBits();
371 OutListBits
+= Msg
->OutEstimated
;
375 // send the raw message
376 Msg
->bReceivedAck
= false;
377 Connection
->SendMessage(Msg
);
378 // if we're closing the channel, mark this channel as dying, so we can reject any new data
379 // note that we can still have some fragments of the data in incoming queue, and it will be
380 // processed normally
381 if (Msg
->bClose
) SetClosing();
385 //==========================================================================
387 // VChannel::ProcessInMessage
389 //==========================================================================
390 bool VChannel::ProcessInMessage (VMessageIn
&Msg
) {
391 // fix channel incoming sequence
392 if (Msg
.bReliable
) Connection
->InReliable
[Index
] = Msg
.ChanSequence
;
395 const bool isCloseMsg
= Msg
.bClose
;
396 if (!Closing
) ParseMessage(Msg
);
398 // handle a close notify
400 if (InList
) Sys_Error("ERROR: %s: closing channel #%d with unprocessed incoming queue", *GetDebugName(), Index
);
408 //==========================================================================
410 // VChannel::ReceivedMessage
412 // process a raw, possibly out-of-sequence message
413 // either queue it or dispatch it
414 // the message won't be discarded
416 //==========================================================================
417 void VChannel::ReceivedMessage (VMessageIn
&Msg
) {
418 vassert(Connection
->Channels
[Index
] == this);
420 if (Msg
.bReliable
&& Msg
.ChanSequence
!= Connection
->InReliable
[Index
]+1) {
421 // if this message is not in a sqeuence, buffer it
422 // out-of-sequence message cannot be open message
423 // actually, we should show channel error, and block all further messaging on it
424 // (or even close the connection, as it looks like broken/malicious)
428 vassert(Msg
.ChanSequence
> Connection
->InReliable
[Index
]);
430 // put this into incoming queue, keeping the queue ordered
431 VMessageIn
*prev
= nullptr, *curr
= InList
;
433 if (Msg
.ChanSequence
== curr
->ChanSequence
) return; // duplicate message, ignore it
434 if (Msg
.ChanSequence
< curr
->ChanSequence
) break; // insert before `curr`
439 VMessageIn
*newmsg
= new VMessageIn(Msg
);
440 if (prev
) prev
->Next
= newmsg
; else InList
= newmsg
;
442 InListBits
+= newmsg
->GetNumBits();
445 for (VMessageIn
*m
= InList
; m
&& m
->Next
; m
= m
->Next
) vassert(m
->ChanSequence
< m
->Next
->ChanSequence
);
446 //vassert(InListCount <= MAX_RELIABLE_BUFFER); //FIXME: signal error here!
447 if (InListBits
> /*(MAX_RELIABLE_BUFFER+18)*MAX_MSG_SIZE_BITS*/128000*8) {
448 GCon
->Logf(NAME_DevNet
, "NETWORK ERROR: channel %s incoming queue overflowed!", *GetDebugName());
449 Connection
->AbortChannel(this);
453 // this is "in sequence" message, process it
454 bool removed
= ProcessInMessage(Msg
);
457 // dispatch any waiting messages
459 if (InList
->ChanSequence
!= Connection
->InReliable
[Index
]+1) break;
460 VMessageIn
*curr
= InList
;
461 InList
= InList
->Next
;
462 InListBits
-= curr
->GetNumBits();
464 vassert(InListCount
>= 0);
465 vassert(InListBits
>= 0);
466 removed
= ProcessInMessage(*curr
);
474 //==========================================================================
478 //==========================================================================
479 void VChannel::Tick () {
483 //==========================================================================
485 // VChannel::WillOverflowMsg
487 //==========================================================================
488 bool VChannel::WillOverflowMsg (const VMessageOut
*msg
, int addbits
) const noexcept
{
490 return msg
->WillOverflow(addbits
);
494 //==========================================================================
496 // VChannel::WillOverflowMsg
498 //==========================================================================
499 bool VChannel::WillOverflowMsg (const VMessageOut
*msg
, const VBitStreamWriter
&strm
) const noexcept
{
501 return msg
->WillOverflow(strm
);
505 //==========================================================================
507 // VChannel::PutStream
509 // moves steam to msg (sending previous msg if necessary)
511 // returns `true` if something was flushed
513 //==========================================================================
514 bool VChannel::PutStream (VMessageOut
*msg
, VBitStreamWriter
&strm
) {
516 if (strm
.GetNumBits() == 0) return false;
518 if (WillOverflowMsg(msg
, strm
)) {
521 msg
->Reset(this, msg
->bReliable
);
523 vassert(!WillOverflowMsg(msg
, strm
));
524 msg
->CopyFromWS(strm
);
530 //==========================================================================
532 // VChannel::FlushMsg
534 // sends message if it is not empty
536 // returns `true` if something was flushed
538 //==========================================================================
539 bool VChannel::FlushMsg (VMessageOut
*msg
) {
541 if (msg
->GetNumBits() || msg
->bOpen
|| msg
->bClose
) {
543 msg
->Reset(this, msg
->bReliable
);
550 //==========================================================================
554 //==========================================================================
555 void VChannel::SendRpc (VMethod
*Func
, VObject
* /*Owner*/) {
556 // we cannot simply get out of here, because we need to pop function arguments
558 //const bool blockSend = !CanSendData();
559 const bool blockSend
= (Closing
|| IsQueueFull() < 0);
560 bool serverSide
= Closing
; // abuse the flag
562 // check for server-side only
563 if (!serverSide
&& IsThinker()) {
564 VThinkerChannel
*tc
= (VThinkerChannel
*)this;
565 VThinker
*th
= tc
->GetThinker();
566 if (th
&& (th
->ThinkerFlags
&(VThinker::TF_AlwaysRelevant
|VThinker::TF_ServerSideOnly
)) == VThinker::TF_ServerSideOnly
) serverSide
= true;
569 VMessageOut
Msg(this, !!(Func
->Flags
&FUNC_NetReliable
));
570 //GCon->Logf(NAME_DevNet, "%s: creating RPC: %s", *GetDebugName(), *Func->GetFullName());
571 Msg
.WriteUInt((unsigned)Func
->NetIndex
);
573 // serialise arguments
574 VStack
*Param
= VObject::VMGetStackPtr()-Func
->ParamsSize
+1; // skip self
575 for (int i
= 0; i
< Func
->NumParams
; ++i
) {
576 switch (Func
->ParamTypes
[i
].Type
) {
581 VField::NetSerialiseValue(Msg
, Connection
->ObjMap
, (vuint8
*)&Param
->i
, Func
->ParamTypes
[i
]);
585 VField::NetSerialiseValue(Msg
, Connection
->ObjMap
, (vuint8
*)&Param
->f
, Func
->ParamTypes
[i
]);
593 VField::NetSerialiseValue(Msg
, Connection
->ObjMap
, (vuint8
*)&Param
->p
, Func
->ParamTypes
[i
]);
602 VField::NetSerialiseValue(Msg
, Connection
->ObjMap
, (vuint8
*)&Vec
, Func
->ParamTypes
[i
]);
607 Host_Error("%s: Bad method argument type %d", *GetDebugName(), Func
->ParamTypes
[i
].Type
);
609 if (Func
->ParamFlags
[i
]&FPARM_Optional
) {
610 Msg
.WriteBit(!!Param
->i
);
615 if (serverSide
) return; // nothing to do
619 if (!(Func
->Flags
&FUNC_NetReliable
)) return; // nobody cares
620 // alas, cannot send reliable RPC, close the channel, and get out of here
621 // if this is non-thinker channel, it is fatal
622 // if this is thinker channel, but it has "always relevant", it is fatal
624 GCon
->Logf(NAME_DevNet
, "%s: cannot send reliable RPC (%s), closing connection (queue: depth=%d; bitsize=%d)", *GetDebugName(), *Func
->GetFullName(), OutListCount
, OutListBits
);
629 VThinkerChannel
*tc
= (VThinkerChannel
*)this;
630 if (tc
->GetThinker() && (tc
->GetThinker()->ThinkerFlags
&VThinker::TF_AlwaysRelevant
)) {
631 GCon
->Logf(NAME_DevNet
, "%s: cannot send reliable thinker RPC (%s), closing connection (queue: depth=%d; bitsize=%d)", *GetDebugName(), *Func
->GetFullName(), OutListCount
, OutListBits
);
635 GCon
->Logf(NAME_DevNet
, "%s: cannot send reliable thinker RPC (%s), closing channel (queue: depth=%d; bitsize=%d)", *GetDebugName(), *Func
->GetFullName(), OutListCount
, OutListBits
);
641 if (net_debug_rpc
) GCon
->Logf(NAME_DevNet
, "%s: created %s RPC: %s (%d bits) (queue: depth=%d; bitsize=%d)", *GetDebugName(), (Func
->Flags
&FUNC_NetReliable
? "reliable" : "unreliable"), *Func
->GetFullName(), Msg
.GetNumBits(), OutListCount
, OutListBits
);
645 //==========================================================================
649 //==========================================================================
650 bool VChannel::ReadRpc (VMessageIn
&Msg
, int FldIdx
, VObject
*Owner
) {
651 VMethod
*Func
= nullptr;
652 for (VMethod
*CM
= Owner
->GetClass()->NetMethods
; CM
; CM
= CM
->NextNetMethod
) {
653 if (CM
->NetIndex
== FldIdx
) {
658 if (!Func
) return false;
659 if (net_debug_rpc
) GCon
->Logf(NAME_DevNet
, "%s: ...received RPC (%s); method %s", *GetDebugName(), (Connection
->IsClient() ? "client" : "server"), *Func
->GetFullName());
661 //memset(pr_stackPtr, 0, Func->ParamsSize*sizeof(VStack));
662 VObject::VMCheckAndClearStack(Func
->ParamsSize
);
664 VObject::PR_PushPtr(Owner
);
666 for (int i
= 0; i
< Func
->NumParams
; ++i
) {
667 switch (Func
->ParamTypes
[i
].Type
) {
672 VField::NetSerialiseValue(Msg
, Connection
->ObjMap
, (vuint8
*)&VObject::VMGetStackPtr()->i
, Func
->ParamTypes
[i
]);
673 VObject::VMIncStackPtr();
676 VField::NetSerialiseValue(Msg
, Connection
->ObjMap
, (vuint8
*)&VObject::VMGetStackPtr()->f
, Func
->ParamTypes
[i
]);
677 VObject::VMIncStackPtr();
680 VObject::VMGetStackPtr()->p
= nullptr;
681 VField::NetSerialiseValue(Msg
, Connection
->ObjMap
, (vuint8
*)&VObject::VMGetStackPtr()->p
, Func
->ParamTypes
[i
]);
682 VObject::VMIncStackPtr();
688 VField::NetSerialiseValue(Msg
, Connection
->ObjMap
, (vuint8
*)&VObject::VMGetStackPtr()->p
, Func
->ParamTypes
[i
]);
689 VObject::VMIncStackPtr();
694 VField::NetSerialiseValue(Msg
, Connection
->ObjMap
, (vuint8
*)&Vec
, Func
->ParamTypes
[i
]);
695 VObject::PR_Pushv(Vec
);
699 Host_Error("%s: Bad method argument type `%s` for RPC method call `%s`", *GetDebugName(), *Func
->ParamTypes
[i
].GetName(), *Func
->GetFullName());
701 if (Func
->ParamFlags
[i
]&FPARM_Optional
) {
702 VObject::VMGetStackPtr()->i
= Msg
.ReadBit();
703 VObject::VMIncStackPtr();
707 (void)VObject::ExecuteFunction(Func
);