Merge branch 'fixes' into main/rendor-staging
[ryzomcore.git] / nel / src / net / module_gateway_transport.cpp
blob08ff51eebf27e8697a48e9322ddc6a7dce93c38e
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "stdnet.h"
18 #include "nel/misc/time_nl.h"
19 #include "nel/net/module_gateway.h"
20 #include "nel/net/module.h"
21 #include "nel/net/module_manager.h"
22 #include "nel/net/module_socket.h"
23 #include "nel/net/module_message.h"
24 #include "nel/net/callback_client.h"
25 #include "nel/net/callback_server.h"
27 using namespace std;
28 using namespace NLMISC;
30 #ifdef DEBUG_NEW
31 #define new DEBUG_NEW
32 #endif
35 namespace NLNET
38 // keep alive delay in seconds of inactivity
39 // NB : it is useless to set it at a value less than 100" because
40 // according to RFC 1122 (Requirements for Internet Hosts),
41 // the TCP transmission time out is a least of 100" before
42 // closing a connection without acknowledge.
43 // That means modules seens from a dead connection will only be
44 // removed after little more than 100".
45 const uint32 KEEP_ALIVE_DELAY = 120;
47 /** the specialized route for server transport */
48 class CL3ServerRoute : public CGatewayRoute
50 public:
51 /// The id of the socket in the server
52 TSockId SockId;
54 /// Time stamp of last message received/emitted
55 mutable uint32 LastCommTime;
58 CL3ServerRoute(IGatewayTransport *transport)
59 : CGatewayRoute(transport),
60 LastCommTime(CTime::getSecondsSince1970())
64 void sendMessage(const CMessage &message) const;
67 #define LAYER3_SERVER_CLASS_NAME "L3Server"
69 /** Gateway transport using layer 3 server */
70 class CGatewayL3ServerTransport : public IGatewayTransport
72 friend class CL3ServerRoute;
73 public:
74 /// The callback server that receive connection and dispatch message
75 CUniquePtr<CCallbackServer> _CallbackServer;
77 /// A static mapper to retrieve transport from the CCallbackServer pointer
78 typedef map<CCallbackNetBase*, CGatewayL3ServerTransport*> TDispatcherIndex;
79 static TDispatcherIndex _DispatcherIndex;
81 /// The table that keep track of all routes
82 typedef std::map<TSockId, CL3ServerRoute*> TRouteMap;
83 TRouteMap _Routes;
86 /// Constructor
87 CGatewayL3ServerTransport(const IGatewayTransport::TCtorParam &param)
88 : IGatewayTransport(param)
92 ~CGatewayL3ServerTransport()
94 if (_CallbackServer.get() != NULL)
96 // the transport is still open, close it before destruction
97 closeServer();
101 const std::string &getClassName() const
103 static string className(LAYER3_SERVER_CLASS_NAME);
104 return className;
107 virtual void update()
109 H_AUTO(L3S_update);
110 // update the callback server
111 if (_CallbackServer.get() != NULL)
112 _CallbackServer->update2(100, 0);
114 uint32 now = CTime::getSecondsSince1970();
115 // check each connected client for keep alive
116 TRouteMap::iterator first(_Routes.begin()), last(_Routes.end());
117 for (; first != last; ++first)
119 CL3ServerRoute *route = first->second;
121 if (now - route->LastCommTime > KEEP_ALIVE_DELAY)
123 nldebug("NETL6:L3Server: sending KeepAlive message");
124 // send a keep alive message
125 CMessage keepAlive("KA");
126 route->sendMessage(keepAlive);
128 // update the last event time
129 route->LastCommTime = CTime::getSecondsSince1970();
132 // force a flush of the connection
133 _CallbackServer->flush(route->SockId);
139 virtual uint32 getRouteCount() const
141 return (uint32)_Routes.size();
144 void dump(NLMISC::CLog &log) const
146 IModuleManager &mm = IModuleManager::getInstance();
147 log.displayNL(" NeL Net layer 3 transport, SERVER mode");
148 if (_CallbackServer.get() == NULL)
150 log.displayNL(" The server is currently closed.");
152 else
154 log.displayNL(" The server is open on '%s' and support %u routes :",
155 _CallbackServer->listenAddress().asString().c_str(),
156 _Routes.size());
157 TRouteMap::const_iterator first(_Routes.begin()), last(_Routes.end());
158 for (; first != last; ++first)
160 TSockId sockId = first->first;
161 CL3ServerRoute *route = first->second;
162 log.displayNL(" + route to '%s', %u entries in the proxy translation table :",
163 sockId->getTcpSock()->remoteAddr().asString().c_str(),
164 route->ForeignToLocalIdx.getAToBMap().size());
167 CGatewayRoute::TForeignToLocalIdx::TAToBMap::const_iterator first(route->ForeignToLocalIdx.getAToBMap().begin()), last(route->ForeignToLocalIdx.getAToBMap().end());
168 for (; first != last; ++first)
170 IModuleProxy *modProx = mm.getModuleProxy(first->second);
172 log.displayNL(" - Proxy '%s' : local proxy id %u => foreign module id %u",
173 modProx != NULL ? modProx->getModuleName().c_str() : "ERROR, invalid module",
174 first->second,
175 first->first);
180 log.displayNL(" Dumping send buffers states");
181 _CallbackServer->displaySendQueueStat(&log);
182 log.displayNL(" Dumping receive buffers states");
183 _CallbackServer->displayReceiveQueueStat(&log);
187 void onCommand(const CMessage &/* command */)
189 // nothing done for now
190 throw EInvalidCommand();
192 /// The gateway send a textual command to the transport
193 bool onCommand(const TParsedCommandLine &command)
195 if (command.SubParams.size() < 1)
196 throw EInvalidCommand();
198 const std::string &commandName = command.SubParams[0]->ParamName;
199 if (commandName == "open")
201 const TParsedCommandLine *portParam = command.getParam("port");
202 if (portParam == NULL)
203 throw EInvalidCommand();
205 uint16 port;
206 fromString(portParam->ParamValue, port);
208 openServer(port);
210 else if (commandName == "close")
212 closeServer();
214 else
215 return false;
217 return true;
220 /// Open the server by starting listing for incoming connection on the specified port
221 void openServer(uint16 port)
223 if (_CallbackServer.get() != NULL)
224 throw ETransportError("openServer : The server is already open");
226 // create a new callback server
227 CUniquePtr<CCallbackServer> cbs(new CCallbackServer());
229 // register the callbacks
230 cbs->setConnectionCallback(cbConnection, static_cast<IGatewayTransport*>(this));
231 cbs->setDisconnectionCallback(cbDisconnection, static_cast<IGatewayTransport*>(this));
232 cbs->setDefaultCallback(cbDispatchMessage);
234 // open the server
235 cbs->init(port);
237 _CallbackServer = CUniquePtrMove(cbs);
239 // register it in the dispatcher
240 _DispatcherIndex.insert(make_pair(_CallbackServer.get(), this));
243 /// Close the server, this will close the listing socket and any active connection
244 void closeServer()
246 if (_CallbackServer.get() == NULL)
247 throw ETransportError("closeServer : The server is not open");
249 // close all client connections
250 while (!_Routes.empty())
252 CL3ServerRoute *route = _Routes.begin()->second;
254 // close the connection
255 _CallbackServer->disconnect(route->SockId);
256 // callback the gateway
257 _Gateway->onRouteRemoved(route);
259 // delete route and cleanup
260 _Routes.erase(_Routes.begin());
261 delete route;
264 // Remove the dispatcher info
265 _DispatcherIndex.erase(_CallbackServer.get());
267 // release the callback server
268 delete _CallbackServer.release();
272 /***************************************************/
273 /** Event management **/
274 /***************************************************/
276 // handle the connection of a new client on the server
277 void onConnection ( TSockId from)
279 H_AUTO(L3S_onConnection);
280 nlassert(_Routes.find(from) == _Routes.end());
282 // Create a new route for this connection
283 CL3ServerRoute* route = new CL3ServerRoute(this);
284 route->SockId = from;
286 // update the last event time
287 route->LastCommTime = CTime::getSecondsSince1970();
289 // store the route information
290 _Routes.insert(make_pair(from, route));
292 // callback the gateway
293 _Gateway->onRouteAdded(route);
296 // handle the deconnection of a new client on the server
297 void onDisconnection ( TSockId from)
299 H_AUTO(L3S_onDisconnection);
300 TRouteMap::iterator it(_Routes.find(from));
301 nlassert(it != _Routes.end());
303 // callback the gateway that this route is no more
304 _Gateway->onRouteRemoved(it->second);
306 // delete the route
307 CL3ServerRoute *route = it->second;
308 _Routes.erase(it);
309 delete route;
312 // Called to dispatch an incoming message to the gateway
313 void onDispatchMessage(const CMessage &msgin, TSockId from, CCallbackNetBase &/* netbase */)
315 H_AUTO(L3S_onDispatchMessage);
316 TRouteMap::iterator it(_Routes.find(from));
317 nlassert(it != _Routes.end());
319 // update the last event time
320 it->second->LastCommTime = CTime::getSecondsSince1970();
322 if (msgin.getName() == "KA")
324 // this is just a server prob, ignore it
325 return;
328 _Gateway->onReceiveMessage(it->second, msgin);
333 /***************************************************/
334 /** static callback forwarder **/
335 /***************************************************/
336 // Forwarder to the real method
337 static void cbConnection ( TSockId from, void *arg )
339 nlassert(arg != NULL);
340 CGatewayL3ServerTransport *transport = dynamic_cast<CGatewayL3ServerTransport *>(static_cast<IGatewayTransport*>(arg));
341 nlassert(transport != NULL);
343 transport->onConnection(from);
346 // Forwarder to the real method
347 static void cbDisconnection ( TSockId from, void *arg )
349 nlassert(arg != NULL);
350 CGatewayL3ServerTransport *transport = dynamic_cast<CGatewayL3ServerTransport *>(static_cast<IGatewayTransport*>(arg));
351 nlassert(transport != NULL);
353 transport->onDisconnection(from);
356 // Forward to the real method, do the dispatching to the correct CGatewayL3ServerTransport instance
357 static void cbDispatchMessage (CMessage &msgin, TSockId from, CCallbackNetBase &netbase)
359 // retrieve the transport instance
360 TDispatcherIndex::iterator it(_DispatcherIndex.find(&netbase));
361 nlassert(it != _DispatcherIndex.end());
363 // forward the call
364 it->second->onDispatchMessage(msgin, from, netbase);
369 CGatewayL3ServerTransport::TDispatcherIndex CGatewayL3ServerTransport::_DispatcherIndex;
371 // register this class in the transport factory
372 NLMISC_REGISTER_OBJECT(IGatewayTransport, CGatewayL3ServerTransport, std::string, string(LAYER3_SERVER_CLASS_NAME));
374 void CL3ServerRoute::sendMessage(const CMessage &message) const
376 H_AUTO(L3SRoute_sendMessage);
377 NLNET_AUTO_DELTE_ASSERT;
379 CGatewayL3ServerTransport *trpt = static_cast<CGatewayL3ServerTransport*>(_Transport);
381 // send the message
382 trpt->_CallbackServer->send(message, SockId);
384 // update the last time
385 LastCommTime = CTime::getSecondsSince1970();
388 /////////////////////////////////////////////////////////////////////////////////////////
389 /////////////////////////////////////////////////////////////////////////////////////////
390 /// Layer 3 client transport
391 /////////////////////////////////////////////////////////////////////////////////////////
392 /////////////////////////////////////////////////////////////////////////////////////////
393 class CL3ClientRoute : public CGatewayRoute
395 public:
396 /// The server address for this route
397 CInetAddress ServerAddr;
398 /// The Client callback
399 mutable CCallbackClient CallbackClient;
400 /// Time stamp of last message received/emitted
401 mutable uint32 LastCommTime;
403 /// The last time we try to reconnect (in case of disconnection)
404 uint32 LastConnectionRetry;
406 // conn id
407 uint32 ConnId;
409 CL3ClientRoute(IGatewayTransport *transport, CInetAddress serverAddr,uint32 connId)
410 : CGatewayRoute(transport),
411 ServerAddr(serverAddr),
412 LastCommTime(CTime::getSecondsSince1970()),
413 LastConnectionRetry(0),
414 ConnId(connId)
418 void sendMessage(const CMessage &message) const
420 NLNET_AUTO_DELTE_ASSERT;
421 H_AUTO(L3CRoute_sendMessage);
422 if (CallbackClient.connected())
424 // update the last comme time
425 LastCommTime = CTime::getSecondsSince1970();
427 CallbackClient.send(message);
432 #define LAYER3_CLIENT_CLASS_NAME "L3Client"
434 /** Gateway transport using layer 3 client */
435 class CGatewayL3ClientTransport : public IGatewayTransport
437 friend class CL3ClientRoute;
438 public:
439 /// A static mapper to retrieve transport from the CCallbackServer pointer
440 typedef map<CCallbackNetBase*, CGatewayL3ClientTransport*> TDispatcherIndex;
441 static TDispatcherIndex _DispatcherIndex;
443 /// Storage for active connection
444 typedef map<TSockId, CL3ClientRoute*> TClientRoutes;
445 TClientRoutes _Routes;
447 /// Indexed storage of active connection (used for stable connId)
448 /// a NULL TSockeId mean a free connection slot.
449 typedef vector<TSockId> TClientRouteIds;
450 TClientRouteIds _RouteIds;
451 /// A list of free slot ready for use
452 typedef vector<TClientRouteIds::difference_type> TFreeRouteIds;
453 TFreeRouteIds _FreeRoutesIds;
455 /// the route to delete outside of the update loop
456 list<CL3ClientRoute*> _RouteToRemove;
458 /// Retry interval for reconnection
459 uint32 _RetryInterval;
461 enum
463 /// Default time interval (in seconds) between to reconnection attempts
464 RETRY_INTERVAL = 5,
465 /// A minimum value in case or configuration error
466 MIN_RETRY_INTERVAL = 1,
469 /// Constructor
470 CGatewayL3ClientTransport(const IGatewayTransport::TCtorParam &param)
471 : IGatewayTransport(param),
472 _RetryInterval(RETRY_INTERVAL)
476 ~CGatewayL3ClientTransport()
478 deletePendingRoute();
480 // close all open connection
481 for (uint i=0; i<_RouteIds.size(); ++i)
483 if (_RouteIds[i] != NULL)
485 // close this open connection
486 close(i);
491 void deletePendingRoute()
493 H_AUTO(L3C_deletePendingRoute);
494 // delete any route pending
495 while (!_RouteToRemove.empty())
497 CL3ClientRoute *route = _RouteToRemove.front();
498 _DispatcherIndex.erase(&(route->CallbackClient));
499 _Routes.erase(route->CallbackClient.getSockId());
501 _RouteIds[route->ConnId] = NULL;
502 _FreeRoutesIds.push_back(route->ConnId);
503 delete route;
504 _RouteToRemove.pop_front();
508 const std::string &getClassName() const
510 static string className(LAYER3_CLIENT_CLASS_NAME);
511 return className;
514 virtual void update()
516 H_AUTO(L3C_update);
517 // delete any route pending
518 deletePendingRoute();
520 uint32 now = CTime::getSecondsSince1970();
521 // update the client connection
522 TClientRoutes::iterator first(_Routes.begin()), last(_Routes.end());
523 for (; first != last; ++first)
525 CL3ClientRoute *route = first->second;
527 if (!route->CallbackClient.connected())
529 // this route is not connected, try a reconnect ?
530 if (route->LastConnectionRetry + _RetryInterval < now)
532 route->LastConnectionRetry = now;
535 nldebug("Connecting to %s...", route->ServerAddr.asString().c_str());
536 route->CallbackClient.connect(route->ServerAddr);
537 nldebug("Connected to %s", route->ServerAddr.asString().c_str());
538 _Gateway->onRouteAdded(route);
540 catch(...)
542 nlinfo("Server %s still not available for connection", route->ServerAddr.asString().c_str());
546 else
548 route->CallbackClient.update2(100, 0);
550 // check dead connection. For client, we use a little longer timer to
551 // avoid cross checking of client and server. If server is alive, then we receive
552 // the server keep alive packet a little before we need to send the client one, thus
553 // reseting the keep alive timer.
554 if (now - route->LastCommTime > (KEEP_ALIVE_DELAY+5))
556 nldebug("NETL6:L3Client: sending KeepAlive message");
558 // send a keep alive message
559 CMessage keepAlive("KA");
561 route->sendMessage(keepAlive);
564 // force a flush of the connection
565 route->CallbackClient.flush();
570 virtual uint32 getRouteCount() const
572 return (uint32)_Routes.size();
575 void dump(NLMISC::CLog &log) const
577 IModuleManager &mm = IModuleManager::getInstance();
578 log.displayNL(" NeL Net layer 3 transport, CLIENT mode");
580 log.displayNL(" There are actually %u active route :", _Routes.size());
582 TClientRoutes::const_iterator first(_Routes.begin()), last(_Routes.end());
583 for (; first != last; ++first)
585 CL3ClientRoute *route = first->second;
586 log.displayNL(" + route to '%s', %s, %u entries in the proxy translation table :",
587 route->ServerAddr.asString().c_str(),
588 route->CallbackClient.connected() ? "connected" : "NOT CONNECTED",
589 route->ForeignToLocalIdx.getAToBMap().size());
591 CGatewayRoute::TForeignToLocalIdx::TAToBMap::const_iterator first(route->ForeignToLocalIdx.getAToBMap().begin()), last(route->ForeignToLocalIdx.getAToBMap().end());
592 for (; first != last; ++first)
594 IModuleProxy *modProx = mm.getModuleProxy(first->second);
596 log.displayNL(" - Proxy '%s' : local proxy id %u => foreign module id %u",
597 modProx != NULL ? modProx->getModuleName().c_str() : "ERROR, invalid module",
598 first->second,
599 first->first);
603 log.displayNL(" Dumping send buffer state");
604 route->CallbackClient.displaySendQueueStat(&log);
605 log.displayNL(" Dumping receive buffer state");
606 route->CallbackClient.displayReceiveQueueStat(&log);
610 void onCommand(const CMessage &/* command */)
612 // nothing done for now
613 throw EInvalidCommand();
615 /// The gateway send a textual command to the transport
616 bool onCommand(const TParsedCommandLine &command)
618 if (command.SubParams.size() < 1)
619 throw EInvalidCommand();
621 const std::string &commandName = command.SubParams[0]->ParamName;
622 if (commandName == "connect")
624 const TParsedCommandLine *addrParam = command.getParam("addr");
625 if (addrParam == NULL)
626 throw EInvalidCommand();
628 CInetAddress addr(addrParam->ParamValue);
630 connect(addr);
632 else if (commandName == "close")
634 const TParsedCommandLine *conIdParam= command.getParam("connId");
635 if (conIdParam == NULL)
636 throw EInvalidCommand();
638 uint32 connId;
639 fromString(conIdParam->ParamValue, connId);
641 close(connId);
643 else if (commandName == "retryInterval")
645 uint32 interval;
646 fromString(command.SubParams[0]->ParamValue, interval);
647 _RetryInterval = std::max(uint32(MIN_RETRY_INTERVAL), interval);
649 nldebug("CGatewayL3ClientTransport : setting retry interval to %u", _RetryInterval);
651 else
652 return false;
654 return true;
658 /// connect to a server
659 void connect(CInetAddress &addr)
661 H_AUTO(L3C_connect);
662 uint32 connId;
664 // affect a connection id
665 if (_FreeRoutesIds.empty())
667 connId = (uint32)_RouteIds.size();
668 _RouteIds.push_back(InvalidSockId);
670 else
672 connId = (uint32)_FreeRoutesIds.back();
673 _FreeRoutesIds.pop_back();
676 CUniquePtr<CL3ClientRoute> route(new CL3ClientRoute(this, addr, connId));
678 // set the callbacks
679 route->CallbackClient.setDisconnectionCallback(cbDisconnection, static_cast<IGatewayTransport*>(this));
680 route->CallbackClient.setDefaultCallback(cbDispatchMessage);
684 nldebug("CGatewayL3ClientTransport : Connecting to %s...", addr.asString().c_str());
685 route->LastConnectionRetry = CTime::getSecondsSince1970();
686 // connect to the server
687 route->CallbackClient.connect(addr);
688 nldebug("CGatewayL3ClientTransport : Connected to %s with connId %u", addr.asString().c_str(), connId);
690 catch (const ESocketConnectionFailed &)
692 nlinfo("CGatewayL3ClientTransport : Failed to connect to server %s, retrying in %u seconds", addr.asString().c_str(), _RetryInterval);
695 // store the route
696 _Routes.insert(make_pair(route->CallbackClient.getSockId(), route.get()));
697 _RouteIds[connId] = route->CallbackClient.getSockId();
699 // register it in the dispatcher
700 _DispatcherIndex.insert(make_pair(&route->CallbackClient, this));
702 // release the auto ptr
703 CL3ClientRoute *rt = route.release();
705 // callback the gateway about the new route
706 if (rt->CallbackClient.connected())
707 _Gateway->onRouteAdded(rt);
710 // handle the connection of a new client on the server
711 void close ( uint32 connId)
713 H_AUTO(L3C_close);
714 // some basic checks on connId
715 if (connId >= _RouteIds.size())
717 nlwarning("CGatewayL3ClientTransport : Invalid connectionId %u, max is %u", connId, _RouteIds.size()-1);
718 return;
721 if (_RouteIds[connId] == NULL)
723 nlwarning("CGatewayL3ClientTransport : Invalid connectionId %u, the connection is unused now.", connId);
724 return;
728 deletePendingRoute();
730 // retrieve the connection to close
731 TClientRoutes::iterator it(_Routes.find(_RouteIds[connId]));
732 nlassert(it != _Routes.end());
734 CL3ClientRoute *route = it->second;
736 nldebug("CGatewayL3ClientTransport : Closing connection %u to %s", connId, route->ServerAddr.asString().c_str());
739 if (route->CallbackClient.connected())
741 // callback gateway
742 _Gateway->onRouteRemoved(route);
744 // close the connection
745 route->CallbackClient.disconnect();
748 // cleanup memory, index ...
749 _DispatcherIndex.erase(&(route->CallbackClient));
750 _Routes.erase(it);
751 delete route;
752 _RouteIds[connId] = NULL;
753 _FreeRoutesIds.push_back(connId);
756 /***************************************************/
757 /** Event management **/
758 /***************************************************/
760 // handle the deconnection of a the client from the server
761 void onDisconnection ( TSockId from)
763 H_AUTO(L3C_onDisconnection);
764 // nothing to do, as route as kept persistent and try to reconnect
766 TClientRoutes::iterator it(_Routes.find(from));
767 nlassert(it != _Routes.end());
769 nldebug("CGatewayL3ClientTransport : Disconnection from %s", it->second->ServerAddr.asString().c_str());
772 // callback the gateway that this route is no more
773 _Gateway->onRouteRemoved(it->second);
775 // update the last connection try to 'now'
776 it->second->LastConnectionRetry = CTime::getSecondsSince1970();
778 // // delete the route
779 // CL3ClientRoute *route = it->second;
781 // _RouteToRemove.push_back(route);
784 // Called to dispatch an incoming message to the gateway
785 void onDispatchMessage(const CMessage &msgin, TSockId from, CCallbackNetBase &/* netbase */)
787 H_AUTO(L3C_onDispatchMessage);
788 TClientRoutes::iterator it(_Routes.find(from));
789 nlassert(it != _Routes.end());
791 // update last comm time
792 it->second->LastCommTime = CTime::getSecondsSince1970();
794 if (msgin.getName() == "KA")
796 // this is just a server prob, ignore it
797 return;
800 _Gateway->onReceiveMessage(it->second, msgin);
804 /***************************************************/
805 /** static callback forwarder **/
806 /***************************************************/
808 // Forwarder to the real method
809 static void cbDisconnection ( TSockId from, void *arg )
811 nlassert(arg != NULL);
812 CGatewayL3ClientTransport *transport = dynamic_cast<CGatewayL3ClientTransport *>(static_cast<IGatewayTransport*>(arg));
813 nlassert(transport != NULL);
815 transport->onDisconnection(from);
818 // Forward to the real method, do the dispatching to the correct CGatewayL3ServerTransport instance
819 static void cbDispatchMessage (CMessage &msgin, TSockId from, CCallbackNetBase &netbase)
821 // retrieve the transport instance
822 TDispatcherIndex::iterator it(_DispatcherIndex.find(&netbase));
823 nlassert(it != _DispatcherIndex.end());
825 // forward the call
826 it->second->onDispatchMessage(msgin, from, netbase);
831 CGatewayL3ClientTransport::TDispatcherIndex CGatewayL3ClientTransport::_DispatcherIndex;
833 // register this class in the transport factory
834 NLMISC_REGISTER_OBJECT(IGatewayTransport, CGatewayL3ClientTransport, std::string, string(LAYER3_CLIENT_CLASS_NAME));
837 void forceGatewayTransportLink()
841 } // namespace NLNET