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

libFAUDES 2.23h --- 2014.04.03 --- c++ api documentaion by doxygen