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