About
User Reference
C++ API
luafaudes
Developer
Links
libFAUDES online
libFAUDES

Sections

Index

iop_simplenet.cpp

Go 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);
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: network name
00308 void nDevice::NetworkName(const std::string& rNetwork) {
00309   if(mState!=Down) return;
00310   mNetwork=rNetwork;
00311 }
00312 
00313 // programmatic config: insert node name
00314 void nDevice::InsNode(const std::string& rNodeName) {
00315   if(mState!=Down) return;
00316   mNetworkNodes[rNodeName]="unknown:0";
00317 }
00318 
00319 // programmatic config: clear known nodes
00320 void nDevice::ClearNodes(void) {
00321   if(mState!=Down) return;
00322   mNetworkNodes.clear();
00323 }
00324 
00325 // programmatic config: insert input event
00326 void nDevice::InsInputEvent(const std::string& event) {
00327   if(mState!=Down) return;
00328   AttributeSimplenetEvent inp;
00329   inp.DefaultInput();
00330   Idx ev=pConfiguration->Insert(event);
00331   pConfiguration->Attribute(ev, inp);
00332 }
00333 
00334 // programmatic config: insert output event
00335 void nDevice::InsOutputEvent(const std::string& event) {
00336   if(mState!=Down) return;
00337   AttributeSimplenetEvent outp;
00338   outp.DefaultOutput();
00339   Idx ev=pConfiguration->Insert(event);
00340   pConfiguration->Attribute(ev, outp);
00341 }
00342 
00343 
00344 //Compile(void)
00345 void nDevice::Compile(void){
00346   //setup up internal data structure
00347   FD_DHV("nDevice(" << this << ")::Compile()");
00348   // call base
00349   vDevice::Compile();
00350 }
00351 
00352 
00353 //DoWritePreface(rTr,rLabel)
00354 void nDevice::DoWritePreface(TokenWriter& rTw, const std::string& rLabel, const Type* pContext) const {
00355   FD_DHV("nDevice::DoWrite()");
00356   //call base
00357   vDevice::DoWritePreface(rTw,rLabel,pContext);
00358   // write my data: my server role ip address
00359   Token vtag;
00360   vtag.SetEmpty("ServerAddress");
00361   vtag.InsAttributeString("value",mListenAddress.IpColonPort());
00362   rTw<<vtag;
00363   // write my data: my server broadcast address
00364   Token btag;
00365   btag.SetEmpty("BroadcastAddress");
00366   btag.InsAttributeString("value",mBroadcastAddress.IpColonPort());
00367   rTw<<btag;
00368   // write my data network topology
00369   Token ntag;
00370   ntag.SetBegin("Network");
00371   ntag.InsAttributeString("name",mNetwork);
00372   rTw<<ntag;
00373   std::map<std::string,std::string>::const_iterator nit;
00374   for(nit=mNetworkNodes.begin();nit!=mNetworkNodes.end();nit++) {
00375     vtag.SetEmpty("Node");
00376     vtag.InsAttributeString("name",nit->first);
00377     SimplenetAddress defaddress(nit->second);
00378     if(defaddress.Valid()) 
00379       vtag.InsAttributeString("address",nit->second);
00380     rTw<<vtag;
00381   }
00382   rTw.WriteEnd("Network");
00383 }
00384 
00385 //DoRead(rTr,rLabel)
00386 void nDevice::DoReadPreface(TokenReader& rTr, const std::string& rLabel, const Type* pContext) {
00387   FD_DHV("nDevice::DoReadPreface()");
00388   // call base (reads name and timescale)
00389   vDevice::DoReadPreface(rTr,rLabel,pContext);
00390 
00391   // sense and digest pre 2.16 format
00392   Token token;
00393   rTr.Peek(token);
00394   if(token.IsString()) {
00395     mListenAddress.IpColonPort(rTr.ReadString());
00396     if(!mListenAddress.Valid()) {
00397       std::stringstream errstr;
00398       errstr << "Simplenet address expected at " << rTr.FileLine();
00399       throw Exception("nDevice::DoRead", errstr.str(), 50);
00400     }
00401     mNetwork=rTr.ReadString();
00402     mNetworkNodes.clear();
00403     rTr.ReadBegin("Network");
00404     while(!rTr.Eos("Network")) {
00405       mNetworkNodes[rTr.ReadString()]="unknown:0";
00406     }
00407     rTr.ReadEnd("Network");
00408     return;
00409   }
00410 
00411   // read my data: server address
00412   Token atag;
00413   rTr.ReadBegin("ServerAddress",atag);
00414   mListenAddress.IpColonPort(atag.AttributeStringValue("value"));
00415   if(!mListenAddress.Valid()) {
00416     std::stringstream errstr;
00417     errstr << "Simplenet address expected at " << rTr.FileLine();
00418     throw Exception("nDevice::DoRead", errstr.str(), 50);
00419   }
00420   rTr.ReadEnd("ServerAddress");
00421   // read my data: broadcast address (optional)
00422   mBroadcastAddress.IpColonPort("255.255.255.255:40000");
00423   rTr.Peek(token);
00424   if(token.IsBegin("BroadcastAddress")) {
00425     rTr.ReadBegin("BroadcastAddress",atag);
00426     mBroadcastAddress.IpColonPort(atag.AttributeStringValue("value"));
00427     if(!mBroadcastAddress.Valid()) {
00428       std::stringstream errstr;
00429       errstr << "Simplenet address expected at " << rTr.FileLine();
00430       throw Exception("nDevice::DoRead", errstr.str(), 50);
00431     }
00432     rTr.ReadEnd("BroadcastAddress");
00433   }
00434   // read my data: network
00435   Token ntag;
00436   rTr.ReadBegin("Network",ntag);
00437   mNetwork=ntag.AttributeStringValue("name");
00438   // loop network nodes
00439   while(!rTr.Eos("Network")) {
00440     rTr.ReadBegin("Node",ntag);
00441     std::string node=ntag.AttributeStringValue("name");
00442     InsNode(node);
00443     // undocumented feature: explicit server addresses in dev file; tmoor 20121113
00444     if(ntag.ExistsAttributeString("address")) {
00445       SimplenetAddress defaddress;
00446       defaddress.IpColonPort(ntag.AttributeStringValue("address"));
00447       if(!defaddress.Valid()) {
00448         std::stringstream errstr;
00449         errstr << "Simplenet address expected at " << rTr.FileLine();
00450         throw Exception("nDevice::DoRead", errstr.str(), 50);
00451       }
00452       mNetworkNodes[node]=defaddress.IpColonPort();
00453     }
00454     rTr.ReadEnd("Node");
00455   }
00456   rTr.ReadEnd("Network");
00457 }
00458 
00459 
00460 // lock - unlock shortcuts;
00461 #define LOCK_E  {int rc = faudes_mutex_lock(&mMutex); \
00462   if(rc) {FD_ERR("nDevice::LOCK_E: lock mutex error\n"); exit(1); }}    
00463 #define UNLOCK_E  {int rc = faudes_mutex_unlock(&mMutex); \
00464   if(rc) {FD_ERR("nDevice::LOCK_E: unlock mutex error\n"); exit(1); }}    
00465 #define TLOCK_E  {int rc = faudes_mutex_lock(&ndevice->mMutex); \
00466   if(rc) {FD_ERR("nDevice::TLOCK_E: lock mutex error\n"); exit(1); }}   
00467 #define TUNLOCK_E  {int rc = faudes_mutex_unlock(&ndevice->mMutex); \
00468   if(rc) {FD_ERR("nDevice::TLOCK_E: unlock mutex error\n"); exit(1); }}   
00469 
00470 
00471 // Write Output 
00472 void nDevice::WriteOutput(Idx output) {
00473 
00474   FD_DHV("nDevice::WriteOutput(" << mOutputs.SymbolicName(output) << ")");
00475 
00476   // bail out (do notify clients even when servers incomplete)
00477   if(mState!=Up && mState!=StartUp) return;
00478 
00479   // test event
00480   if(!mOutputs.Exists(output)) {
00481     std::stringstream errstr;
00482     errstr << "Unknown output event " << output;
00483     throw Exception("nDevice::WriteOutput", errstr.str(), 65);
00484   }
00485 
00486   // find properties
00487   const AttributeSimplenetOutput* aattr = pConfiguration->Attribute(output).Outputp();
00488   if(!aattr) {
00489     std::stringstream errstr;
00490     errstr << "Invalid output attribute " << output;
00491     throw Exception("nDevice::WriteOutput", errstr.str(), 65);
00492   }
00493 
00494   // report
00495   std::string message= "<Notify> " + mOutputs.SymbolicName(output) + " </Notify>\n";
00496   FD_DHV("nDevice::WriteOutput(): message: " << message.substr(0,message.length()-1));
00497   
00498   // send event to those clients that did subscribe 
00499   LOCK_E;
00500   std::map<int,ClientState>::iterator sit=mOutputClientStates.begin();
00501   for(;sit!=mOutputClientStates.end();sit++) {
00502     if(!sit->second.mEvents.Empty())
00503       if(!sit->second.mEvents.Exists(output))
00504         continue;
00505     int clientsock=sit->second.mClientSocket;
00506     FD_DHV("nDevice::WriteOutput(): to socket " << clientsock);
00507     syncSend(clientsock, message.c_str(), message.length(), 0);
00508   }
00509   UNLOCK_E;
00510   FD_DHV("nDevice::WriteOutput(): done");
00511 }
00512 
00513 
00514 
00515 // Start(void)
00516 void nDevice::Start(void) {
00517   if(mState!=Down) return;
00518   FD_DH("nDevice(" << mName <<")::Start()");
00519   // call base
00520   vDevice::Start();
00521   mState=StartUp;
00522   // clear event server states
00523   mInputServerStates.clear();
00524   std::map<std::string,std::string>::iterator nit;
00525   for(nit=mNetworkNodes.begin(); nit!=mNetworkNodes.end();nit++) {
00526     if(nit->first == mName) continue;
00527     mInputServerStates[nit->first].mAddress= SimplenetAddress(nit->second);
00528     mInputServerStates[nit->first].mEvents= EventSet();
00529     mInputServerStates[nit->first].mServerSocket=-1;
00530     mInputServerStates[nit->first].mLineBuffer="";
00531   }
00532   // clear client states
00533   mOutputClientStates.clear();
00534   // set my effective address
00535   char hostname[1024];
00536   int hostname_len =1023;
00537   if(gethostname(hostname,hostname_len)!=0) {
00538     std::stringstream errstr;
00539     errstr << "Simplenet fatal network error (cannot get hostname)";
00540     throw Exception("nDevice::Start", errstr.str(), 553);
00541   }
00542   hostname[hostname_len]=0;
00543   mEffectiveListenAddress=mListenAddress;
00544   mEffectiveListenAddress.Ip(hostname);
00545   FD_DH("nDevice::Start(): server adress " << mEffectiveListenAddress.IpColonPort());
00546   // open a tcp port to listen: create socket
00547   mListenSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
00548   if(mListenSocket<=0) {
00549     std::stringstream errstr;
00550     errstr << "Simplenet fatal network error (cannot open server socket)";
00551     throw Exception("nDevice::Start", errstr.str(), 553);
00552   }
00553   int reuse=1;
00554   faudes_setsockopt(mListenSocket,SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));  
00555   // open a tcp port to listen: set up address
00556   struct sockaddr_in serveraddr;
00557   memset(&serveraddr, 0, sizeof(serveraddr));
00558   serveraddr.sin_family = AF_INET;
00559   serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);  
00560   serveraddr.sin_port = htons(mListenAddress.Port());     
00561   // open a tcp port to listen: bind socket to address
00562   if(bind(mListenSocket, (struct sockaddr *) &serveraddr,sizeof(serveraddr)) <0) {
00563     std::stringstream errstr;
00564     errstr << "Simplenet fatal network error (cannot bind socket)";
00565     throw Exception("nDevice::Start", errstr.str(), 553);
00566   }
00567   // open a tcp port to listen: start to listen
00568   if(listen(mListenSocket, 77) < 0) {  // todo: max pending connections
00569     std::stringstream errstr;
00570     errstr << "Simplenet fatal network error (cannot listen from socket)";
00571     throw Exception("nDevice::Start", errstr.str(), 553);
00572   }
00573   // open a udp port to listen: create socket
00574   mBroadcastSocket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
00575   if(mBroadcastSocket<=0) {
00576     std::stringstream errstr;
00577     errstr << "Simplenet fatal network error (cannot open broadcast socket)";
00578     throw Exception("nDevice::Start", errstr.str(), 553);
00579   }
00580   //int reuse=1;
00581   faudes_setsockopt(mBroadcastSocket,SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));  
00582   faudes_setsockopt(mBroadcastSocket,SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(reuse));  
00583   // open a udp port: enable broadcast 
00584   // int reuse
00585   if(faudes_setsockopt(mBroadcastSocket, SOL_SOCKET, SO_BROADCAST, &reuse, sizeof(reuse)) ) {
00586     std::stringstream errstr;
00587     errstr << "Simplenet fatal network error (cannot setopt broadcast socket)";
00588     throw Exception("nDevice::Start", errstr.str(), 553);
00589   }  
00590   // open a udp port to listen: set up address
00591   struct sockaddr_in broadcastaddr;
00592   memset(&broadcastaddr, 0, sizeof(broadcastaddr));
00593   broadcastaddr.sin_family = AF_INET;
00594   broadcastaddr.sin_addr.s_addr = htonl(INADDR_ANY);  
00595   broadcastaddr.sin_port = htons(mBroadcastAddress.Port());     
00596   // open a udp port to listen: bind socket to address
00597   if(bind(mBroadcastSocket, (struct sockaddr *) &broadcastaddr,sizeof(broadcastaddr)) <0) {
00598     std::stringstream errstr;
00599     errstr << "Simplenet fatal network error (cannot bind broadcast socket)";
00600     throw Exception("nDevice::Start", errstr.str(), 553);
00601   }
00602   // start background thread to listen: create & run thread
00603   mStopListen=false;
00604   int rc  = faudes_thread_create(&mThreadListen, NDeviceListen, this);
00605   // thread error 
00606   if(rc) {
00607     std::stringstream errstr;
00608     errstr << "Simplenet fatal thread error (cannot create thread)";
00609     throw Exception("nDevice::Start", errstr.str(), 554);
00610   }
00611 }
00612 
00613 // Stop(void)
00614 void nDevice::Stop(void) {
00615   // bail out
00616   if(mState!=Up && mState!=StartUp) return;
00617   FD_DH("nDevice::Stop()");
00618   // stop background threads
00619   LOCK_E;
00620   mStopListen=true;
00621   UNLOCK_E;
00622   // signal update to my listen thread: via udp message ... release select
00623   std::string message= "<Stop> " + mNetwork + " " + mName + " </Stop>\n";
00624   struct sockaddr_in broadcastaddr;
00625   memset(&broadcastaddr, '\0', sizeof(broadcastaddr));
00626   broadcastaddr.sin_family=AF_INET;
00627   broadcastaddr.sin_port=htons(mBroadcastAddress.Port());
00628   broadcastaddr.sin_addr.s_addr=inet_addr(mBroadcastAddress.Ip().c_str());
00629   LOCK_E;
00630   sendto(mBroadcastSocket,message.c_str(),message.length(),0,
00631      (struct sockaddr *) & broadcastaddr, sizeof(broadcastaddr));
00632   UNLOCK_E;
00633   // wait until listen thread finished ... implies all other threads finished too
00634   FD_DH("nDevice::Stop(): waiting for listen thread");
00635   faudes_thread_join(mThreadListen, NULL);
00636   FD_DH("nDevice::Stop(): listen thread finished");
00637   // close server socket
00638   shutdown(mListenSocket,2);
00639   faudes_closesocket(mListenSocket);
00640   mListenSocket=-1;
00641   // close broadcast socket
00642   shutdown(mBroadcastSocket,2);
00643   faudes_closesocket(mBroadcastSocket);
00644   mBroadcastSocket=-1;
00645   // call base (implies reset)
00646   vDevice::Stop();
00647 }
00648 
00649 
00650 
00651 // background thread, 
00652 // - receiving requests on on broadcast port 
00653 // - sending announce broadcats
00654 // - accept connections on listen port for output clients 
00655 // - notify connected output clients about events
00656 // - connecting to input servers to receiving notifications
00657 void* NDeviceListen(void* arg){
00658   bool term;
00659   std::map<std::string,nDevice::ServerState>::iterator sit;
00660   std::map<int,nDevice::ClientState>::iterator cit;
00661   // cast this object
00662   nDevice* ndevice= static_cast<nDevice*>(arg);
00663   // say hello
00664   FD_DH("nDevice::Listen(" << ndevice << ")");
00665   // clear broadcast time stamp
00666   timeval lastbroadcast;  
00667   lastbroadcast.tv_sec=0;
00668   lastbroadcast.tv_usec=0;
00669 #ifdef FAUDES_DEBUG_IODEVICE
00670   // clear debugging time stamp
00671   int debuglisten=0;
00672 #endif
00673 
00674   // infinite loop 
00675   while(true){
00676 
00677     // detect missing servers
00678     int servermis=0;
00679     for(sit=ndevice->mInputServerStates.begin(); sit!=ndevice->mInputServerStates.end(); sit++) {
00680       if(sit->second.mServerSocket>0) continue;
00681       FD_DH("nDevice::Listen(): missing server for node: " << sit->first);
00682       servermis++;
00683     }
00684 
00685     // detect missing clients (extension 2.22i, trust by number, should ask nodename on subscription)
00686     int clientmis= ndevice->mNetworkNodes.size()-1;
00687     for(cit=ndevice->mOutputClientStates.begin(); cit!=ndevice->mOutputClientStates.end(); cit++) {
00688       if(cit->second.mClientSocket<0) continue;
00689       if(cit->second.mConnected) clientmis--;
00690     }
00691 #ifdef FAUDES_DEBUG_IODEVICE
00692     if(clientmis!=servermis)
00693       FD_DH("nDevice::Listen(): missing clients to subscribe: #"<< clientmis);
00694 #endif
00695 
00696     // update state
00697     if((servermis>0 || clientmis>0) && ndevice->mState==vDevice::Up) {
00698       TLOCK_E;
00699       ndevice->mState=vDevice::StartUp;
00700       TUNLOCK_E;
00701     }
00702     if(servermis==0 && clientmis==0 && ndevice->mState==vDevice::StartUp) {
00703       TLOCK_E;
00704       ndevice->mState=vDevice::Up;
00705       TUNLOCK_E;
00706     }
00707 
00708     // try to find input servers
00709     if(servermis>0 && ndevice->mState==vDevice::StartUp) {
00710       // is a broadcast due? (period 5sec)
00711       timeval now;  
00712       gettimeofday(&now,0);
00713       if(now.tv_sec - lastbroadcast.tv_sec >5) {
00714         // udp message
00715         std::string message= "<Request> " 
00716           + ndevice->mNetwork + " " + ndevice->mName + " </Request>\n";
00717         // udp broadcast
00718         struct sockaddr_in broadcastaddr;
00719         memset(&broadcastaddr, '\0', sizeof(broadcastaddr));
00720         broadcastaddr.sin_family=AF_INET;
00721         broadcastaddr.sin_port=htons(ndevice->mBroadcastAddress.Port());
00722         broadcastaddr.sin_addr.s_addr=inet_addr(ndevice->mBroadcastAddress.Ip().c_str());
00723         TLOCK_E;
00724         int rc=sendto(ndevice->mBroadcastSocket,message.c_str(),message.length(),
00725           0,(struct sockaddr *) & broadcastaddr, sizeof(broadcastaddr));
00726         (void) rc;
00727         FD_DH("nDevice::Listen(): broadcast request: " <<  message.substr(0,message.length()-1) << " #" << rc);
00728         TUNLOCK_E;
00729         gettimeofday(&lastbroadcast,0);
00730       }
00731     }
00732 
00733     // subscribe to missing servers
00734     for(sit=ndevice->mInputServerStates.begin(); sit!=ndevice->mInputServerStates.end(); sit++) {
00735       // have active connection?
00736       if(sit->second.mServerSocket>0) continue;
00737       // have no address?
00738       if(!sit->second.mAddress.Valid()) continue;
00739       // try to connect
00740       FD_DH("nDevice::Listen(): subscribing to " << sit->first << 
00741           " at " << sit->second.mAddress.IpColonPort());
00742       // open a tcp port: create socket
00743       int serversock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
00744       if(serversock<=0) {
00745         FD_DH("nDevice::Listen(): subscription failed: no socket");
00746         continue;
00747       }
00748       // open a tcp port: set up internet address
00749       unsigned long int serverinaddr = INADDR_NONE;
00750       if(serverinaddr==INADDR_NONE) {
00751         FD_DH("nDevice::Listen(): using address as advertised");
00752         serverinaddr = inet_addr(sit->second.mAddress.Ip().c_str());
00753       }
00754       if(serverinaddr==INADDR_NONE) {
00755         struct hostent *host;
00756         host = gethostbyname(sit->second.mAddress.Ip().c_str());
00757         if(host!=0) {
00758           FD_DH("nDevice::Listen(): using address by name lookup");
00759           serverinaddr = *(unsigned long int*) host->h_addr;
00760         }
00761       }
00762       if(serverinaddr==INADDR_NONE) {
00763         FD_DH("nDevice::Listen(): subscription failed: invalid address " << sit->second.mAddress.Ip());
00764         faudes_closesocket(serversock);
00765         continue;
00766       }
00767       // open a tcp port: set up socket address 
00768       struct sockaddr_in serveraddress;
00769       memset(&serveraddress, 0, sizeof(serveraddress));
00770       serveraddress.sin_family = AF_INET;
00771       serveraddress.sin_addr.s_addr=serverinaddr; 
00772       serveraddress.sin_port = htons(sit->second.mAddress.Port());     
00773       // open a tcp port: connect
00774       if(connect(serversock, (struct sockaddr*) &serveraddress, sizeof(serveraddress))<0) {
00775         FD_DH("nDevice::Listen(): subscription failed: connect");
00776         faudes_closesocket(serversock);
00777         continue;
00778       }    
00779       // record success, say hello to remote input server
00780       FD_DH("nDevice::Listen(): subscribing to " << sit->first << " via socket " << serversock);
00781       sit->second.mServerSocket=serversock;
00782       std::string hello;
00783       hello="% Simplenet universal event subscription: "+ndevice->mName+" subscribing from "+sit->first+"\n"; 
00784       syncSend(serversock, hello.c_str(), hello.length(), 0);
00785       hello="% Expecting notifications in format '<Notify> event_name </Notify>'\n";
00786       syncSend(serversock, hello.c_str(), hello.length(), 0);
00787       hello="% Trying to subscribe all required events\n";
00788       syncSend(serversock, hello.c_str(), hello.length(), 0);
00789       // subscribe to input events
00790       EventSet sevents=ndevice->Inputs();
00791       sevents.Name("Subscribe");
00792       std::string message=sevents.ToString() + "\n";
00793       syncSend(serversock,message.c_str(), message.length(),0); 
00794       // used to get info in pre 2.22h 
00795       /*
00796       hello="% Going to Sending info command, explicit subscription may follow\n";
00797       hello="<Cmd> Info </Cmd>\n";
00798       syncSend(serversock, hello.c_str(), hello.length(), 0);
00799       */
00800       FD_DH("nDevice::Listen(): subscribing to " << sit->first << " via socket " << serversock << ": ok");
00801     }
00802 
00803 
00804     // prepare relevant wait on sources ... 
00805     fd_set mysocks;
00806     int mysocks_max=0;
00807     FD_ZERO(&mysocks);
00808     // ... my server listen socket, expecting other nodes to connect and subscribe
00809     if(mysocks_max<ndevice->mListenSocket) mysocks_max=ndevice->mListenSocket;
00810     if(mysocks_max>= FD_SETSIZE) FD_ERR("NDeviceListen: fail to select socket " << mysocks_max);
00811     FD_SET(ndevice->mListenSocket, &mysocks);
00812     // ... udp port, expecting requests and adverts 
00813     if(mysocks_max< ndevice->mBroadcastSocket) mysocks_max=ndevice->mBroadcastSocket;
00814     if(mysocks_max>= FD_SETSIZE) FD_ERR("NDeviceListen: fail to select socket " << mysocks_max);
00815     FD_SET(ndevice->mBroadcastSocket, &mysocks);
00816     // ... input server connections, expecting notifications
00817     for(sit=ndevice->mInputServerStates.begin(); sit!=ndevice->mInputServerStates.end(); sit++) {
00818       int serversock=sit->second.mServerSocket;
00819       if(serversock<0) continue;
00820       if(mysocks_max< serversock) mysocks_max=serversock;
00821       if(mysocks_max>= FD_SETSIZE) FD_ERR("NDeviceListen: fail to select socket " << mysocks_max);
00822       FD_SET(serversock, &mysocks);
00823     }
00824     // ... output client connections, expecting commands
00825     for(cit=ndevice->mOutputClientStates.begin(); cit!=ndevice->mOutputClientStates.end(); cit++) {
00826       int clientsock=cit->second.mClientSocket;
00827       if(clientsock<0) continue;
00828       if(mysocks_max< clientsock) mysocks_max=clientsock;
00829       if(mysocks_max>= FD_SETSIZE) FD_ERR("NDeviceListen: fail to select socket " << mysocks_max);
00830       FD_SET(clientsock, &mysocks);
00831     }
00832 
00833     // wait for traffic with moderate timeout 
00834     struct timeval tv;
00835     tv.tv_sec =  1;
00836     tv.tv_usec = 0;
00837     int avail=select(mysocks_max+1, &mysocks, NULL, NULL, &tv);
00838 
00839     // reduce debugging output
00840     #ifdef FAUDES_DEBUG_IODEVICE
00841     debuglisten++;
00842     if(debuglisten>10) {    
00843       FD_DH("nDevice::Listen(): listen as node \"" << ndevice->mName << "\" on network \"" << ndevice->mNetwork << "\"" << " #" << avail);
00844       debuglisten=0;
00845     }
00846     #endif
00847 
00848     // handle incomming connection requests
00849     if(avail>0)  
00850     if(FD_ISSET(ndevice->mListenSocket,&mysocks)) {
00851       avail--;
00852       int clientsock=-1;
00853       struct sockaddr_in clientaddr;
00854       socklen_t clientaddr_len = sizeof(clientaddr);
00855       clientsock=accept(ndevice->mListenSocket, (struct sockaddr *) &clientaddr, &clientaddr_len );
00856       if(clientsock<0) {
00857         FD_DH("nDevice::Listen(): failed to accept incomming connection");
00858         break;
00859       }
00860       FD_DH("nDevice::Listen(): accepted connection from client " << inet_ntoa(clientaddr.sin_addr) << 
00861         " on socket " << clientsock);
00862       // record client by socket
00863       TLOCK_E;
00864       nDevice::ClientState* cstate = &ndevice->mOutputClientStates[clientsock];
00865       cstate->mClientSocket=clientsock;
00866       cstate->mEvents.Clear();
00867       cstate->mConnected=false;
00868       cstate->mLineBuffer="";
00869       TUNLOCK_E;
00870       // say hello
00871       std::string hello;
00872       hello="% Simplenet Event Server: "+ndevice->mName+" providing events\n";
00873       syncSend(clientsock, hello.c_str(), hello.length(), 0);
00874       hello="% Notifications will have format '<Notify> event_name </Notify>'\n";
00875       syncSend(clientsock, hello.c_str(), hello.length(), 0);
00876       hello="% Commands are accepted in format '<Cmd> cmd_name </Cmd>'\n";
00877       syncSend(clientsock, hello.c_str(), hello.length(), 0);
00878       hello="% Supported commands are Info, Status, and ResetRequest\n";
00879       syncSend(clientsock, hello.c_str(), hello.length(), 0);
00880     }
00881 
00882     // handle incomming broadcast
00883     if(avail>0)  
00884     if(FD_ISSET(ndevice->mBroadcastSocket,&mysocks)) {
00885       avail--;
00886       // get message
00887       char data[1024]; 
00888       int data_len=1023;
00889       struct sockaddr_in fromaddr;
00890       socklen_t fromaddr_len = sizeof(fromaddr);
00891       data_len=recvfrom(ndevice->mBroadcastSocket,data,data_len,0, (struct sockaddr*) &fromaddr,&fromaddr_len);
00892       if(data_len<0) data_len=0; // todo:  eof
00893       data[data_len]=0;
00894       if(data_len>=1) if(data[data_len-1]=='\n') data[data_len-1]=0;
00895       FD_DH("nDevice::Listen(): received udp datagram " << data << 
00896          " from " << inet_ntoa(fromaddr.sin_addr));
00897       // interpret message
00898       TokenReader tr(TokenReader::String,std::string(data));
00899       try {
00900         Token token;
00901         tr.Peek(token);
00902         // interpret udp request ...
00903         if(token.IsBegin("Request")) {
00904     tr.ReadBegin("Request");
00905           if(tr.ReadString()==ndevice->mNetwork) {
00906             // extension 2.22i: identify sender (optional for compatibility)
00907       std::string snode;
00908             Token stoken;
00909             tr.Peek(stoken);
00910             if(stoken.IsString()) snode=stoken.StringValue();
00911             // extension 2.22i: if this is missing server, reset my request timer
00912             sit=ndevice->mInputServerStates.find(snode);
00913             if(sit!=ndevice->mInputServerStates.end()) {
00914         if(sit->second.mServerSocket==-1) {
00915                 lastbroadcast.tv_sec=0;
00916                 lastbroadcast.tv_usec=0;
00917         }
00918       }
00919             // extension 2.22i: ignore my own requests
00920             if(snode!=ndevice->mName) {
00921               // set up advert
00922               std::string message= "<Advert> " 
00923                   + ndevice->mNetwork + " " 
00924                   + ndevice->mName    + " " +
00925             ndevice->mEffectiveListenAddress.IpColonPort()+ "  </Advert>\n"; 
00926               // udp reply
00927               struct sockaddr_in replyaddr;
00928               memset(&replyaddr, '\0', sizeof(replyaddr));
00929               replyaddr.sin_family=AF_INET;
00930               replyaddr.sin_port=htons(ndevice->mBroadcastAddress.Port());
00931               //replyaddr.sin_addr.s_addr=fromaddr.sin_addr.s_addr;
00932               replyaddr.sin_addr.s_addr=inet_addr(ndevice->mBroadcastAddress.Ip().c_str());
00933               //replyaddr.sin_addr.s_addr=htonl(INADDR_BROADCAST);
00934               TLOCK_E;
00935               int rc = sendto(ndevice->mBroadcastSocket,message.c_str(),message.length(),0,(struct sockaddr *) & replyaddr, sizeof(replyaddr));
00936         TUNLOCK_E
00937           FD_DH("nDevice::Listen(): reply advert: " <<  message.substr(0,message.length()-1) << " #" << rc);
00938       } else {
00939               FD_DH("nDevice::Listen(): ingoring request from myself");
00940       }
00941     } else {
00942             FD_DH("nDevice::Listen(): ingoring request from other network");
00943     }
00944   }
00945         // interpret udp advert ...
00946         if(token.IsBegin("Advert")) {
00947     tr.ReadBegin("Advert");
00948           if(tr.ReadString()==ndevice->mNetwork) {
00949             std::string node = tr.ReadString();
00950             std::string saddr = tr.ReadString();
00951             SimplenetAddress addr(saddr);
00952             addr.Ip(inet_ntoa(fromaddr.sin_addr)); // overwrite with actual ip
00953             FD_DHV("nDevice::Listen(): figure actual ip address " << addr.Ip());
00954             if(!addr.Valid()) {
00955               addr=saddr;
00956               FD_DH("nDevice::Listen(): fallback to explicit ip address " << addr.Ip());
00957       }
00958             std::map<std::string,nDevice::ServerState>::iterator sit;
00959             sit=ndevice->mInputServerStates.find(node);
00960             if(sit==ndevice->mInputServerStates.end()) { 
00961               FD_DH("nDevice::Listen(): ignoring irrelevant advert (myself?) " << node);
00962             } else if(sit->second.mAddress.Valid()) {
00963               FD_DH("nDevice::Listen(): ignoring address overwrite (hardwired?) " << node);
00964       }
00965             if(sit!=ndevice->mInputServerStates.end())  
00966       if(!sit->second.mAddress.Valid()) {
00967               FD_DH("nDevice::Listen(): accept advert " << node);
00968               sit->second.mAddress=addr;
00969               if(sit->second.mServerSocket>=0) faudes_closesocket(sit->second.mServerSocket);
00970               sit->second.mServerSocket=-1;
00971       }
00972           } else {
00973             FD_DH("nDevice::Listen(): ingoring advert from other network");
00974     }
00975         }
00976       } catch (faudes::Exception&) {
00977         FD_DH("nDevice::Listen(): ignore invalid udp message");
00978       }
00979     }
00980        
00981 
00982     // handle input servers: receive event notification 
00983     int revcount=0;
00984     if(avail>0)  
00985     for(sit=ndevice->mInputServerStates.begin(); sit!=ndevice->mInputServerStates.end(); sit++) {
00986       int serversock=sit->second.mServerSocket;
00987       if(serversock<0) continue;
00988       if(FD_ISSET(serversock, &mysocks)) {
00989         avail--;
00990         FD_DH("nDevice::Listen(): reading sock " <<  serversock);
00991         // buffer data in line buffer
00992         char buffer[1025];
00993         int count = recv(serversock, buffer, 1024, 0);
00994         if(count<=0) { // todo: test eof
00995           FD_DH("nDevice::Listen(): reading sock " <<  serversock << " : eof");
00996           faudes_closesocket(serversock); 
00997           sit->second.mServerSocket=-1;
00998           continue;          
00999         } 
01000         FD_DH("nDevice::Listen(): reading server sock " <<  serversock  << ": #" << count);
01001         buffer[count]=0;
01002         sit->second.mLineBuffer +=std::string(buffer);
01003         // interpret line(s)
01004         if(count>0) 
01005         if(buffer[count-1]=='\n') 
01006         if(sit->second.mLineBuffer.length()>0) 
01007         {
01008           const std::string& linebuffer = sit->second.mLineBuffer;
01009 #ifdef FAUDES_DEBUG_IODEVICE
01010           if(linebuffer.length()>0)
01011     if(linebuffer[0]!='%')
01012            FD_DH("nDevice::Listen(): reading server sock " <<  serversock  << ": line: " << linebuffer);
01013 #endif
01014           // tokenise notification
01015           TokenReader tr(TokenReader::String,linebuffer);
01016           try {
01017             Token token;
01018             while(tr.Peek(token)) {
01019               // its an event notify
01020               if(token.Type()==Token::Begin && token.StringValue()=="Notify") {
01021                 tr.ReadBegin("Notify");
01022             std::string event = tr.ReadString();
01023                 tr.ReadEnd("Notify");
01024                 faudes_mutex_lock(ndevice->pBufferMutex);
01025                 FD_DH("nDevice::Listen(): found event " << event);
01026                 Idx sev=ndevice->mInputs.Index(event);
01027                 if(ndevice->mInputs.Exists(sev)) ndevice->pInputBuffer->push_back(sev);
01028                 faudes_mutex_unlock(ndevice->pBufferMutex);
01029                 revcount++;
01030           continue;
01031               }
01032               // its an info reply (ignored as of 2.22i)
01033               if(token.Type()==Token::Begin && token.StringValue()=="SimplenetDevice") {
01034                 FD_DH("nDevice::Listen(): found device info");
01035           nDevice remote;
01036                 remote.Read(tr);
01037                 FD_DH("nDevice::Listen(): found device with outputs " << remote.Outputs().ToString());      
01038                 // used to subscribe on relevant events in pre 2.22h
01039                 /*   
01040                 EventSet sevents=ndevice->Inputs();
01041                 sevents.SetIntersection(remote.Outputs());
01042           sevents.Name("Subscribe");
01043           std::string message=sevents.ToString();
01044                 FD_DH("nDevice::Listen(): subscribing events " << message);
01045                 message += "\n";
01046                 syncSend(serversock,message.c_str(), message.length(),0); 
01047                 */
01048           continue;
01049               }
01050               // skip other sections
01051               if(token.Type()==Token::Begin) {
01052                 FD_DH("nDevice::Listen(): ignore section " << token.StringValue());
01053     std::string section=token.StringValue();
01054                 tr.ReadBegin(section);
01055           while(!tr.Eos(section)) tr.Get(token);
01056                 tr.ReadEnd(section);
01057           continue;
01058         }
01059               // ignore token
01060               FD_DH("nDevice::Listen(): error: ignore token");
01061               tr.Get(token);
01062             }
01063           } catch (faudes::Exception&) {
01064             FD_DH("nDevice::Listen(): " <<  serversock  << ": invalid notification");
01065           }
01066           sit->second.mLineBuffer.clear();
01067   }
01068       }
01069     }
01070 
01071     // handle output clients: reply to commands 
01072     if(avail>0)  
01073     for(cit=ndevice->mOutputClientStates.begin(); cit!=ndevice->mOutputClientStates.end(); cit++) {
01074       int clientsock=cit->second.mClientSocket;
01075       if(clientsock<0) continue;
01076       if(FD_ISSET(clientsock, &mysocks)) {
01077         avail--;
01078         FD_DH("nDevice::Listen(): reading client sock " <<  clientsock);
01079         // buffer data in line buffer
01080         char buffer[1025];
01081         int count = recv(clientsock, buffer, 1024, 0);
01082         if(count<=0) { // todo: test eof
01083           FD_DH("nDevice::Listen(): reading client sock " <<  clientsock << " : eof");
01084           faudes_closesocket(clientsock); 
01085           cit->second.mClientSocket=-1;
01086           continue;          
01087         } 
01088         FD_DH("nDevice::Listen(): reading client sock " <<  clientsock  << ": #" << count);
01089         buffer[count]=0;
01090         cit->second.mLineBuffer +=std::string(buffer);
01091         // interpret line(s)
01092         if(count>0) 
01093         if(buffer[count-1]=='\n') 
01094         if(cit->second.mLineBuffer.length()>0) 
01095         {
01096           const std::string& linebuffer = cit->second.mLineBuffer;
01097 #ifdef FAUDES_DEBUG_IODEVICE
01098           if(linebuffer.length()>0)
01099     if(linebuffer[0]!='%')
01100            FD_DH("nDevice::Listen(): reading client sock " <<  clientsock  << ": line: " << linebuffer);
01101 #endif
01102           // tokenise command
01103           TokenReader tr(TokenReader::String,linebuffer);
01104           try {
01105             Token token;
01106             while(tr.Peek(token)) {
01107               // its a command
01108               if(token.IsBegin("Cmd")) { 
01109             tr.ReadBegin("Cmd");
01110           std::string cmd = tr.ReadString();
01111             tr.ReadEnd("Cmd");
01112                 std::string response="<NAck> </NAck>\n";
01113                 FD_DH("nDevice::Reply(" <<  clientsock  << "): received cmd " << cmd);
01114                 // command: info
01115                 if(cmd=="Info") {
01116                   TLOCK_E;
01117                   response=ndevice->ToString() + "\n";
01118                   TUNLOCK_E;
01119                 }
01120                 // command: status
01121                 if(cmd=="Status") {
01122                   TLOCK_E;
01123                   if(ndevice->mState==vDevice::Up) response="<Ack> Up </Ack>\n";
01124                   if(ndevice->mState==vDevice::StartUp) response="<Ack> StartUp </Ack>\n";
01125                   if(ndevice->mState==vDevice::ShutDown) response="<Ack> ShutDown </Ack>\n";
01126                   TUNLOCK_E;
01127                 }
01128                 // its a reset request
01129                 if(cmd=="ResetRequest") {
01130                   FD_DH("nDevice::Reply(" <<  clientsock  << "): reset request");
01131                   faudes_mutex_lock(ndevice->pBufferMutex);
01132             if(!ndevice->mResetRequest) revcount++;   
01133             ndevice->mResetRequest=true;
01134                   faudes_mutex_unlock(ndevice->pBufferMutex);
01135                   response="";
01136             }
01137                 // send reply
01138                 syncSend(clientsock, response.c_str(), response.length(), 0);
01139         }
01140               // its a event subscription
01141               if(token.IsBegin("Subscribe")) {  
01142             EventSet sevents;
01143                 sevents.Read(tr,"Subscribe");
01144                 sevents.RestrictSet(ndevice->Outputs());
01145                 sevents.Name("Subscribed");
01146                 FD_DH("nDevice::Reply(" <<  clientsock  << "): providing events " << sevents.ToString());
01147                 TLOCK_E;
01148                 cit->second.mEvents.Clear();              
01149                 cit->second.mEvents.InsertSet(sevents);
01150                 cit->second.mConnected=true;
01151           std::string response=sevents.ToString()+"\n";
01152                 TUNLOCK_E;
01153                 // send reply
01154                 syncSend(clientsock, response.c_str(), response.length(), 0);
01155         }
01156       }
01157           } catch (faudes::Exception&) {
01158             FD_DH("nDevice::Reply(" <<  clientsock  << "): invalid cmd");
01159           }
01160           cit->second.mLineBuffer.clear();
01161     }
01162       }
01163     }
01164 
01165 
01166     // signal condition for received events / reset requests
01167     if(revcount>0) {
01168       FD_DH("nDevice::Listen(): broadcast condition");
01169       faudes_mutex_lock(ndevice->pWaitMutex);
01170       faudes_cond_broadcast(ndevice->pWaitCondition);
01171       faudes_mutex_unlock(ndevice->pWaitMutex);
01172       revcount=0;
01173     }
01174 
01175     // should remove unconnected clients ?
01176 
01177 
01178     // some error
01179     if(avail<0) {
01180       FD_DH("nDevice::Listen(): select error");
01181     }
01182 
01183     // terminate thread on request
01184     TLOCK_E;
01185     term= ndevice->mStopListen;
01186     TUNLOCK_E; 
01187     if(term) break;
01188   }
01189 
01190   // close clientsockets
01191   FD_DH("nDevice::Listen(): close client sockets");
01192   TLOCK_E;
01193   for(cit=ndevice->mOutputClientStates.begin(); cit!=ndevice->mOutputClientStates.end(); cit++) {
01194     int clientsock= cit->second.mClientSocket;
01195     if(clientsock>0) faudes_closesocket(clientsock);
01196     cit->second.mClientSocket=-1;
01197   }
01198   ndevice->mOutputClientStates.clear();
01199   TUNLOCK_E; 
01200   // close serversockets
01201   FD_DH("nDevice::Listen(): close server sockets");
01202   for(sit=ndevice->mInputServerStates.begin(); sit!=ndevice->mInputServerStates.end(); sit++) {
01203     int serversock=sit->second.mServerSocket;
01204     if(serversock>0) faudes_closesocket(serversock);
01205     sit->second.mServerSocket=-1;
01206   }
01207   FD_DH("nDevice::Listen(): terminating listen thread");
01208   faudes_thread_exit(NULL);
01209   return NULL;
01210 }
01211 
01212 
01213 
01214 
01215 // reset dynamic faudes state (buffered events, current time)
01216 void nDevice::Reset(void) {
01217   // call base for time and input buffer
01218   vDevice::Reset();
01219   // bail out (do notify clients even when servers incomplete)
01220   if(mState!=Up && mState!=StartUp) return;
01221   // have message
01222   std::string message= "<Cmd> ResetRequest </Cmd>\n";
01223   // send cmd to all my servers
01224   LOCK_E;
01225   std::map<std::string,ServerState>::iterator sit=mInputServerStates.begin();
01226   for(; sit!=mInputServerStates.end(); sit++) {
01227     int serversock=sit->second.mServerSocket;
01228     if(serversock<0) continue;
01229     FD_DH("nDevice::Reset(): sending reset request to socket " << serversock);
01230     syncSend(serversock, message.c_str(), message.length(), 0);
01231   }
01232   UNLOCK_E;
01233 }
01234 
01235 
01236 #endif // configured simplenet
01237 
01238 
01239 } // name space
01240 
01241 
01242 

libFAUDES 2.22k --- 2013.04.02 --- c++ source docu by doxygen