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

libFAUDES 2.16b --- 2010-9-8 --- c++ source docu by doxygen 1.6.3