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/>.
19 #include "nel/net/service.h"
20 #include "nel/net/module.h"
21 #include "nel/net/module_manager.h"
22 #include "nel/net/inet_address.h"
23 #include "nel/net/module_message.h"
24 #include "nel/net/module_gateway.h"
25 #include "nel/net/module_socket.h"
32 using namespace NLMISC
;
33 using namespace NLNET
;
38 //////////////////////////////////////
39 // Module interceptor implementation
40 //////////////////////////////////////
41 IModuleInterceptable::IModuleInterceptable()
46 IModuleInterceptable::~IModuleInterceptable()
48 if (_Registrar
!= NULL
)
49 _Registrar
->unregisterInterceptor(this);
52 void IModuleInterceptable::registerInterceptor(IInterceptorRegistrar
*registrar
)
54 nlassert(registrar
!= NULL
);
56 _Registrar
= registrar
;
58 _Registrar
->registerInterceptor(this);
61 void IModuleInterceptable::interceptorUnregistered(IInterceptorRegistrar
*registrar
)
63 nlassert(registrar
== _Registrar
);
68 IInterceptorRegistrar
*IModuleInterceptable::getRegistrar()
74 //////////////////////////////////////
75 // Module factory implementation
76 //////////////////////////////////////
78 IModuleFactory::IModuleFactory(const std::string
&moduleClassName
)
79 : _ModuleClassName(moduleClassName
)
83 IModuleFactory::~IModuleFactory()
85 // Delete any module that still exist
86 while (!_ModuleInstances
.empty())
88 CRefPtr
<IModule
> sanityCheck(*(_ModuleInstances
.begin()));
90 IModuleManager::getInstance().deleteModule(sanityCheck
);
92 // container is cleared by deleteModule (see below)
93 // make sure the module is effectively destroyed
94 // NB : is the code assert here, this mean that some user code
95 // (or eventualy NeL code) have kept a smart pointer on the module
96 // and this is bad. All smart pointer MUST be released when the
97 // factory is about to be removed.
98 nlassertex(sanityCheck
== NULL
, ("Some code have kept pointer on module '%s'", sanityCheck
->getModuleName().c_str()));
101 // if the context is still active
102 if (INelContext::isContextInitialised() && IModuleManager::isInitialized())
103 // This factory is no longer available
104 IModuleManager::getInstance().unregisterModuleFactory(this);
107 const std::string
&IModuleFactory::getModuleClassName() const
109 return _ModuleClassName
;
113 void IModuleFactory::deleteModule(IModule
*module
)
115 set
<TModulePtr
>::iterator
it(_ModuleInstances
.find(module
));
116 nlassert(it
!= _ModuleInstances
.end());
118 CRefPtr
<IModule
> sanityCheck(module
);
120 // removing this smart ptr must release the module
121 _ModuleInstances
.erase(it
);
123 nlassert(sanityCheck
== NULL
);
126 void IModuleFactory::registerModuleInFactory(TModulePtr module
)
128 nlassert(module
!= NULL
);
130 nlassert(_ModuleInstances
.find(module
) == _ModuleInstances
.end());
132 // keep track of the module
133 _ModuleInstances
.insert(module
);
135 module
->setFactory(this);
138 //////////////////////////////////////
139 // CModuleTask implementation
140 //////////////////////////////////////
141 CModuleTask::CModuleTask (class CModuleBase
* /*module */)
144 // module->queueModuleTask(this);
148 void CModuleTask::initMessageQueue(CModuleBase
* /* module */)
152 void CModuleTask::flushMessageQueue(CModuleBase
*module
)
154 // process any queued message
155 while (!module
->_SyncMessages
.empty())
157 IModuleProxy
*proxy
= module
->_SyncMessages
.front().first
;
158 CMessage
&msg
= module
->_SyncMessages
.front().second
;
160 module
->_onProcessModuleMessage(proxy
, msg
);
162 module
->_SyncMessages
.pop_front();
166 void CModuleTask::processPendingMessage(CModuleBase
*module
)
168 flushMessageQueue(module
);
172 //////////////////////////////////////
173 // Module base implementation
174 //////////////////////////////////////
176 CModuleBase::CModuleBase()
177 : _CurrentSender(NULL
),
178 _CurrentMessage(NULL
),
179 _CurrentMessageFailed(false),
180 _MessageDispatchTask(NULL
),
181 _ModuleFactory(NULL
),
182 _ModuleId(INVALID_MODULE_ID
)
184 // register module itself in the interceptor list
185 IModuleInterceptable::registerInterceptor(this);
188 CModuleBase::~CModuleBase()
190 // deleting a module from it's own current task is forbiden
191 nlassert(_ModuleTasks
.empty()
192 || CCoTask::getCurrentTask() != _ModuleTasks
.front());
194 // terminate and release any pending module task
195 while (!_ModuleTasks
.empty())
197 CModuleTask
*task
= _ModuleTasks
.front();
199 // deleting the task will waiting it to terminate
202 _ModuleTasks
.erase(_ModuleTasks
.begin());
205 if (_MessageDispatchTask
)
207 // delete reception task
208 delete _MessageDispatchTask
;
211 // unregister all interceptors
212 while (!_ModuleInterceptors
.empty())
214 IModuleInterceptable
*interceptor
= *(_ModuleInterceptors
.begin());
215 unregisterInterceptor(interceptor
);
219 void CModuleBase::registerInterceptor(IModuleInterceptable
*interceptor
)
221 // check that this interceptor not already registered
222 nlassert(find(_ModuleInterceptors
.begin(), _ModuleInterceptors
.end(), interceptor
) == _ModuleInterceptors
.end());
224 // insert the interceptor in the list
225 _ModuleInterceptors
.push_back(interceptor
);
228 void CModuleBase::unregisterInterceptor(IModuleInterceptable
*interceptor
)
230 TInterceptors::iterator it
= find(_ModuleInterceptors
.begin(), _ModuleInterceptors
.end(), interceptor
);
231 nlassert(it
!= _ModuleInterceptors
.end());
233 _ModuleInterceptors
.erase(it
);
235 interceptor
->interceptorUnregistered(this);
238 TModuleId
CModuleBase::getModuleId() const
243 const std::string
&CModuleBase::getModuleName() const
248 const std::string
&CModuleBase::getModuleClassName() const
250 return _ModuleFactory
->getModuleClassName();
253 const std::string
&CModuleBase::getModuleFullyQualifiedName() const
255 if (_FullyQualifedModuleName
.empty())
257 nlassertex(!_ModuleName
.empty(), ("Call to CModuleBase::getModuleFullyQualifiedName before module name have been set (did you call from module constructor ?)"));
260 if (IService::isServiceInitialized())
261 hostName
= IService::getInstance()->getHostName();
263 hostName
= ::NLNET::CInetAddress::localHost().hostName();
264 // int pid = ::getpid();
266 _FullyQualifedModuleName
= IModuleManager::getInstance().getUniqueNameRoot()+":"+_ModuleName
;
269 return _FullyQualifedModuleName
;
272 std::string
CModuleBase::getModuleManifest() const
276 // call each interceptor in order to build the manifest
277 TInterceptors::const_iterator
first(_ModuleInterceptors
.begin()), last(_ModuleInterceptors
.end());
278 for (; first
!= last
; ++first
)
280 IModuleInterceptable
*interceptor
= *first
;
282 manifest
+= interceptor
->buildModuleManifest() + " ";
285 if (!manifest
.empty() && manifest
[manifest
.size()-1] == ' ')
286 manifest
.resize(manifest
.size()-1);
291 void CModuleBase::onReceiveModuleMessage(IModuleProxy
*senderModuleProxy
, const CMessage
&message
)
293 H_AUTO(CModuleBase_onReceiveModuleMessage
);
295 if (!_ModuleTasks
.empty())
297 // there is a task running, queue in the message
298 _SyncMessages
.push_back(make_pair(senderModuleProxy
, message
));
302 // go in user code for processing
303 if (_MessageDispatchTask
!= NULL
)
305 // process the message in the co task
306 _CurrentSender
= senderModuleProxy
;
307 _CurrentMessage
= &message
;
309 _MessageDispatchTask
->resume();
311 if (_CurrentMessageFailed
)
312 throw IModule::EInvokeFailed();
316 // normal processing by the main task
317 _onProcessModuleMessage(senderModuleProxy
, message
);
322 void CModuleBase::_receiveModuleMessageTask()
324 H_AUTO(CModuleBase__receiveModuleMessageTask
);
326 while (!_MessageDispatchTask
->isTerminationRequested())
328 // we have a message to dispatch
331 // take a copy of the message to dispatch
332 IModuleProxy
*currentSender
= _CurrentSender
;
333 CMessage currentMessage
= *_CurrentMessage
;
334 _onProcessModuleMessage(currentSender
, currentMessage
);
335 _CurrentMessageFailed
= false;
337 catch (const NLMISC::Exception
&e
)
339 nlwarning("In module task '%s' (cotask message receiver), exception '%e' thrown", typeid(this).name(), e
.what());
340 // an exception have been thrown
341 _CurrentMessageFailed
= true;
345 nlwarning("In module task '%s' (cotask message receiver), unknown exception thrown", typeid(this).name());
346 // an exception have been thrown
347 _CurrentMessageFailed
= true;
349 // switch to main task
350 _MessageDispatchTask
->yield();
355 void CModuleBase::queueModuleTask(CModuleTask
*task
)
357 _ModuleTasks
.push_back(task
);
360 CModuleTask
*CModuleBase::getActiveModuleTask()
362 if (_ModuleTasks
.empty())
365 return _ModuleTasks
.front();
369 const std::string
&CModuleBase::getInitStringHelp()
375 // Init base module, init module name
376 bool CModuleBase::initModule(const TParsedCommandLine
&initInfo
)
378 // read module init param for base module .
380 if (initInfo
.getParam("base.useCoTaskDispatch"))
382 // init the message dispatch task
383 // NLNET_START_MODULE_TASK(CModuleBase, _receiveModuleMessageTask);
384 // TModuleTask<className> *task = new TModuleTask<className>(this, &className::methodName);
385 _MessageDispatchTask
= new TModuleTask
<CModuleBase
>(this, TModuleTask
<CModuleBase
>::TMethodPtr(&CModuleBase::_receiveModuleMessageTask
));
388 // register this module in the command executor
389 registerCommandsHandler();
394 const std::string
&CModuleBase::getCommandHandlerName() const
396 return getModuleName();
400 void CModuleBase::plugModule(IModuleSocket
*moduleSocket
)
402 CModuleSocket
*sock
= dynamic_cast<CModuleSocket
*>(moduleSocket
);
403 nlassert(sock
!= NULL
);
405 TModuleSockets::iterator
it(_ModuleSockets
.find(moduleSocket
));
406 if (it
!= _ModuleSockets
.end())
407 throw EModuleAlreadyPluggedHere();
410 // ok, we can plug the module
412 sock
->_onModulePlugged(this);
414 // all fine, store the socket pointer.
415 _ModuleSockets
.insert(moduleSocket
);
418 void CModuleBase::unplugModule(IModuleSocket
*moduleSocket
)
420 CModuleSocket
*sock
= dynamic_cast<CModuleSocket
*>(moduleSocket
);
421 nlassert(sock
!= NULL
);
423 TModuleSockets::iterator
it(_ModuleSockets
.find(moduleSocket
));
424 if (it
== _ModuleSockets
.end())
425 throw EModuleNotPluggedHere();
427 sock
->_onModuleUnplugged(TModulePtr(this));
429 _ModuleSockets
.erase(it
);
432 void CModuleBase::getPluggedSocketList(std::vector
<IModuleSocket
*> &resultList
)
434 TModuleSockets::iterator
first(_ModuleSockets
.begin()), last(_ModuleSockets
.end());
435 for (; first
!= last
; ++first
)
437 resultList
.push_back(*first
);
441 /** Do a module operation invocation.
442 * Caller MUST be in a module task to call this method.
443 * The call is blocking until receptions of the operation
444 * result message (or a module down)
446 void CModuleBase::invokeModuleOperation(IModuleProxy
*destModule
, const NLNET::CMessage
&opMsg
, NLNET::CMessage
&resultMsg
)
448 H_AUTO(CModuleBase_invokeModuleOperation
);
450 nlassert(opMsg
.getType() == CMessage::Request
);
452 // check that we are running in a coroutine task
453 CModuleTask
*task
= dynamic_cast<CModuleTask
*>(CCoTask::getCurrentTask());
454 nlassert(task
!= NULL
);
455 // send the message to the module
456 destModule
->sendModuleMessage(this, opMsg
);
458 // fill the invoke stack
459 _InvokeStack
.push_back(destModule
);
463 // yield and wait for messages
466 if (task
->mustFailInvoke())
468 nlassert(!_InvokeStack
.empty());
469 // empty the invoke stack
470 _InvokeStack
.pop_back();
472 task
->resetFailInvoke();
474 throw EInvokeFailed();
477 while (!_SyncMessages
.empty())
479 IModuleProxy
*proxy
= _SyncMessages
.front().first
;
480 CMessage
&msg
= _SyncMessages
.front().second
;
481 if (msg
.getType() == CMessage::Response
)
483 // we have the response message
484 nlassert(proxy
== destModule
);
486 // remove this message form the queue
487 _SyncMessages
.pop_front();
488 // empty the invoke stack
489 _InvokeStack
.pop_back();
490 // stop reading received message now
493 else if (msg
.getType() == CMessage::Except
)
495 // the other side returned an exception !
497 // empty the invoke stack
498 _InvokeStack
.pop_back();
500 throw EInvokeFailed();
504 // another message, dispatch it normally
505 // CMessage::TMessageType msgType = msg.getType();
508 _onProcessModuleMessage(proxy
, msg
);
512 // nlwarning("Some exception where throw will dispatching message '%s' from '%s' to '%s'",
513 // msg.getName().c_str(),
514 // proxy->getModuleName().c_str(),
515 // this->getModuleName().c_str());
517 // if (msgType == CMessage::Request)
519 // // send back an exception message
521 // except.setType("EXCEPT", CMessage::Except);
522 // proxy->sendModuleMessage(this, except);
527 // remove this message form the queue
528 _SyncMessages
.pop_front();
534 void CModuleBase::_onModuleUp(IModuleProxy
*removedProxy
)
536 H_AUTO(CModuleBase__onModuleUp
);
538 // call the normal callback in the interceptor list
539 TInterceptors::iterator
first(_ModuleInterceptors
.begin()), last(_ModuleInterceptors
.end());
540 for (;first
!= last
; ++first
)
542 IModuleInterceptable
*interceptor
= *first
;
543 interceptor
->onModuleUp(removedProxy
);
547 void CModuleBase::_onModuleDown(IModuleProxy
*removedProxy
)
549 H_AUTO(CModuleBase__onModuleDown
);
551 // remove any message from the message queue that come from this proxy
553 TMessageList::iterator
first(_SyncMessages
.begin()), last(_SyncMessages
.end());
554 for (; first
!= last
; ++first
)
556 if (first
->first
== removedProxy
)
558 _SyncMessages
.erase(first
);
559 first
= _SyncMessages
.begin();
563 // check the invocation stack also
565 TInvokeStack::iterator
first(_InvokeStack
.begin()), last(_InvokeStack
.end());
566 for (; first
!= last
; ++first
)
568 if (*first
== removedProxy
)
570 // at least, we need either a running task or the default dispatch task activated
571 nlassert(!_ModuleTasks
.empty() || _MessageDispatchTask
!= NULL
);
573 // gasp, we lost one of the module needed to managed the invocation stack!
574 // make each call generate an exception
575 while (first
!= _InvokeStack
.end())
577 // The module task can be either the first in the module task list or
578 // the co routine dispatching task if it is activated
579 CModuleTask
*task
= !_ModuleTasks
.empty() ? _ModuleTasks
.front() : _MessageDispatchTask
;
581 // switch to task to unstack one level
589 // call the normal callback in the interceptor list
590 TInterceptors::iterator
first(_ModuleInterceptors
.begin()), last(_ModuleInterceptors
.end());
591 for (;first
!= last
; ++first
)
593 (*first
)->onModuleDown(removedProxy
);
597 bool CModuleBase::_onProcessModuleMessage(IModuleProxy
*senderModuleProxy
, const CMessage
&message
)
599 H_AUTO(CModuleBase__OnProcessModuleMessage
);
601 // try the call on each interceptor
607 TInterceptors::iterator
first(_ModuleInterceptors
.begin()), last(_ModuleInterceptors
.end());
608 for (;first
!= last
; ++first
)
610 if ((*first
)->onProcessModuleMessage(senderModuleProxy
, message
))
619 nlwarning("Some exception where throw will dispatching message '%s' from '%s' to '%s'",
620 message
.getName().c_str(),
621 senderModuleProxy
->getModuleName().c_str(),
622 this->getModuleName().c_str());
624 if (message
.getType() == CMessage::Request
)
626 // send back an exception message
628 except
.setType("EXCEPT", CMessage::Except
);
629 senderModuleProxy
->sendModuleMessage(this, except
);
631 // here we return true because the message have been processed
632 // (even if the processing have raised some exception !)
639 void CModuleBase::setFactory(IModuleFactory
*factory
)
641 nlassert(_ModuleFactory
== NULL
);
643 _ModuleFactory
= factory
;
646 IModuleFactory
*CModuleBase::getFactory()
648 return _ModuleFactory
;
651 NLMISC_CLASS_COMMAND_IMPL(CModuleBase
, plug
)
653 nlunreferenced(human
);
654 nlunreferenced(quiet
);
655 nlunreferenced(rawCommandString
);
657 if (args
.size() != 1)
660 IModuleSocket
*socket
= IModuleManager::getInstance().getModuleSocket(args
[0]);
664 log
.displayNL("Unknown socket named '%s'", args
[0].c_str());
670 if (_ModuleSockets
.find(socket
) == _ModuleSockets
.end())
672 log
.displayNL("Failed to plug the module '%s' into the socket '%s'",
673 getModuleName().c_str(),
674 socket
->getSocketName().c_str());
677 log
.displayNL("Module '%s' plugged into the socket '%s'",
678 getModuleName().c_str(),
679 socket
->getSocketName().c_str());
684 NLMISC_CLASS_COMMAND_IMPL(CModuleBase
, unplug
)
686 nlunreferenced(human
);
687 nlunreferenced(quiet
);
688 nlunreferenced(rawCommandString
);
690 if (args
.size() != 1)
693 IModuleSocket
*socket
= IModuleManager::getInstance().getModuleSocket(args
[0]);
697 log
.displayNL("Unknown socket named '%s'", args
[0].c_str());
701 if (_ModuleSockets
.find(socket
) == _ModuleSockets
.end())
703 log
.displayNL("The module '%s' is not plugged in the socket '%s'",
704 getModuleName().c_str(),
705 socket
->getSocketName().c_str());
709 unplugModule(socket
);
711 if (_ModuleSockets
.find(socket
) != _ModuleSockets
.end())
712 log
.displayNL("Failed to unplug the module '%s' from the socket '%s'",
713 getModuleName().c_str(),
714 socket
->getSocketName().c_str());
716 log
.displayNL("Module '%s' unplugged out of the socket '%s'",
717 getModuleName().c_str(),
718 socket
->getSocketName().c_str());
723 NLMISC_CLASS_COMMAND_IMPL(CModuleBase
, sendPing
)
725 nlunreferenced(human
);
726 nlunreferenced(quiet
);
727 nlunreferenced(rawCommandString
);
729 if (args
.size() != 1)
732 string modName
= args
[0];
734 // look in each socket
735 vector
<IModuleSocket
*> sockets
;
736 this->getPluggedSocketList(sockets
);
738 for (uint i
=0; i
<sockets
.size(); ++i
)
740 IModuleSocket
*socket
= sockets
[i
];
741 vector
<IModuleProxy
*> proxList
;
742 socket
->getModuleList(proxList
);
744 for (uint i
=0; i
<proxList
.size(); ++i
)
746 if (proxList
[i
]->getModuleName() == modName
)
749 CMessage
ping("DEBUG_MOD_PING");
750 proxList
[i
]->sendModuleMessage(this, ping
);
751 log
.displayNL("Ping debug message send to '%s'", modName
.c_str());
757 log
.displayNL("Can't find a route to send message to module '%s'", modName
.c_str());
762 NLMISC_CLASS_COMMAND_IMPL(CModuleBase
, dump
)
764 nlunreferenced(human
);
765 nlunreferenced(quiet
);
766 nlunreferenced(rawCommandString
);
768 if (args
.size() != 0)
771 log
.displayNL("---------------------------");
772 log
.displayNL("Dumping base module state :");
773 log
.displayNL("---------------------------");
774 log
.displayNL(" Module name : '%s'", getModuleName().c_str());
775 log
.displayNL(" Module full name : '%s'", getModuleFullyQualifiedName().c_str());
776 log
.displayNL(" Module class : '%s'", _ModuleFactory
->getModuleClassName().c_str());
777 log
.displayNL(" Module ID : %u", _ModuleId
);
778 log
.displayNL(" The module is plugged into %u sockets :", _ModuleSockets
.size());
780 TModuleSockets::iterator
first(_ModuleSockets
.begin()), last(_ModuleSockets
.end());
781 for (; first
!= last
; ++first
)
783 IModuleSocket
*ps
= *first
;
784 vector
<IModuleProxy
*> proxies
;
785 ps
->getModuleList(proxies
);
787 log
.displayNL(" Socket '%s', %u modules reachable :", ps
->getSocketName().c_str(), proxies
.size()-1);
789 for (uint i
=0; i
<proxies
.size(); ++i
)
791 string name
= proxies
[i
]->getModuleName();
792 if (name
.find('/') != string::npos
)
793 name
= name
.substr(name
.find('/')+1);
794 if (name
!= getModuleFullyQualifiedName())
796 log
.displayNL(" Module '%s' (Module Proxy ID : %u, class : '%s')",
797 proxies
[i
]->getModuleName().c_str(),
798 proxies
[i
]->getModuleProxyId(),
799 proxies
[i
]->getModuleClassName().c_str());
809 /************************************************************************
811 ************************************************************************/
813 CModuleProxy::CModuleProxy(TModulePtr localModule
, TModuleId localModuleId
, const std::string
&moduleClassName
, const std::string
&fullyQualifiedModuleName
, const std::string
&moduleManifest
)
814 : _ModuleProxyId(localModuleId
),
815 _ForeignModuleId(INVALID_MODULE_ID
),
816 _LocalModule(localModule
),
817 _ModuleClassName(CStringMapper::map(moduleClassName
)),
818 _FullyQualifiedModuleName(CStringMapper::map(fullyQualifiedModuleName
)),
819 _Manifest(moduleManifest
),
824 TModuleId
CModuleProxy::getModuleProxyId() const
826 return _ModuleProxyId
;
829 TModuleId
CModuleProxy::getForeignModuleId() const
831 return _ForeignModuleId
;
834 uint32
CModuleProxy::getModuleDistance() const
839 IModule
*CModuleProxy::getLocalModule() const
844 CGatewayRoute
*CModuleProxy::getGatewayRoute() const
849 const std::string
&CModuleProxy::getModuleName() const
851 return CStringMapper::unmap(_FullyQualifiedModuleName
);
853 const std::string
&CModuleProxy::getModuleClassName() const
855 return CStringMapper::unmap(_ModuleClassName
);
858 const std::string
&CModuleProxy::getModuleManifest() const
864 IModuleGateway
*CModuleProxy::getModuleGateway() const
869 void CModuleProxy::sendModuleMessage(IModule
*senderModule
, const NLNET::CMessage
&message
)
871 H_AUTO(CModuleProxy_sendModuleMessage
);
873 if (_Gateway
== NULL
)
875 throw EModuleNotReachable();
878 // We need to find the proxy for the sender using the addressee gateway
879 IModuleProxy
*senderProx
= _Gateway
->getPluggedModuleProxy(senderModule
);
880 if (senderProx
== NULL
)
882 throw EModuleNotReachable();
885 _Gateway
->sendModuleProxyMessage(senderProx
, this, message
);
888 const TSecurityData
*CModuleProxy::findSecurityData(uint8 dataTag
) const
890 const TSecurityData
*ms
= _SecurityData
;
894 if (ms
->DataTag
== dataTag
)
896 // this block match !