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 * Limitations: Not threadsafe, not reentrant.
27 #include "nel/misc/types_nl.h"
28 #include "nel/misc/debug.h"
29 #include "nel/misc/entity_id.h"
30 #include "nel/misc/sheet_id.h"
32 #include "nel/net/unified_network.h"
34 #include "nel/net/transport_class.h"
45 using namespace NLMISC
;
46 using namespace NLNET
;
54 NLMISC::CVariable
<bool> VerboseNETTC("nel","VerboseNETTC","Enable verbose logging in CTransportClass operations",true,0,true);
61 uint
CTransportClass::Mode
= 0; // 0=nothing 1=read 2=write 3=register
63 map
<string
, CTransportClass::CRegisteredClass
> CTransportClass::LocalRegisteredClass
; // registered class that are in my program
65 CTransportClass::CRegisteredClass
CTransportClass::TempRegisteredClass
;
67 NLNET::CMessage
CTransportClass::TempMessage
;
69 vector
<CTransportClass::CRegisteredBaseProp
*> CTransportClass::DummyProp
;
71 bool CTransportClass::Init
= false;
78 string
typeToString (CTransportClass::TProp type
)
81 "PropUInt8", "PropUInt16", "PropUInt32", "PropUInt64",
82 "PropSInt8", "PropSInt16", "PropSInt32", "PropSInt64",
83 "PropBool", "PropFloat", "PropDouble", "PropString", "PropDataSetRow", "PropSheetId", "PropUCString", "PropUKN" };
84 // "PropBool", "PropFloat", "PropDouble", "PropString", "PropDataSetRow", "PropEntityId", "PropSheetId", "PropUKN" };
86 if (type
> CTransportClass::PropUKN
)
87 return "<InvalidType>";
91 void CTransportClass::displayDifferentClass (TServiceId sid
, const string
&className
, const vector
<CRegisteredBaseProp
> &otherClass
, const vector
<CRegisteredBaseProp
*> &myClass
)
93 NETTC_INFO ("NETTC: Service with sid %hu send me the TransportClass '%s' with differents properties:", sid
.get(), className
.c_str());
94 NETTC_INFO ("NETTC: My local TransportClass is:");
95 for (uint i
= 0; i
< myClass
.size(); i
++)
97 NETTC_INFO ("NETTC: Property: %d Name: '%s' type: '%s'", i
, myClass
[i
]->Name
.c_str(), typeToString(myClass
[i
]->Type
).c_str());
100 NETTC_INFO ("NETTC: The other side TransportClass is:");
101 for (uint i
= 0; i
< otherClass
.size(); i
++)
103 NETTC_INFO ("NETTC: Property: %d Name: '%s' type: '%s'", i
, otherClass
[i
].Name
.c_str(), typeToString(otherClass
[i
].Type
).c_str());
107 void CTransportClass::registerOtherSideClass (TServiceId sid
, TOtherSideRegisteredClass
&osrc
)
109 for (TOtherSideRegisteredClass::iterator it
= osrc
.begin(); it
!= osrc
.end (); it
++)
111 // find the class name in the map
113 TRegisteredClass::iterator res
= LocalRegisteredClass
.find ((*it
).first
);
114 if (res
== LocalRegisteredClass
.end ())
116 // The other service knows a class that we don't
117 // there was previously an nlwarning here but that was wrong because it is quite normal for this to happen when one service
118 // ueses different transport classes to communicate with several different services, so the message has been changed to an nldebug
119 NETTC_DEBUG ("NETTC: the other side class '%s' declared from service %d is not registered in my system, skip it", (*it
).first
.c_str(),(uint32
)sid
.get());
123 if (sid
.get() >= (*res
).second
.Instance
->States
.size ())
124 (*res
).second
.Instance
->States
.resize (sid
.get()+1);
126 (*res
).second
.Instance
->States
[sid
.get()].clear ();
128 for (sint j
= 0; j
< (sint
)(*it
).second
.size (); j
++)
130 // check each prop to see the correspondance
132 // try to find the prop name in the array
134 for (k
= 0; k
< (*res
).second
.Instance
->Prop
.size(); k
++)
136 if ((*it
).second
[j
].Name
== (*res
).second
.Instance
->Prop
[k
]->Name
)
138 if ((*it
).second
[j
].Type
!= (*res
).second
.Instance
->Prop
[k
]->Type
)
140 nlwarning ("NETTC: Property '%s' of the class '%s' have not the same type in the 2 sides (%s %s)", (*it
).second
[j
].Name
.c_str(), (*it
).first
.c_str(), typeToString((*it
).second
[j
].Type
).c_str(), typeToString((*res
).second
.Instance
->Prop
[k
]->Type
).c_str());
145 if (k
== (*res
).second
.Instance
->Prop
.size())
148 (*res
).second
.Instance
->States
[sid
.get()].push_back (make_pair (-1, (*it
).second
[j
].Type
));
152 // same, store the index
153 (*res
).second
.Instance
->States
[sid
.get()].push_back (make_pair (k
, PropUKN
));
157 // check if the version are the same
158 if ((*it
).second
.size () != (*res
).second
.Instance
->Prop
.size ())
160 // 2 class don't have the same number of prop => different class => display class
161 displayDifferentClass (sid
, (*it
).first
.c_str(), (*it
).second
, (*res
).second
.Instance
->Prop
);
165 // check if the prop are same
166 for (uint i
= 0; i
< (*res
).second
.Instance
->Prop
.size (); i
++)
168 if ((*res
).second
.Instance
->Prop
[i
]->Name
!= (*it
).second
[i
].Name
)
170 // different name => different class => display class
171 displayDifferentClass (sid
, (*it
).first
.c_str(), (*it
).second
, (*res
).second
.Instance
->Prop
);
174 else if ((*res
).second
.Instance
->Prop
[i
]->Type
!= (*it
).second
[i
].Type
)
176 // different type => different class => display class
177 displayDifferentClass (sid
, (*it
).first
.c_str(), (*it
).second
, (*res
).second
.Instance
->Prop
);
184 displayLocalRegisteredClass ();
188 void CTransportClass::registerClass (CTransportClass
&instance
)
191 nlassert (Mode
== 0);
193 // set the mode to register
196 // clear the current class
197 TempRegisteredClass
.clear ();
199 // set the instance pointer
200 TempRegisteredClass
.Instance
= &instance
;
202 // fill name and props
203 TempRegisteredClass
.Instance
->description ();
205 // add the new registered class in the array
206 LocalRegisteredClass
[TempRegisteredClass
.Instance
->Name
] = TempRegisteredClass
;
212 void CTransportClass::unregisterClass ()
214 for (TRegisteredClass::iterator it
= LocalRegisteredClass
.begin(); it
!= LocalRegisteredClass
.end (); it
++)
216 for (uint j
= 0; j
< (*it
).second
.Instance
->Prop
.size (); j
++)
218 delete (*it
).second
.Instance
->Prop
[j
];
220 (*it
).second
.Instance
->Prop
.clear ();
221 (*it
).second
.Instance
= NULL
;
223 LocalRegisteredClass
.clear ();
226 void CTransportClass::displayLocalRegisteredClass (CRegisteredClass
&c
)
228 NETTC_DEBUG ("NETTC: > %s", c
.Instance
->Name
.c_str());
229 for (uint j
= 0; j
< c
.Instance
->Prop
.size (); j
++)
231 NETTC_DEBUG ("NETTC: > %s %s", c
.Instance
->Prop
[j
]->Name
.c_str(), typeToString(c
.Instance
->Prop
[j
]->Type
).c_str());
234 for (uint l
= 0; l
< c
.Instance
->States
.size (); l
++)
236 if (c
.Instance
->States
[l
].size () != 0)
238 NETTC_DEBUG ("NETTC: > sid: %u", l
);
239 for (uint k
= 0; k
< c
.Instance
->States
[l
].size (); k
++)
241 NETTC_DEBUG ("NETTC: - %d type : %s", c
.Instance
->States
[l
][k
].first
, typeToString(c
.Instance
->States
[l
][k
].second
).c_str());
247 void CTransportClass::displayLocalRegisteredClass ()
249 NETTC_DEBUG ("NETTC:> LocalRegisteredClass:");
250 for (TRegisteredClass::iterator it
= LocalRegisteredClass
.begin(); it
!= LocalRegisteredClass
.end (); it
++)
252 displayLocalRegisteredClass ((*it
).second
);
256 void cbTCReceiveMessage (CMessage
&msgin
, const string
&name
, TServiceId sid
)
258 NETTC_DEBUG ("NETTC: cbReceiveMessage");
260 CTransportClass::TempMessage
.clear();
261 CTransportClass::TempMessage
.assignFromSubMessage( msgin
);
264 CTransportClass::readHeader(CTransportClass::TempMessage
, className
);
266 CTransportClass::TRegisteredClass::iterator it
= CTransportClass::LocalRegisteredClass
.find (className
);
267 if (it
== CTransportClass::LocalRegisteredClass
.end ())
269 nlwarning ("NETTC: Receive unknown transport class '%s' received from %s-%hu", className
.c_str(), name
.c_str(), sid
.get());
273 nlassert ((*it
).second
.Instance
!= NULL
);
275 if (!(*it
).second
.Instance
->read (name
, sid
))
277 nlwarning ("NETTC: Can't read the transportclass '%s' received from %s-%hu (probably not registered on sender service)", className
.c_str(), name
.c_str(), sid
.get());
281 void cbTCReceiveOtherSideClass (CMessage
&msgin
, const string
&/* name */, TServiceId sid
)
283 NETTC_DEBUG ("NETTC: cbReceiveOtherSideClass");
285 CTransportClass::TOtherSideRegisteredClass osrc
;
288 msgin
.serial (nbClass
);
290 NETTC_DEBUG ("NETTC: %d class", nbClass
);
292 for (uint i
= 0; i
< nbClass
; i
++)
295 msgin
.serial (className
);
297 osrc
.push_back(make_pair (className
, vector
<CTransportClass::CRegisteredBaseProp
>()));
300 msgin
.serial (nbProp
);
302 NETTC_DEBUG ("NETTC: %s (%d prop)", className
.c_str(), nbProp
);
304 for (uint j
= 0; j
< nbProp
; j
++)
306 CTransportClass::CRegisteredBaseProp prop
;
307 msgin
.serial (prop
.Name
);
308 msgin
.serialEnum (prop
.Type
);
309 NETTC_DEBUG ("NETTC: %s %s", prop
.Name
.c_str(), typeToString(prop
.Type
).c_str());
310 osrc
[osrc
.size()-1].second
.push_back (prop
);
314 // we have the good structure
315 CTransportClass::registerOtherSideClass (sid
, osrc
);
318 static TUnifiedCallbackItem CallbackArray
[] =
320 { "CT_LRC", cbTCReceiveOtherSideClass
},
321 { "CT_MSG", cbTCReceiveMessage
},
324 void cbTCUpService (const std::string
&serviceName
, TServiceId sid
, void * /* arg */)
326 NETTC_DEBUG ("NETTC: CTransportClass Service %s %hu is up", serviceName
.c_str(), sid
.get());
327 if (sid
.get() >= 256)
329 CTransportClass::sendLocalRegisteredClass (sid
);
332 void CTransportClass::init ()
334 // this isn't an error!
337 CUnifiedNetwork::getInstance()->addCallbackArray (CallbackArray
, sizeof (CallbackArray
) / sizeof (CallbackArray
[0]));
339 // create an instance of all d'ifferent prop types
341 DummyProp
.resize (PropUKN
);
343 nlassert (PropUInt8
< PropUKN
); DummyProp
[PropUInt8
] = new CTransportClass::CRegisteredProp
<uint8
>;
344 nlassert (PropUInt16
< PropUKN
); DummyProp
[PropUInt16
] = new CTransportClass::CRegisteredProp
<uint16
>;
345 nlassert (PropUInt32
< PropUKN
); DummyProp
[PropUInt32
] = new CTransportClass::CRegisteredProp
<uint32
>;
346 nlassert (PropUInt64
< PropUKN
); DummyProp
[PropUInt64
] = new CTransportClass::CRegisteredProp
<uint64
>;
347 nlassert (PropSInt8
< PropUKN
); DummyProp
[PropSInt8
] = new CTransportClass::CRegisteredProp
<sint8
>;
348 nlassert (PropSInt16
< PropUKN
); DummyProp
[PropSInt16
] = new CTransportClass::CRegisteredProp
<sint16
>;
349 nlassert (PropSInt32
< PropUKN
); DummyProp
[PropSInt32
] = new CTransportClass::CRegisteredProp
<sint32
>;
350 nlassert (PropSInt64
< PropUKN
); DummyProp
[PropSInt64
] = new CTransportClass::CRegisteredProp
<sint64
>;
351 nlassert (PropBool
< PropUKN
); DummyProp
[PropBool
] = new CTransportClass::CRegisteredProp
<bool>;
352 nlassert (PropFloat
< PropUKN
); DummyProp
[PropFloat
] = new CTransportClass::CRegisteredProp
<float>;
353 nlassert (PropDouble
< PropUKN
); DummyProp
[PropDouble
] = new CTransportClass::CRegisteredProp
<double>;
354 nlassert (PropString
< PropUKN
); DummyProp
[PropString
] = new CTransportClass::CRegisteredProp
<string
>;
355 // nlassert (PropDataSetRow < PropUKN); DummyProp[PropDataSetRow] = new CTransportClass::CRegisteredProp<TDataSetRow>;
356 // nlassert (PropEntityId < PropUKN); DummyProp[PropEntityId] = new CTransportClass::CRegisteredProp<CEntityId>;
357 nlassert (PropSheetId
< PropUKN
); DummyProp
[PropSheetId
] = new CTransportClass::CRegisteredProp
<CSheetId
>;
358 nlassert (PropUCString
< PropUKN
); DummyProp
[PropUCString
] = new CTransportClass::CRegisteredProp
<ucstring
>;
360 // we have to know when a service comes, so add callback (put the callback before all other one because we have to send this message first)
361 CUnifiedNetwork::getInstance()->setServiceUpCallback("*", cbTCUpService
, NULL
, false);
366 void CTransportClass::release ()
370 for (uint i
= 0; i
< DummyProp
.size (); i
++)
377 void CTransportClass::createLocalRegisteredClassMessage ()
379 TempMessage
.clear ();
380 if (TempMessage
.isReading())
381 TempMessage
.invert();
382 TempMessage
.setType ("CT_LRC");
384 uint32 nbClass
= (uint32
)LocalRegisteredClass
.size ();
385 TempMessage
.serial (nbClass
);
387 for (TRegisteredClass::iterator it
= LocalRegisteredClass
.begin(); it
!= LocalRegisteredClass
.end (); it
++)
389 nlassert ((*it
).first
== (*it
).second
.Instance
->Name
);
391 TempMessage
.serial ((*it
).second
.Instance
->Name
);
393 uint32 nbProp
= (uint32
)(*it
).second
.Instance
->Prop
.size ();
394 TempMessage
.serial (nbProp
);
396 for (uint j
= 0; j
< (*it
).second
.Instance
->Prop
.size (); j
++)
398 // send the name and the type of the prop
399 TempMessage
.serial ((*it
).second
.Instance
->Prop
[j
]->Name
);
400 TempMessage
.serialEnum ((*it
).second
.Instance
->Prop
[j
]->Type
);
407 * Get the name of message (for displaying), or extract the class name if it is a transport class.
410 * - msgin is an input message that contains a valid message
413 * - the pos in msgin was modified
414 * - msgName contains "msg %s" or "transport class %s" where %s is the name of message, or the name
415 * transport class is the message is a CT_MSG.
417 void getNameOfMessageOrTransportClass( NLNET::CMessage
& msgin
, std::string
& msgName
)
419 if ( msgin
.getName() == "CT_MSG" )
423 msgin
.seek( msgin
.getHeaderSize(), NLMISC::IStream::begin
);
424 msgin
.serial( msgName
);
426 catch (const EStreamOverflow
&)
428 msgName
= "<Name not found>";
430 msgName
= "transport class " + msgName
;
434 msgName
= "msg " + msgin
.getName();