1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
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.
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/>.
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"
28 using namespace NLMISC
;
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
51 /// The id of the socket in the server
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
;
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
;
87 CGatewayL3ServerTransport(const IGatewayTransport::TCtorParam
¶m
)
88 : IGatewayTransport(param
)
92 ~CGatewayL3ServerTransport()
94 if (_CallbackServer
.get() != NULL
)
96 // the transport is still open, close it before destruction
101 const std::string
&getClassName() const
103 static string
className(LAYER3_SERVER_CLASS_NAME
);
107 virtual void 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.");
154 log
.displayNL(" The server is open on '%s' and support %u routes :",
155 _CallbackServer
->listenAddress().asString().c_str(),
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",
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();
206 fromString(portParam
->ParamValue
, port
);
210 else if (commandName
== "close")
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
);
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
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());
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
);
307 CL3ServerRoute
*route
= it
->second
;
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
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());
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
);
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
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
;
409 CL3ClientRoute(IGatewayTransport
*transport
, CInetAddress serverAddr
,uint32 connId
)
410 : CGatewayRoute(transport
),
411 ServerAddr(serverAddr
),
412 LastCommTime(CTime::getSecondsSince1970()),
413 LastConnectionRetry(0),
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
;
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
;
463 /// Default time interval (in seconds) between to reconnection attempts
465 /// A minimum value in case or configuration error
466 MIN_RETRY_INTERVAL
= 1,
470 CGatewayL3ClientTransport(const IGatewayTransport::TCtorParam
¶m
)
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
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
);
504 _RouteToRemove
.pop_front();
508 const std::string
&getClassName() const
510 static string
className(LAYER3_CLIENT_CLASS_NAME
);
514 virtual void 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
);
542 nlinfo("Server %s still not available for connection", route
->ServerAddr
.asString().c_str());
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",
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
);
632 else if (commandName
== "close")
634 const TParsedCommandLine
*conIdParam
= command
.getParam("connId");
635 if (conIdParam
== NULL
)
636 throw EInvalidCommand();
639 fromString(conIdParam
->ParamValue
, connId
);
643 else if (commandName
== "retryInterval")
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
);
658 /// connect to a server
659 void connect(CInetAddress
&addr
)
664 // affect a connection id
665 if (_FreeRoutesIds
.empty())
667 connId
= (uint32
)_RouteIds
.size();
668 _RouteIds
.push_back(InvalidSockId
);
672 connId
= (uint32
)_FreeRoutesIds
.back();
673 _FreeRoutesIds
.pop_back();
676 CUniquePtr
<CL3ClientRoute
> route(new CL3ClientRoute(this, addr
, connId
));
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
);
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
)
714 // some basic checks on connId
715 if (connId
>= _RouteIds
.size())
717 nlwarning("CGatewayL3ClientTransport : Invalid connectionId %u, max is %u", connId
, _RouteIds
.size()-1);
721 if (_RouteIds
[connId
] == NULL
)
723 nlwarning("CGatewayL3ClientTransport : Invalid connectionId %u, the connection is unused now.", connId
);
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())
742 _Gateway
->onRouteRemoved(route
);
744 // close the connection
745 route
->CallbackClient
.disconnect();
748 // cleanup memory, index ...
749 _DispatcherIndex
.erase(&(route
->CallbackClient
));
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
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());
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()