iop_simplenet.cppGo to the documentation of this file.00001 /** @file iop_simplenet.cpp Simple networked events via tcp/ip */ 00002 00003 /* 00004 FAU Discrete Event Systems Library (libfaudes) 00005 00006 Copyright (C) 2008, Thomas Moor 00007 Exclusive copyright is granted to Klaus Schmidt 00008 00009 */ 00010 00011 00012 00013 #include "iop_simplenet.h" 00014 00015 00016 namespace faudes { 00017 00018 00019 /* 00020 ********************************************** 00021 ********************************************** 00022 ********************************************** 00023 00024 implementation: SimplenetAddress 00025 00026 ********************************************** 00027 ********************************************** 00028 ********************************************** 00029 */ 00030 00031 // std faudes 00032 FAUDES_TYPE_IMPLEMENTATION(SimplenetDevice,nDevice,vDevice) 00033 00034 // construct 00035 SimplenetAddress::SimplenetAddress(void) { 00036 mIp=""; 00037 mPort=-1; 00038 } 00039 00040 // copy construct 00041 SimplenetAddress::SimplenetAddress(const SimplenetAddress& rOther) { 00042 mIp=rOther.mIp; 00043 mPort=rOther.mPort; 00044 } 00045 00046 // construct from string 00047 SimplenetAddress::SimplenetAddress(const std::string& rString) { 00048 IpColonPort(rString); 00049 } 00050 00051 // validity 00052 bool SimplenetAddress::Valid(void) const { 00053 if(mPort<=0) return false; 00054 if(mIp=="") return false; 00055 if(mIp.find(':',0)!=std::string::npos) return false; 00056 return true; 00057 } 00058 00059 // get colon seperated string 00060 std::string SimplenetAddress::IpColonPort(void) const { 00061 std::string res; 00062 if(!Valid()) return res; 00063 res=mIp+":"+ToStringInteger(mPort); 00064 return res; 00065 } 00066 00067 // Set from colon seperated string 00068 void SimplenetAddress::IpColonPort(std::string ipcolonport) { 00069 FD_DHV("SimplenetAddress::IpColonPort(): " << ipcolonport << " --> ?"); 00070 // invalid 00071 mIp=""; 00072 mPort=-1; 00073 // find colon 00074 std::size_t cpos = ipcolonport.find(':',0); 00075 if(cpos==std::string::npos) return; 00076 if(cpos==0) return; 00077 if(cpos+1>= ipcolonport.length()) return; 00078 // extract ip 00079 mIp=ipcolonport.substr(0,cpos); 00080 // extract port 00081 mPort=ToIdx(ipcolonport.substr(cpos+1)); 00082 // report 00083 FD_DHV("SimplenetAddress::IpColonPort(): " << ipcolonport << " --> " << IpColonPort()); 00084 // test for errors (might be too strict) 00085 if(IpColonPort()!=ipcolonport) { 00086 mIp=""; 00087 mPort=-1; 00088 } 00089 } 00090 00091 // sorting 00092 bool SimplenetAddress::operator < (const SimplenetAddress& rOther) const { 00093 if(this->mIp < rOther.mIp) return true; 00094 if(this->mIp > rOther.mIp) return false; 00095 if(this->mPort < rOther.mPort) return true; 00096 return false; 00097 } 00098 00099 00100 // only compile for simplenet support 00101 #ifdef FAUDES_IODEVICE_SIMPLENET 00102 00103 /* 00104 ********************************************** 00105 ********************************************** 00106 ********************************************** 00107 00108 implementation: AttributeSimplenetOutput 00109 00110 ********************************************** 00111 ********************************************** 00112 ********************************************** 00113 */ 00114 00115 // std faudes type 00116 FAUDES_TYPE_IMPLEMENTATION(Void,AttributeSimplenetOutput,AttributeVoid) 00117 00118 00119 //DoWrite(rTw); 00120 void AttributeSimplenetOutput::DoWrite(TokenWriter& rTw, const std::string& rLabel, const Type* pContext) const { 00121 (void) rLabel; (void) pContext; 00122 } 00123 00124 00125 //DoRead(rTr) 00126 void AttributeSimplenetOutput::DoRead(TokenReader& rTr, const std::string& rLabel, const Type* pContext) { 00127 (void) rLabel; (void) pContext; 00128 // report 00129 FD_DHV("AttributeSimplenetOutput(" << this << ")::DoRead(tr)"); 00130 00131 // sense and digest pre 2.16 format 00132 Token token; 00133 rTr.Peek(token); 00134 if(token.Type()==Token::Begin) 00135 if(token.StringValue()=="Output") { 00136 rTr.ReadBegin("Output"); 00137 rTr.ReadEnd("Output"); 00138 } 00139 } 00140 00141 00142 /* 00143 ********************************************** 00144 ********************************************** 00145 ********************************************** 00146 00147 implementation: AttributeSimplenetInput 00148 00149 ********************************************** 00150 ********************************************** 00151 ********************************************** 00152 */ 00153 00154 00155 // std faudes type 00156 FAUDES_TYPE_IMPLEMENTATION(Void,AttributeSimplenetInput,AttributeVoid) 00157 00158 00159 //DoWrite(rTw); 00160 void AttributeSimplenetInput::DoWrite(TokenWriter& rTw, const std::string& rLabel, const Type* pContext) const { 00161 (void) rLabel; (void) pContext; 00162 } 00163 00164 00165 //DoRead(rTr) 00166 void AttributeSimplenetInput::DoRead(TokenReader& rTr, const std::string& rLabel, const Type* pContext) { 00167 (void) rLabel; (void) pContext; 00168 // report 00169 FD_DHV("AttributeSimplenetInput(" << this << ")::DoRead(tr)"); 00170 00171 // sense and digest pre 2.16 format 00172 Token token; 00173 rTr.Peek(token); 00174 if(token.Type()==Token::Begin) 00175 if(token.StringValue()=="Input") { 00176 rTr.ReadBegin("Input"); 00177 rTr.ReadEnd("Input"); 00178 } 00179 } 00180 00181 00182 00183 00184 /* 00185 ********************************************** 00186 ********************************************** 00187 ********************************************** 00188 00189 implementation: AttributeSimplenetEvent 00190 00191 ********************************************** 00192 ********************************************** 00193 ********************************************** 00194 */ 00195 00196 00197 00198 // std faudes type 00199 FAUDES_TYPE_IMPLEMENTATION(Void,AttributeSimplenetEvent,AttributeDeviceEvent) 00200 00201 // Default constructor, set my prototypes 00202 AttributeSimplenetEvent::AttributeSimplenetEvent(void) : AttributeDeviceEvent() { 00203 FD_DHV("AttributeSimplenetEvent::AttributeSimplenetEvent(" << this << ")");; 00204 pOutputPrototype=OutputPrototypep(); 00205 pInputPrototype=InputPrototypep(); 00206 } 00207 00208 // Copy constructor 00209 AttributeSimplenetEvent::AttributeSimplenetEvent(const AttributeSimplenetEvent& rOtherAttr) : 00210 AttributeDeviceEvent() 00211 { 00212 FD_DHV("AttributeSimplenetEvent(" << this << "): form other attr " << &rOtherAttr); 00213 pOutputPrototype=OutputPrototypep(); 00214 pInputPrototype=InputPrototypep(); 00215 DoAssign(rOtherAttr); 00216 } 00217 00218 00219 // pseudo statics 00220 const AttributeSimplenetOutput* AttributeSimplenetEvent::OutputPrototypep(void){ 00221 AttributeSimplenetOutput* attrp= new AttributeSimplenetOutput(); 00222 return attrp; 00223 } 00224 00225 // pseudo statics 00226 const AttributeSimplenetInput* AttributeSimplenetEvent::InputPrototypep(void) { 00227 AttributeSimplenetInput* attrp= new AttributeSimplenetInput(); 00228 return attrp; 00229 } 00230 00231 00232 /* 00233 ********************************************** 00234 ********************************************** 00235 ********************************************** 00236 00237 implementation: nDevice 00238 00239 ********************************************** 00240 ********************************************** 00241 ********************************************** 00242 */ 00243 00244 // autoregister 00245 AutoRegisterType<nDevice> gRtiRegisterSimplenetDevice("SimplenetDevice"); 00246 00247 // helper: send entire buffer 00248 int syncSend(int dest, const char* data, int len, int flag) { 00249 int from=0; 00250 int left=len; 00251 while(left>0) { 00252 int rc=send(dest, data+from, left, 0); 00253 if(rc<0) { 00254 std::stringstream errstr; 00255 errstr << "Simplenet fatal network error (cannot send message)"; 00256 throw Exception("nDevice::syncSend", errstr.str(), 553, true); // mute console out 00257 } 00258 left-=rc; 00259 } 00260 return len; 00261 } 00262 00263 00264 // constructor 00265 nDevice::nDevice(void) : vDevice() { 00266 FD_DHV("nDevice(" << this << ")::nDevice()"); 00267 mpConfiguration = new TaNameSet<AttributeSimplenetEvent>; 00268 pConfiguration = dynamic_cast< TaNameSet<AttributeSimplenetEvent>* >(mpConfiguration); 00269 // default token section 00270 mDefaultLabel="SimplenetDevice"; 00271 // default network data 00272 mName="SimplenetNode"; 00273 mNetwork="Simplenet"; 00274 mListenAddress.IpColonPort("localhost:40000"); 00275 mBroadcastAddress.IpColonPort("255.255.255.255:40000"); 00276 // clear/prepare state 00277 faudes_mutex_init(&mMutex); 00278 mListenSocket=-1; 00279 mBroadcastSocket=-1; 00280 } 00281 00282 // destructor 00283 nDevice::~nDevice(void) { 00284 FD_DHV("nDevice(" << this << ")::~nDevice()"); 00285 // stop 00286 Stop(); 00287 // clean up my data 00288 faudes_mutex_destroy(&mMutex); 00289 } 00290 00291 // clear all configuration 00292 void nDevice::Clear(void) { 00293 FD_DHV("nDevice(" << this << ")::Clear()"); 00294 // call base, incl stop 00295 vDevice::Clear(); 00296 // clear compiled data 00297 mInputSubscriptions.clear(); 00298 } 00299 00300 00301 // programmatic config: server address 00302 void nDevice::ServerAddress(const std::string& rAddr) { 00303 if(mState!=Down) return; 00304 mListenAddress.IpColonPort(rAddr); 00305 } 00306 00307 // programmatic config: broadcast address 00308 void nDevice::BroadcastAddress(const std::string& rAddr) { 00309 if(mState!=Down) return; 00310 mBroadcastAddress.IpColonPort(rAddr); 00311 } 00312 00313 00314 // programmatic config: network name 00315 void nDevice::NetworkName(const std::string& rNetwork) { 00316 if(mState!=Down) return; 00317 mNetwork=rNetwork; 00318 } 00319 00320 // programmatic config: insert node name 00321 void nDevice::InsNode(const std::string& rNodeName) { 00322 if(mState!=Down) return; 00323 mNetworkNodes[rNodeName]="unknown:0"; 00324 } 00325 00326 // programmatic config: insert node address 00327 void nDevice::InsNodeAddress(const std::string& rNodeName, const std::string& rNodeAddress) { 00328 if(mState!=Down) return; 00329 mNetworkNodes[rNodeName]=rNodeAddress; 00330 } 00331 00332 // programmatic config: clear known nodes 00333 void nDevice::ClearNodes(void) { 00334 if(mState!=Down) return; 00335 mNetworkNodes.clear(); 00336 } 00337 00338 // programmatic config: insert input event 00339 void nDevice::InsInputEvent(const std::string& event) { 00340 if(mState!=Down) return; 00341 AttributeSimplenetEvent inp; 00342 inp.DefaultInput(); 00343 Idx ev=pConfiguration->Insert(event); 00344 pConfiguration->Attribute(ev, inp); 00345 } 00346 00347 // programmatic config: insert output event 00348 void nDevice::InsOutputEvent(const std::string& event) { 00349 if(mState!=Down) return; 00350 AttributeSimplenetEvent outp; 00351 outp.DefaultOutput(); 00352 Idx ev=pConfiguration->Insert(event); 00353 pConfiguration->Attribute(ev, outp); 00354 } 00355 00356 00357 //Compile(void) 00358 void nDevice::Compile(void){ 00359 //setup up internal data structure 00360 FD_DHV("nDevice(" << this << ")::Compile()"); 00361 // call base 00362 vDevice::Compile(); 00363 } 00364 00365 00366 //DoWritePreface(rTr,rLabel) 00367 void nDevice::DoWritePreface(TokenWriter& rTw, const std::string& rLabel, const Type* pContext) const { 00368 FD_DHV("nDevice::DoWrite()"); 00369 //call base 00370 vDevice::DoWritePreface(rTw,rLabel,pContext); 00371 // write my data: my server role ip address 00372 Token vtag; 00373 vtag.SetEmpty("ServerAddress"); 00374 vtag.InsAttributeString("value",mListenAddress.IpColonPort()); 00375 rTw<<vtag; 00376 // write my data: my server broadcast address 00377 Token btag; 00378 btag.SetEmpty("BroadcastAddress"); 00379 btag.InsAttributeString("value",mBroadcastAddress.IpColonPort()); 00380 rTw<<btag; 00381 // write my data network topology 00382 Token ntag; 00383 ntag.SetBegin("Network"); 00384 ntag.InsAttributeString("name",mNetwork); 00385 rTw<<ntag; 00386 std::map<std::string,std::string>::const_iterator nit; 00387 for(nit=mNetworkNodes.begin();nit!=mNetworkNodes.end();nit++) { 00388 vtag.SetEmpty("Node"); 00389 vtag.InsAttributeString("name",nit->first); 00390 SimplenetAddress defaddress(nit->second); 00391 if(defaddress.Valid()) 00392 vtag.InsAttributeString("address",nit->second); 00393 rTw<<vtag; 00394 } 00395 rTw.WriteEnd("Network"); 00396 } 00397 00398 //DoRead(rTr,rLabel) 00399 void nDevice::DoReadPreface(TokenReader& rTr, const std::string& rLabel, const Type* pContext) { 00400 FD_DHV("nDevice::DoReadPreface()"); 00401 // call base (reads name and timescale) 00402 vDevice::DoReadPreface(rTr,rLabel,pContext); 00403 00404 // sense and digest pre 2.16 format 00405 Token token; 00406 rTr.Peek(token); 00407 if(token.IsString()) { 00408 mListenAddress.IpColonPort(rTr.ReadString()); 00409 if(!mListenAddress.Valid()) { 00410 std::stringstream errstr; 00411 errstr << "Simplenet address expected at " << rTr.FileLine(); 00412 throw Exception("nDevice::DoRead", errstr.str(), 50); 00413 } 00414 mNetwork=rTr.ReadString(); 00415 mNetworkNodes.clear(); 00416 rTr.ReadBegin("Network"); 00417 while(!rTr.Eos("Network")) { 00418 mNetworkNodes[rTr.ReadString()]="unknown:0"; 00419 } 00420 rTr.ReadEnd("Network"); 00421 return; 00422 } 00423 00424 // read my data: server address 00425 Token atag; 00426 rTr.ReadBegin("ServerAddress",atag); 00427 mListenAddress.IpColonPort(atag.AttributeStringValue("value")); 00428 if(!mListenAddress.Valid()) { 00429 std::stringstream errstr; 00430 errstr << "Simplenet address expected at " << rTr.FileLine(); 00431 throw Exception("nDevice::DoRead", errstr.str(), 50); 00432 } 00433 rTr.ReadEnd("ServerAddress"); 00434 // read my data: broadcast address (optional) 00435 mBroadcastAddress.IpColonPort("255.255.255.255:40000"); 00436 rTr.Peek(token); 00437 if(token.IsBegin("BroadcastAddress")) { 00438 rTr.ReadBegin("BroadcastAddress",atag); 00439 mBroadcastAddress.IpColonPort(atag.AttributeStringValue("value")); 00440 if(!mBroadcastAddress.Valid()) { 00441 std::stringstream errstr; 00442 errstr << "Simplenet address expected at " << rTr.FileLine(); 00443 throw Exception("nDevice::DoRead", errstr.str(), 50); 00444 } 00445 rTr.ReadEnd("BroadcastAddress"); 00446 } 00447 // read my data: network 00448 Token ntag; 00449 rTr.ReadBegin("Network",ntag); 00450 mNetwork=ntag.AttributeStringValue("name"); 00451 // loop network nodes 00452 while(!rTr.Eos("Network")) { 00453 rTr.ReadBegin("Node",ntag); 00454 std::string node=ntag.AttributeStringValue("name"); 00455 InsNode(node); 00456 // undocumented feature: explicit server addresses in dev file; tmoor 20121113 00457 if(ntag.ExistsAttributeString("address")) { 00458 SimplenetAddress defaddress; 00459 defaddress.IpColonPort(ntag.AttributeStringValue("address")); 00460 if(!defaddress.Valid()) { 00461 std::stringstream errstr; 00462 errstr << "Simplenet address expected at " << rTr.FileLine(); 00463 throw Exception("nDevice::DoRead", errstr.str(), 50); 00464 } 00465 mNetworkNodes[node]=defaddress.IpColonPort(); 00466 } 00467 rTr.ReadEnd("Node"); 00468 } 00469 rTr.ReadEnd("Network"); 00470 } 00471 00472 00473 // lock - unlock shortcuts; 00474 #define LOCK_E {int rc = faudes_mutex_lock(&mMutex); \ 00475 if(rc) {FD_ERR("nDevice::LOCK_E: lock mutex error\n"); exit(1); }} 00476 #define UNLOCK_E {int rc = faudes_mutex_unlock(&mMutex); \ 00477 if(rc) {FD_ERR("nDevice::LOCK_E: unlock mutex error\n"); exit(1); }} 00478 #define TLOCK_E {int rc = faudes_mutex_lock(&ndevice->mMutex); \ 00479 if(rc) {FD_ERR("nDevice::TLOCK_E: lock mutex error\n"); exit(1); }} 00480 #define TUNLOCK_E {int rc = faudes_mutex_unlock(&ndevice->mMutex); \ 00481 if(rc) {FD_ERR("nDevice::TLOCK_E: unlock mutex error\n"); exit(1); }} 00482 00483 00484 // Write Output 00485 void nDevice::WriteOutput(Idx output) { 00486 00487 FD_DHV("nDevice::WriteOutput(" << mOutputs.SymbolicName(output) << ")"); 00488 00489 // bail out (do notify clients even when servers incomplete) 00490 if(mState!=Up && mState!=StartUp) return; 00491 00492 // test event 00493 if(!mOutputs.Exists(output)) { 00494 std::stringstream errstr; 00495 errstr << "Unknown output event " << output; 00496 throw Exception("nDevice::WriteOutput", errstr.str(), 65); 00497 } 00498 00499 // find properties 00500 const AttributeSimplenetOutput* aattr = pConfiguration->Attribute(output).Outputp(); 00501 if(!aattr) { 00502 std::stringstream errstr; 00503 errstr << "Invalid output attribute " << output; 00504 throw Exception("nDevice::WriteOutput", errstr.str(), 65); 00505 } 00506 00507 // report 00508 std::string message= "<Notify> " + mOutputs.SymbolicName(output) + " </Notify>\n"; 00509 FD_DHV("nDevice::WriteOutput(): message: " << message.substr(0,message.length()-1)); 00510 00511 // send event to those clients that did subscribe 00512 LOCK_E; 00513 int clientsock=-1; 00514 try { 00515 std::map<int,ClientState>::iterator sit=mOutputClientStates.begin(); 00516 for(;sit!=mOutputClientStates.end();sit++) { 00517 if(!sit->second.mEvents.Empty()) 00518 if(!sit->second.mEvents.Exists(output)) 00519 continue; 00520 clientsock=sit->second.mClientSocket; 00521 if(clientsock>0) { 00522 FD_DHV("nDevice::WriteOutput(): to socket " << clientsock); 00523 syncSend(clientsock, message.c_str(), message.length(), 0); 00524 } 00525 } 00526 } catch (faudes::Exception&) { 00527 FD_DH("nDevice::WriteOutput(): failed to notify client on socket " << clientsock); 00528 } 00529 UNLOCK_E; 00530 FD_DHV("nDevice::WriteOutput(): done"); 00531 } 00532 00533 00534 00535 // Start(void) 00536 void nDevice::Start(void) { 00537 if(mState!=Down) return; 00538 FD_DH("nDevice(" << mName <<")::Start()"); 00539 // call base 00540 vDevice::Start(); 00541 mState=StartUp; 00542 // clear event server states 00543 mInputServerStates.clear(); 00544 std::map<std::string,std::string>::iterator nit; 00545 for(nit=mNetworkNodes.begin(); nit!=mNetworkNodes.end();nit++) { 00546 if(nit->first == mName) continue; 00547 mInputServerStates[nit->first].mAddress= SimplenetAddress(nit->second); 00548 mInputServerStates[nit->first].mEvents= EventSet(); 00549 mInputServerStates[nit->first].mServerSocket=-1; 00550 mInputServerStates[nit->first].mLineBuffer=""; 00551 } 00552 // clear client states 00553 mOutputClientStates.clear(); 00554 // set my effective address 00555 char hostname[1024]; 00556 int hostname_len =1023; 00557 if(gethostname(hostname,hostname_len)!=0) { 00558 std::stringstream errstr; 00559 errstr << "Simplenet fatal network error (cannot get hostname)"; 00560 throw Exception("nDevice::Start", errstr.str(), 553); 00561 } 00562 hostname[hostname_len]=0; 00563 mEffectiveListenAddress=mListenAddress; 00564 mEffectiveListenAddress.Ip(hostname); 00565 FD_DH("nDevice::Start(): server adress " << mEffectiveListenAddress.IpColonPort()); 00566 // open a tcp port to listen: create socket 00567 mListenSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); 00568 if(mListenSocket<=0) { 00569 std::stringstream errstr; 00570 errstr << "Simplenet fatal network error (cannot open server socket)"; 00571 throw Exception("nDevice::Start", errstr.str(), 553); 00572 } 00573 int reuse=1; 00574 faudes_setsockopt(mListenSocket,SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); 00575 // open a tcp port to listen: set up address 00576 struct sockaddr_in serveraddr; 00577 memset(&serveraddr, 0, sizeof(serveraddr)); 00578 serveraddr.sin_family = AF_INET; 00579 serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); 00580 serveraddr.sin_port = htons(mListenAddress.Port()); 00581 // open a tcp port to listen: bind socket to address 00582 if(bind(mListenSocket, (struct sockaddr *) &serveraddr,sizeof(serveraddr)) <0) { 00583 std::stringstream errstr; 00584 errstr << "Simplenet fatal network error (cannot bind socket)"; 00585 throw Exception("nDevice::Start", errstr.str(), 553); 00586 } 00587 // open a tcp port to listen: start to listen 00588 if(listen(mListenSocket, 77) < 0) { // todo: max pending connections 00589 std::stringstream errstr; 00590 errstr << "Simplenet fatal network error (cannot listen from socket)"; 00591 throw Exception("nDevice::Start", errstr.str(), 553); 00592 } 00593 // open a udp port to listen: create socket 00594 mBroadcastSocket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); 00595 if(mBroadcastSocket<=0) { 00596 std::stringstream errstr; 00597 errstr << "Simplenet fatal network error (cannot open broadcast socket)"; 00598 throw Exception("nDevice::Start", errstr.str(), 553); 00599 } 00600 //int reuse=1; 00601 faudes_setsockopt(mBroadcastSocket,SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); 00602 faudes_setsockopt(mBroadcastSocket,SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(reuse)); 00603 // open a udp port: enable broadcast 00604 // int reuse 00605 if(faudes_setsockopt(mBroadcastSocket, SOL_SOCKET, SO_BROADCAST, &reuse, sizeof(reuse)) ) { 00606 std::stringstream errstr; 00607 errstr << "Simplenet fatal network error (cannot setopt broadcast socket)"; 00608 throw Exception("nDevice::Start", errstr.str(), 553); 00609 } 00610 // open a udp port to listen: set up address 00611 struct sockaddr_in broadcastaddr; 00612 memset(&broadcastaddr, 0, sizeof(broadcastaddr)); 00613 broadcastaddr.sin_family = AF_INET; 00614 broadcastaddr.sin_addr.s_addr = htonl(INADDR_ANY); 00615 broadcastaddr.sin_port = htons(mBroadcastAddress.Port()); 00616 // open a udp port to listen: bind socket to address 00617 if(bind(mBroadcastSocket, (struct sockaddr *) &broadcastaddr,sizeof(broadcastaddr)) <0) { 00618 std::stringstream errstr; 00619 errstr << "Simplenet fatal network error (cannot bind broadcast socket)"; 00620 throw Exception("nDevice::Start", errstr.str(), 553); 00621 } 00622 // start background thread to listen: create & run thread 00623 mStopListen=false; 00624 int rc = faudes_thread_create(&mThreadListen, NDeviceListen, this); 00625 // thread error 00626 if(rc) { 00627 std::stringstream errstr; 00628 errstr << "Simplenet fatal thread error (cannot create thread)"; 00629 throw Exception("nDevice::Start", errstr.str(), 554); 00630 } 00631 } 00632 00633 // Stop(void) 00634 void nDevice::Stop(void) { 00635 // bail out 00636 if(mState!=Up && mState!=StartUp) return; 00637 FD_DH("nDevice::Stop()"); 00638 LOCK_E; 00639 // stop background threads 00640 mStopListen=true; 00641 UNLOCK_E; 00642 // signal update to my listen thread: via udp message ... release select 00643 std::string message= "<Stop> " + mNetwork + " " + mName + " </Stop>\n"; 00644 struct sockaddr_in broadcastaddr; 00645 memset(&broadcastaddr, '\0', sizeof(broadcastaddr)); 00646 broadcastaddr.sin_family=AF_INET; 00647 broadcastaddr.sin_port=htons(mBroadcastAddress.Port()); 00648 broadcastaddr.sin_addr.s_addr=inet_addr(mBroadcastAddress.Ip().c_str()); 00649 LOCK_E; 00650 sendto(mBroadcastSocket,message.c_str(),message.length(),0, 00651 (struct sockaddr *) & broadcastaddr, sizeof(broadcastaddr)); 00652 UNLOCK_E; 00653 // wait until listen thread finished 00654 FD_DH("nDevice::Stop(): waiting for listen thread"); 00655 faudes_thread_join(mThreadListen, NULL); 00656 FD_DH("nDevice::Stop(): listen thread finished"); 00657 // close broadcast socket 00658 shutdown(mBroadcastSocket,2); 00659 faudes_closesocket(mBroadcastSocket); 00660 mBroadcastSocket=-1; 00661 // close server socket 00662 shutdown(mListenSocket,2); 00663 faudes_closesocket(mListenSocket); 00664 mListenSocket=-1; 00665 // call base (implies reset) 00666 vDevice::Stop(); 00667 } 00668 00669 00670 00671 // background thread, 00672 // - receiving requests on broadcast port 00673 // - sending requests broadcats 00674 // - accept connections on listen port for output clients 00675 // - notify connected output clients about events 00676 // - connecting to input servers to receiving notifications 00677 void* NDeviceListen(void* arg){ 00678 bool term; 00679 std::map<std::string,nDevice::ServerState>::iterator sit; 00680 std::map<int,nDevice::ClientState>::iterator cit; 00681 // cast this object 00682 nDevice* ndevice= static_cast<nDevice*>(arg); 00683 // say hello 00684 FD_DH("nDevice::Listen(" << ndevice << ")"); 00685 // clear broadcast time stamp 00686 timeval lastbroadcast; 00687 lastbroadcast.tv_sec=0; 00688 lastbroadcast.tv_usec=0; 00689 #ifdef FAUDES_DEBUG_IODEVICE 00690 // clear debugging time stamp 00691 int debuglisten=0; 00692 #endif 00693 00694 // infinite loop 00695 while(true){ 00696 00697 // detect missing servers 00698 int servermis=0; 00699 int serverunknown=0; 00700 for(sit=ndevice->mInputServerStates.begin(); sit!=ndevice->mInputServerStates.end(); sit++) { 00701 // have no address? 00702 if(!sit->second.mAddress.Valid()) { 00703 FD_DH("nDevice::Listen(): missing server address for node: " << sit->first); 00704 serverunknown++; 00705 servermis++; 00706 continue; 00707 } 00708 // have no connection 00709 if(sit->second.mServerSocket<=0) { 00710 FD_DH("nDevice::Listen(): missing server connection for node: " << sit->first); 00711 servermis++; 00712 continue; 00713 } 00714 } 00715 00716 // detect missing clients (extension 2.22i, trust by number, should ask nodename on subscription) 00717 int clientmis= ndevice->mNetworkNodes.size()-1; 00718 for(cit=ndevice->mOutputClientStates.begin(); cit!=ndevice->mOutputClientStates.end(); cit++) { 00719 if(cit->second.mClientSocket<0) continue; 00720 if(cit->second.mConnected) clientmis--; 00721 } 00722 #ifdef FAUDES_DEBUG_IODEVICE 00723 if(clientmis!=servermis) 00724 FD_DH("nDevice::Listen(): missing clients to subscribe: #"<< clientmis); 00725 #endif 00726 00727 // update state 00728 if((servermis>0 || clientmis>0) && ndevice->mState==vDevice::Up) { 00729 TLOCK_E; 00730 ndevice->mState=vDevice::StartUp; 00731 TUNLOCK_E; 00732 } 00733 if(servermis==0 && clientmis==0 && ndevice->mState==vDevice::StartUp) { 00734 TLOCK_E; 00735 ndevice->mState=vDevice::Up; 00736 TUNLOCK_E; 00737 } 00738 00739 00740 // try to find input servers 00741 if(serverunknown>0 && ndevice->mState==vDevice::StartUp) { 00742 // is a broadcast due? (period 5sec) 00743 timeval now; 00744 gettimeofday(&now,0); 00745 if(now.tv_sec - lastbroadcast.tv_sec >5) { 00746 // udp message 00747 std::string message= "<Request> " 00748 + ndevice->mNetwork + " " + ndevice->mName + " </Request>\n"; 00749 // udp broadcast 00750 struct sockaddr_in broadcastaddr; 00751 memset(&broadcastaddr, '\0', sizeof(broadcastaddr)); 00752 broadcastaddr.sin_family=AF_INET; 00753 broadcastaddr.sin_port=htons(ndevice->mBroadcastAddress.Port()); 00754 broadcastaddr.sin_addr.s_addr=inet_addr(ndevice->mBroadcastAddress.Ip().c_str()); 00755 TLOCK_E; 00756 int rc=sendto(ndevice->mBroadcastSocket,message.c_str(),message.length(), 00757 0,(struct sockaddr *) & broadcastaddr, sizeof(broadcastaddr)); 00758 (void) rc; 00759 FD_DH("nDevice::Listen(): broadcast request: " << message.substr(0,message.length()-1) << " #" << rc); 00760 TUNLOCK_E; 00761 gettimeofday(&lastbroadcast,0); 00762 } 00763 } 00764 00765 // subscribe to missing servers 00766 for(sit=ndevice->mInputServerStates.begin(); sit!=ndevice->mInputServerStates.end(); sit++) { 00767 // have active connection? 00768 if(sit->second.mServerSocket>0) continue; 00769 // have no address? 00770 if(!sit->second.mAddress.Valid()) continue; 00771 // try to connect 00772 FD_DH("nDevice::Listen(): subscribing to " << sit->first << 00773 " at " << sit->second.mAddress.IpColonPort()); 00774 // open a tcp port: create socket 00775 int serversock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); 00776 if(serversock<=0) { 00777 FD_DH("nDevice::Listen(): subscription failed: no socket"); 00778 continue; 00779 } 00780 // open a tcp port: set up internet address 00781 unsigned long int serverinaddr = INADDR_NONE; 00782 if(serverinaddr==INADDR_NONE) { 00783 FD_DH("nDevice::Listen(): using address as advertised"); 00784 serverinaddr = inet_addr(sit->second.mAddress.Ip().c_str()); 00785 } 00786 if(serverinaddr==INADDR_NONE) { 00787 struct hostent *host; 00788 host = gethostbyname(sit->second.mAddress.Ip().c_str()); 00789 if(host!=0) { 00790 FD_DH("nDevice::Listen(): using address by name lookup"); 00791 serverinaddr = *(unsigned long int*) host->h_addr; 00792 } 00793 } 00794 if(serverinaddr==INADDR_NONE) { 00795 FD_DH("nDevice::Listen(): subscription failed: invalid address " << sit->second.mAddress.Ip()); 00796 faudes_closesocket(serversock); 00797 continue; 00798 } 00799 // open a tcp port: set up socket address 00800 struct sockaddr_in serveraddress; 00801 memset(&serveraddress, 0, sizeof(serveraddress)); 00802 serveraddress.sin_family = AF_INET; 00803 serveraddress.sin_addr.s_addr=serverinaddr; 00804 serveraddress.sin_port = htons(sit->second.mAddress.Port()); 00805 // open a tcp port: connect 00806 if(connect(serversock, (struct sockaddr*) &serveraddress, sizeof(serveraddress))<0) { 00807 FD_DH("nDevice::Listen(): subscription failed: connect"); 00808 faudes_closesocket(serversock); 00809 continue; 00810 } 00811 // say hello to remote input server 00812 try { 00813 std::string hello; 00814 hello="% Simplenet universal event subscription: "+ndevice->mName+" subscribing from "+sit->first+"\n"; 00815 syncSend(serversock, hello.c_str(), hello.length(), 0); 00816 hello="% Expecting notifications in format '<Notify> event_name </Notify>'\n"; 00817 syncSend(serversock, hello.c_str(), hello.length(), 0); 00818 hello="% Trying to subscribe to all required events\n"; 00819 syncSend(serversock, hello.c_str(), hello.length(), 0); 00820 } catch (faudes::Exception&) { 00821 faudes_closesocket(serversock); 00822 serversock=-1; 00823 } 00824 if(serversock<0) { 00825 FD_DH("nDevice::Listen(): subscription failed: cannot write"); 00826 faudes_closesocket(serversock); 00827 continue; 00828 } 00829 // record success 00830 FD_DH("nDevice::Listen(): subscribing to " << sit->first << " via socket " << serversock); 00831 sit->second.mServerSocket=serversock; 00832 // subscribe to all input events 00833 EventSet sevents=ndevice->Inputs(); 00834 sevents.Name("Subscribe"); 00835 std::string message=sevents.ToString() + "\n"; 00836 syncSend(serversock,message.c_str(), message.length(),0); 00837 // used to get info in pre 2.22h 00838 /* 00839 hello="% Going to Sending info command, explicit subscription may follow\n"; 00840 hello="<Cmd> Info </Cmd>\n"; 00841 syncSend(serversock, hello.c_str(), hello.length(), 0); 00842 */ 00843 FD_DH("nDevice::Listen(): subscribing to " << sit->first << " via socket " << serversock << ": ok"); 00844 } 00845 00846 00847 // prepare relevant wait on sources ... 00848 fd_set mysocks; 00849 int mysocks_max=0; 00850 FD_ZERO(&mysocks); 00851 // ... my server listen socket, expecting other nodes to connect and subscribe 00852 if(mysocks_max<ndevice->mListenSocket) mysocks_max=ndevice->mListenSocket; 00853 if(mysocks_max>= FD_SETSIZE) FD_ERR("NDeviceListen: fail to select socket " << mysocks_max); 00854 FD_SET(ndevice->mListenSocket, &mysocks); 00855 // ... udp port, expecting requests and adverts 00856 if(mysocks_max< ndevice->mBroadcastSocket) mysocks_max=ndevice->mBroadcastSocket; 00857 if(mysocks_max>= FD_SETSIZE) FD_ERR("NDeviceListen: fail to select socket " << mysocks_max); 00858 FD_SET(ndevice->mBroadcastSocket, &mysocks); 00859 // ... input server connections, expecting notifications 00860 for(sit=ndevice->mInputServerStates.begin(); sit!=ndevice->mInputServerStates.end(); sit++) { 00861 int serversock=sit->second.mServerSocket; 00862 if(serversock<0) continue; 00863 if(mysocks_max< serversock) mysocks_max=serversock; 00864 if(mysocks_max>= FD_SETSIZE) FD_ERR("NDeviceListen: fail to select socket " << mysocks_max); 00865 FD_SET(serversock, &mysocks); 00866 } 00867 // ... output client connections, expecting commands 00868 for(cit=ndevice->mOutputClientStates.begin(); cit!=ndevice->mOutputClientStates.end(); cit++) { 00869 int clientsock=cit->second.mClientSocket; 00870 if(clientsock<0) continue; 00871 if(mysocks_max< clientsock) mysocks_max=clientsock; 00872 if(mysocks_max>= FD_SETSIZE) FD_ERR("NDeviceListen: fail to select socket " << mysocks_max); 00873 FD_SET(clientsock, &mysocks); 00874 } 00875 00876 // wait for traffic with moderate timeout 00877 struct timeval tv; 00878 tv.tv_sec = 1; 00879 tv.tv_usec = 0; 00880 int avail=select(mysocks_max+1, &mysocks, NULL, NULL, &tv); 00881 00882 // terminate thread on request (before accepting incomming connections) 00883 TLOCK_E; 00884 term= ndevice->mStopListen; 00885 TUNLOCK_E; 00886 if(term) break; 00887 00888 // reduce debugging output 00889 #ifdef FAUDES_DEBUG_IODEVICE 00890 debuglisten++; 00891 if((debuglisten>10) || (avail>0)) { 00892 FD_DH("nDevice::Listen(): listen as node \"" << ndevice->mName << "\" on network \"" << ndevice->mNetwork << "\"" << " #" << avail); 00893 debuglisten=0; 00894 } 00895 #endif 00896 00897 // handle incomming connection requests 00898 if(avail>0) 00899 if(FD_ISSET(ndevice->mListenSocket,&mysocks)) { 00900 avail--; 00901 int clientsock=-1; 00902 struct sockaddr_in clientaddr; 00903 socklen_t clientaddr_len = sizeof(clientaddr); 00904 clientsock=accept(ndevice->mListenSocket, (struct sockaddr *) &clientaddr, &clientaddr_len ); 00905 if(clientsock<0) { 00906 FD_DH("nDevice::Listen(): failed to accept incomming connection"); 00907 break; 00908 } 00909 FD_DH("nDevice::Listen(): accepted connection from client " << inet_ntoa(clientaddr.sin_addr) << 00910 " on socket " << clientsock); 00911 // say hello 00912 try { 00913 std::string hello; 00914 hello="% Simplenet Event Server: "+ndevice->mName+" providing events\n"; 00915 syncSend(clientsock, hello.c_str(), hello.length(), 0); 00916 hello="% Notifications will have format '<Notify> event_name </Notify>'\n"; 00917 syncSend(clientsock, hello.c_str(), hello.length(), 0); 00918 hello="% Commands are accepted in format '<Cmd> cmd_name </Cmd>'\n"; 00919 syncSend(clientsock, hello.c_str(), hello.length(), 0); 00920 hello="% Supported commands are Subscribe, Info, Status, and ResetRequest\n"; 00921 syncSend(clientsock, hello.c_str(), hello.length(), 0); 00922 } catch (faudes::Exception&) { 00923 faudes_closesocket(clientsock); 00924 clientsock=-1; 00925 } 00926 if(clientsock<0) { 00927 FD_DH("nDevice::Listen(): connection test failed: cannot write"); 00928 faudes_closesocket(clientsock); 00929 break; 00930 } 00931 // record client by socket 00932 TLOCK_E; 00933 nDevice::ClientState* cstate = &ndevice->mOutputClientStates[clientsock]; 00934 cstate->mClientSocket=clientsock; 00935 cstate->mEvents.Clear(); 00936 cstate->mConnected=false; 00937 cstate->mLineBuffer=""; 00938 TUNLOCK_E; 00939 } 00940 00941 // handle incomming broadcast 00942 if(avail>0) 00943 if(FD_ISSET(ndevice->mBroadcastSocket,&mysocks)) { 00944 avail--; 00945 // get message 00946 char data[1024]; 00947 int data_len=1023; 00948 struct sockaddr_in fromaddr; 00949 socklen_t fromaddr_len = sizeof(fromaddr); 00950 data_len=recvfrom(ndevice->mBroadcastSocket,data,data_len,0, (struct sockaddr*) &fromaddr,&fromaddr_len); 00951 if(data_len<0) data_len=0; // todo: eof 00952 data[data_len]=0; 00953 if(data_len>=1) if(data[data_len-1]=='\n') data[data_len-1]=0; 00954 FD_DH("nDevice::Listen(): received udp datagram " << data << 00955 " from " << inet_ntoa(fromaddr.sin_addr)); 00956 // interpret message 00957 TokenReader tr(TokenReader::String,std::string(data)); 00958 try { 00959 Token token; 00960 tr.Peek(token); 00961 // interpret udp request ... 00962 if(token.IsBegin("Request")) { 00963 tr.ReadBegin("Request"); 00964 if(tr.ReadString()==ndevice->mNetwork) { 00965 // extension 2.22i: identify sender (optional for compatibility) 00966 std::string snode; 00967 Token stoken; 00968 tr.Peek(stoken); 00969 if(stoken.IsString()) snode=stoken.StringValue(); 00970 // extension 2.22i: if this is a missing server, reset my request timer 00971 sit=ndevice->mInputServerStates.find(snode); 00972 if(sit!=ndevice->mInputServerStates.end()) { 00973 if(sit->second.mServerSocket==-1) { 00974 lastbroadcast.tv_sec=0; 00975 lastbroadcast.tv_usec=0; 00976 } 00977 } 00978 // extension 2.22i: ignore my own requests 00979 if(snode!=ndevice->mName) { 00980 // set up advert 00981 std::string message= "<Advert> " 00982 + ndevice->mNetwork + " " 00983 + ndevice->mName + " " + 00984 ndevice->mEffectiveListenAddress.IpColonPort()+ " </Advert>\n"; 00985 // udp reply 00986 struct sockaddr_in replyaddr; 00987 memset(&replyaddr, '\0', sizeof(replyaddr)); 00988 replyaddr.sin_family=AF_INET; 00989 replyaddr.sin_port=htons(ndevice->mBroadcastAddress.Port()); 00990 //replyaddr.sin_addr.s_addr=fromaddr.sin_addr.s_addr; 00991 replyaddr.sin_addr.s_addr=inet_addr(ndevice->mBroadcastAddress.Ip().c_str()); 00992 //replyaddr.sin_addr.s_addr=htonl(INADDR_BROADCAST); 00993 TLOCK_E; 00994 int rc = sendto(ndevice->mBroadcastSocket,message.c_str(),message.length(),0,(struct sockaddr *) & replyaddr, sizeof(replyaddr)); 00995 TUNLOCK_E 00996 FD_DH("nDevice::Listen(): reply advert: " << message.substr(0,message.length()-1) << " #" << rc); 00997 } else { 00998 FD_DH("nDevice::Listen(): ingoring request from myself"); 00999 } 01000 } else { 01001 FD_DH("nDevice::Listen(): ingoring request from other network"); 01002 } 01003 } 01004 // interpret udp advert ... 01005 if(token.IsBegin("Advert")) { 01006 tr.ReadBegin("Advert"); 01007 if(tr.ReadString()==ndevice->mNetwork) { 01008 std::string node = tr.ReadString(); 01009 std::string saddr = tr.ReadString(); 01010 SimplenetAddress addr(saddr); 01011 addr.Ip(inet_ntoa(fromaddr.sin_addr)); // overwrite with actual ip 01012 FD_DHV("nDevice::Listen(): figure actual ip address " << addr.Ip()); 01013 if(!addr.Valid()) { 01014 addr=saddr; 01015 FD_DH("nDevice::Listen(): fallback to explicit ip address " << addr.Ip()); 01016 } 01017 std::map<std::string,nDevice::ServerState>::iterator sit; 01018 sit=ndevice->mInputServerStates.find(node); 01019 if(sit==ndevice->mInputServerStates.end()) { 01020 FD_DH("nDevice::Listen(): ignoring irrelevant advert from " << node); 01021 } else if(sit->second.mAddress.Valid()) { 01022 FD_DH("nDevice::Listen(): ignoring address overwrite (hardwired?) " << node); 01023 } 01024 if(sit!=ndevice->mInputServerStates.end()) 01025 if(!sit->second.mAddress.Valid()) { 01026 FD_DH("nDevice::Listen(): accept advert " << node); 01027 sit->second.mAddress=addr; 01028 if(sit->second.mServerSocket>=0) faudes_closesocket(sit->second.mServerSocket); 01029 sit->second.mServerSocket=-1; 01030 } 01031 } else { 01032 FD_DH("nDevice::Listen(): ingoring advert from other network"); 01033 } 01034 } 01035 } catch (faudes::Exception&) { 01036 FD_DH("nDevice::Listen(): ignore invalid udp message"); 01037 } 01038 } 01039 01040 01041 // handle input servers: receive event notification 01042 int revcount=0; 01043 if(avail>0) 01044 for(sit=ndevice->mInputServerStates.begin(); sit!=ndevice->mInputServerStates.end(); sit++) { 01045 int serversock=sit->second.mServerSocket; 01046 if(serversock<0) continue; 01047 if(FD_ISSET(serversock, &mysocks)) { 01048 avail--; 01049 FD_DH("nDevice::Listen(): reading sock " << serversock); 01050 // buffer data in line buffer 01051 char buffer[1025]; 01052 int count = recv(serversock, buffer, 1024, 0); 01053 if(count<=0) { // todo: test eof 01054 FD_DH("nDevice::Listen(): reading server sock " << serversock << " : eof"); 01055 faudes_closesocket(serversock); 01056 sit->second.mServerSocket=-1; 01057 continue; 01058 } 01059 FD_DH("nDevice::Listen(): reading server sock " << serversock << ": #" << count); 01060 buffer[count]=0; 01061 sit->second.mLineBuffer +=std::string(buffer); 01062 // interpret line(s) 01063 if(count>0) 01064 if(buffer[count-1]=='\n') 01065 if(sit->second.mLineBuffer.length()>0) 01066 { 01067 const std::string& linebuffer = sit->second.mLineBuffer; 01068 #ifdef FAUDES_DEBUG_IODEVICE 01069 if(linebuffer.length()>0) 01070 if(linebuffer[0]!='%') 01071 FD_DH("nDevice::Listen(): reading server sock " << serversock << ": line: " << linebuffer); 01072 #endif 01073 // tokenise notification 01074 TokenReader tr(TokenReader::String,linebuffer); 01075 try { 01076 Token token; 01077 while(tr.Peek(token)) { 01078 // its an event notify 01079 if(token.Type()==Token::Begin && token.StringValue()=="Notify") { 01080 tr.ReadBegin("Notify"); 01081 std::string event = tr.ReadString(); 01082 tr.ReadEnd("Notify"); 01083 faudes_mutex_lock(ndevice->pBufferMutex); 01084 FD_DH("nDevice::Listen(): found event " << event); 01085 Idx sev=ndevice->mInputs.Index(event); 01086 if(ndevice->mInputs.Exists(sev)) ndevice->pInputBuffer->push_back(sev); 01087 faudes_mutex_unlock(ndevice->pBufferMutex); 01088 revcount++; 01089 continue; 01090 } 01091 // its an info reply (ignored as of 2.22i) 01092 if(token.Type()==Token::Begin && token.StringValue()=="SimplenetDevice") { 01093 FD_DH("nDevice::Listen(): found device info"); 01094 nDevice remote; 01095 remote.Read(tr); 01096 FD_DH("nDevice::Listen(): found device with outputs " << remote.Outputs().ToString()); 01097 // used to subscribe on relevant events in pre 2.22h 01098 /* 01099 EventSet sevents=ndevice->Inputs(); 01100 sevents.SetIntersection(remote.Outputs()); 01101 sevents.Name("Subscribe"); 01102 std::string message=sevents.ToString(); 01103 FD_DH("nDevice::Listen(): subscribing events " << message); 01104 message += "\n"; 01105 syncSend(serversock,message.c_str(), message.length(),0); 01106 */ 01107 continue; 01108 } 01109 // skip other sections 01110 if(token.Type()==Token::Begin) { 01111 FD_DH("nDevice::Listen(): ignore section " << token.StringValue()); 01112 std::string section=token.StringValue(); 01113 tr.ReadBegin(section); 01114 while(!tr.Eos(section)) tr.Get(token); 01115 tr.ReadEnd(section); 01116 continue; 01117 } 01118 // ignore token 01119 FD_DH("nDevice::Listen(): error: ignore token"); 01120 tr.Get(token); 01121 } 01122 } catch (faudes::Exception&) { 01123 FD_DH("nDevice::Listen(): " << serversock << ": invalid notification"); 01124 } 01125 sit->second.mLineBuffer.clear(); 01126 } 01127 } 01128 } 01129 01130 // handle output clients: reply to commands 01131 if(avail>0) 01132 for(cit=ndevice->mOutputClientStates.begin(); cit!=ndevice->mOutputClientStates.end(); cit++) { 01133 int clientsock=cit->second.mClientSocket; 01134 if(clientsock<0) continue; 01135 if(FD_ISSET(clientsock, &mysocks)) { 01136 avail--; 01137 FD_DH("nDevice::Listen(): reading client sock " << clientsock); 01138 // buffer data in line buffer 01139 char buffer[1025]; 01140 int count = recv(clientsock, buffer, 1024, 0); 01141 if(count<=0) { // todo: test eof 01142 FD_DH("nDevice::Listen(): reading client sock " << clientsock << " : eof"); 01143 TLOCK_E; 01144 faudes_closesocket(clientsock); 01145 cit->second.mClientSocket=-1; 01146 cit->second.mConnected=false; 01147 TUNLOCK_E; 01148 continue; 01149 } 01150 FD_DH("nDevice::Listen(): reading client sock " << clientsock << ": #" << count); 01151 buffer[count]=0; 01152 cit->second.mLineBuffer +=std::string(buffer); 01153 // interpret line(s) 01154 if(count>0) 01155 if(buffer[count-1]=='\n') 01156 if(cit->second.mLineBuffer.length()>0) 01157 { 01158 const std::string& linebuffer = cit->second.mLineBuffer; 01159 #ifdef FAUDES_DEBUG_IODEVICE 01160 if(linebuffer.length()>0) 01161 if(linebuffer[0]!='%') 01162 FD_DH("nDevice::Listen(): reading client sock " << clientsock << ": line: " << linebuffer); 01163 #endif 01164 // tokenise command 01165 TokenReader tr(TokenReader::String,linebuffer); 01166 try { 01167 Token token; 01168 while(tr.Peek(token)) { 01169 // its a command 01170 if(token.IsBegin("Cmd")) { 01171 tr.ReadBegin("Cmd"); 01172 std::string cmd = tr.ReadString(); 01173 tr.ReadEnd("Cmd"); 01174 std::string response="<NAck> </NAck>\n"; 01175 FD_DH("nDevice::Reply(" << clientsock << "): received cmd " << cmd); 01176 // command: info 01177 if(cmd=="Info") { 01178 TLOCK_E; 01179 response=ndevice->ToString() + "\n"; 01180 TUNLOCK_E; 01181 } 01182 // command: status 01183 if(cmd=="Status") { 01184 TLOCK_E; 01185 if(ndevice->mState==vDevice::Up) response="<Ack> Up </Ack>\n"; 01186 if(ndevice->mState==vDevice::StartUp) response="<Ack> StartUp </Ack>\n"; 01187 if(ndevice->mState==vDevice::ShutDown) response="<Ack> ShutDown </Ack>\n"; 01188 TUNLOCK_E; 01189 } 01190 // its a reset request 01191 if(cmd=="ResetRequest") { 01192 FD_DH("nDevice::Reply(" << clientsock << "): reset request"); 01193 faudes_mutex_lock(ndevice->pBufferMutex); 01194 if(!ndevice->mResetRequest) revcount++; 01195 ndevice->mResetRequest=true; 01196 faudes_mutex_unlock(ndevice->pBufferMutex); 01197 response=""; 01198 } 01199 // send reply 01200 syncSend(clientsock, response.c_str(), response.length(), 0); 01201 } 01202 // its a event subscription 01203 if(token.IsBegin("Subscribe")) { 01204 EventSet sevents; 01205 sevents.Read(tr,"Subscribe"); 01206 sevents.RestrictSet(ndevice->Outputs()); 01207 sevents.Name("Subscribed"); 01208 FD_DH("nDevice::Reply(" << clientsock << "): providing events " << sevents.ToString()); 01209 TLOCK_E; 01210 cit->second.mEvents.Clear(); 01211 cit->second.mEvents.InsertSet(sevents); 01212 cit->second.mConnected=true; 01213 std::string response=sevents.ToString()+"\n"; 01214 TUNLOCK_E; 01215 // send reply 01216 syncSend(clientsock, response.c_str(), response.length(), 0); 01217 } 01218 } 01219 } catch (faudes::Exception&) { 01220 FD_DH("nDevice::Reply(" << clientsock << "): invalid cmd"); 01221 } 01222 cit->second.mLineBuffer.clear(); 01223 } 01224 } 01225 } 01226 01227 // signal condition for received events / reset requests 01228 if(revcount>0) { 01229 FD_DH("nDevice::Listen(): broadcast condition"); 01230 faudes_mutex_lock(ndevice->pWaitMutex); 01231 faudes_cond_broadcast(ndevice->pWaitCondition); 01232 faudes_mutex_unlock(ndevice->pWaitMutex); 01233 revcount=0; 01234 } 01235 01236 // should remove unconnected clients ? 01237 01238 01239 // some error 01240 if(avail<0) { 01241 FD_DH("nDevice::Listen(): select error"); 01242 } 01243 01244 } 01245 01246 // close clientsockets 01247 FD_DH("nDevice::Listen(): close client sockets"); 01248 TLOCK_E; 01249 for(cit=ndevice->mOutputClientStates.begin(); cit!=ndevice->mOutputClientStates.end(); cit++) { 01250 int clientsock= cit->second.mClientSocket; 01251 if(clientsock>0) faudes_closesocket(clientsock); 01252 cit->second.mClientSocket=-1; 01253 cit->second.mConnected=false; 01254 } 01255 ndevice->mOutputClientStates.clear(); 01256 TUNLOCK_E; 01257 // close serversockets 01258 FD_DH("nDevice::Listen(): close server sockets"); 01259 for(sit=ndevice->mInputServerStates.begin(); sit!=ndevice->mInputServerStates.end(); sit++) { 01260 int serversock=sit->second.mServerSocket; 01261 if(serversock>0) faudes_closesocket(serversock); 01262 sit->second.mServerSocket=-1; 01263 } 01264 FD_DH("nDevice::Listen(): terminating listen thread"); 01265 faudes_thread_exit(NULL); 01266 return NULL; 01267 } 01268 01269 01270 01271 01272 // reset dynamic faudes state (buffered events, current time) 01273 void nDevice::Reset(void) { 01274 // call base for time and input buffer 01275 vDevice::Reset(); 01276 // bail out (do notify clients even when servers incomplete) 01277 if(mState!=Up && mState!=StartUp) return; 01278 // have message 01279 std::string message= "<Cmd> ResetRequest </Cmd>\n"; 01280 // send cmd to all my servers 01281 LOCK_E; 01282 std::map<std::string,ServerState>::iterator sit=mInputServerStates.begin(); 01283 for(; sit!=mInputServerStates.end(); sit++) { 01284 int serversock=sit->second.mServerSocket; 01285 if(serversock<0) continue; 01286 FD_DH("nDevice::Reset(): sending reset request to socket " << serversock); 01287 syncSend(serversock, message.c_str(), message.length(), 0); 01288 } 01289 UNLOCK_E; 01290 } 01291 01292 01293 #endif // configured simplenet 01294 01295 01296 } // name space 01297 01298 01299 libFAUDES 2.23h --- 2014.04.03 --- c++ api documentaion by doxygen |