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("vDevice::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("vDevice::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("vDevice::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("vDevice::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("vDevice::WriteActuator(): to socket " << clientsock);
00420     syncSend(clientsock, message.c_str(), message.length(), 0);
00421   }
00422   UNLOCK_E;
00423   FD_DH("vDevice::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   // close server socket
00551   shutdown(mServerSocket,2);
00552   close(mServerSocket);
00553   mServerSocket=-1;
00554   // close broadcast socket
00555   shutdown(mBroadcastSocket,2);
00556   close(mBroadcastSocket);
00557   mBroadcastSocket=-1;
00558   // call base
00559   vDevice::Stop();
00560 }
00561 
00562 
00563 
00564 // background thread, listening on my port for clients to connect
00565 void* NDeviceListen(void* arg){
00566   bool term;
00567   std::map<std::string,nDevice::ServerState>::iterator sit;
00568   std::map<int,nDevice::ClientState>::iterator cit;
00569   // cast this object
00570   nDevice* ndevice= static_cast<nDevice*>(arg);
00571   // say hello
00572   FD_DH("nDevice::Listen(" << ndevice << ")");
00573   // clear broadcast time stamp
00574   timeval lastbroadcast;  
00575   lastbroadcast.tv_sec=0;
00576   lastbroadcast.tv_usec=0;
00577 
00578   // infinite loop 
00579   while(true){
00580 
00581     // report missing servers
00582     int missing=0;
00583     for(sit=ndevice->mSensorServerStates.begin(); sit!=ndevice->mSensorServerStates.end(); sit++) {
00584       if(sit->second.mServerSocket>0) continue;
00585       FD_DH("nDevice::Listen(): missing server for node " << sit->first);
00586       missing++;
00587     }
00588     if(missing>0 && ndevice->mState==vDevice::Up) {
00589       TLOCK_E;
00590       ndevice->mState=vDevice::StartUp;
00591       TUNLOCK_E;
00592     }
00593     if(missing==0 && ndevice->mState==vDevice::StartUp) {
00594       TLOCK_E;
00595       ndevice->mState=vDevice::Up;
00596       TUNLOCK_E;
00597     }
00598     if(missing>0 && ndevice->mState==vDevice::StartUp) {
00599       // is a broadcast due?
00600       timeval now;  
00601       gettimeofday(&now,0);
00602       if(now.tv_sec - lastbroadcast.tv_sec >5) {
00603         // udp message
00604         std::string message= "<Request> \"" + ndevice->mNetwork + "\" </Request>\n";
00605         // udp broadcast
00606         struct sockaddr_in broadcastaddr;
00607         broadcastaddr.sin_family=AF_INET;
00608         broadcastaddr.sin_port=htons(FAUDES_IODEVICE_BROADCASTPORT);
00609         broadcastaddr.sin_addr.s_addr=htonl(INADDR_BROADCAST);
00610         TLOCK_E;
00611         int rc=sendto(ndevice->mBroadcastSocket,message.c_str(),message.length(),0,(struct sockaddr *) & broadcastaddr, sizeof(broadcastaddr));
00612         (void) rc;
00613         FD_DH("nDevice::Listen(): broadcast message: " <<  message.substr(0,message.length()-1) << " #" << rc);
00614         TUNLOCK_E;
00615         gettimeofday(&lastbroadcast,0);
00616       }
00617     }
00618 
00619     // initiate/maintaine subscriptions
00620     for(sit=ndevice->mSensorServerStates.begin(); sit!=ndevice->mSensorServerStates.end(); sit++) {
00621       // have active connection?
00622       if(sit->second.mServerSocket>0) continue;
00623       // have an address?
00624       if(!sit->second.mAddress.Valid()) continue;
00625       // try to connect
00626       FD_DH("nDevice::Listen(): subscribing to " << sit->first << 
00627           " at " << sit->second.mAddress.IpColonPort());
00628       // open a tcp port: create socket
00629       int serversock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
00630       if(serversock<=0) {
00631         FD_DH("nDevice::Listen(): subscription failed: no socket");
00632         continue;
00633       }
00634       // open a tcp port: set up internet address
00635       unsigned long int serverinaddr = INADDR_NONE;
00636       if(serverinaddr==INADDR_NONE) {
00637         FD_DH("nDevice::Listen(): using address in dot format");
00638         serverinaddr = inet_addr(sit->second.mAddress.Ip().c_str());
00639       }
00640       if(serverinaddr==INADDR_NONE) {
00641         struct hostent *host;
00642         host = gethostbyname(sit->second.mAddress.Ip().c_str());
00643         if(host!=0) {
00644           FD_DH("nDevice::Listen(): unsing address by name lookup");
00645           serverinaddr = *(unsigned long int*) host->h_addr;
00646         }
00647       }
00648       if(serverinaddr==INADDR_NONE) {
00649         FD_DH("nDevice::Listen(): subscription failed: invalid address " << sit->second.mAddress.Ip());
00650         close(serversock);
00651         continue;
00652       }
00653       // open a tcp port: set up socket address 
00654       struct sockaddr_in serveraddress;
00655       memset(&serveraddress, 0, sizeof(serveraddress));
00656       serveraddress.sin_family = AF_INET;
00657       serveraddress.sin_addr.s_addr=serverinaddr; 
00658       serveraddress.sin_port = htons(sit->second.mAddress.Port());     
00659       // open a tcp port: connect
00660       if(connect(serversock, (struct sockaddr*) &serveraddress, sizeof(serveraddress))<0) {
00661         FD_DH("nDevice::Listen(): subscription failed: connect");
00662         close(serversock);
00663         continue;
00664       }    
00665       // record success, say hello to remote sensor server, ask for info
00666       FD_DH("nDevice::Listen(): subscribing to " << sit->first << " via socket " << serversock);
00667       sit->second.mServerSocket=serversock;
00668       std::string hello;
00669       hello="% Simplenet universal event subscription: \""+ndevice->mName+"\" subscribing from \""+sit->first+"\"\n"; 
00670       syncSend(serversock, hello.c_str(), hello.length(), 0);
00671       hello="% Expecting notifications in format '<Notify> \"event_name\" </Notify>'\n";
00672       syncSend(serversock, hello.c_str(), hello.length(), 0);
00673       hello="% Sending info command, explicit subscription may follow\n";
00674       syncSend(serversock, hello.c_str(), hello.length(), 0);
00675       hello="<Cmd> \"Info\" </Cmd>\n";
00676       syncSend(serversock, hello.c_str(), hello.length(), 0);
00677       FD_DH("nDevice::Listen(): subscribing to " << sit->first << " via socket " << serversock << ": ok");
00678     }
00679 
00680     // prepare relevant  on sources ... 
00681     fd_set mysocks;
00682     int mysocks_max=0;
00683     FD_ZERO(&mysocks);
00684     // ... my server listen socket , expecting other nodes to subscribe
00685     FD_SET(ndevice->mServerSocket, &mysocks);
00686     if(mysocks_max<ndevice->mServerSocket) mysocks_max=ndevice->mServerSocket;
00687     // ... udp port, expecting requests and adverts 
00688     FD_SET(ndevice->mBroadcastSocket, &mysocks);
00689     if(mysocks_max< ndevice->mBroadcastSocket) mysocks_max=ndevice->mBroadcastSocket;
00690     // ... sensor server connections, expecting notifications
00691     for(sit=ndevice->mSensorServerStates.begin(); sit!=ndevice->mSensorServerStates.end(); sit++) {
00692       int serversock=sit->second.mServerSocket;
00693       if(serversock<0) continue;
00694       FD_SET(serversock, &mysocks);
00695       if(mysocks_max< serversock) mysocks_max=serversock;
00696     }
00697 
00698     // wait for traffic with moderate timeout 
00699     struct timeval tv;
00700     tv.tv_sec = 10;
00701     tv.tv_usec = 0;
00702     FD_DH("nDevice::Listen(): listen as node \"" << ndevice->mName << "\" on network \"" << ndevice->mNetwork << "\"");
00703     int avail=select(mysocks_max+1, &mysocks, NULL, NULL, &tv);
00704 
00705     // handle request for subscription
00706     if(avail>0)  if(FD_ISSET(ndevice->mServerSocket,&mysocks)) {
00707       int clientsock=-1;
00708       struct sockaddr_in clientaddr;
00709       socklen_t clientaddr_len = sizeof(clientaddr);
00710       clientsock=accept(ndevice->mServerSocket, (struct sockaddr *) &clientaddr, &clientaddr_len );
00711       if(clientsock<0) {
00712         FD_DH("nDevice::Listen(): failed to accept incomming connection");
00713         break;
00714       }
00715       FD_DH("nDevice::Listen(): connection request from " << inet_ntoa(clientaddr.sin_addr));
00716       // lock for client data base
00717       TLOCK_E;
00718       // record client
00719       nDevice::ClientState* cstate = &ndevice->mActuatorClientStates[clientsock];
00720       cstate->mDevice=ndevice;
00721       cstate->mClientSocket=clientsock;
00722       // start server thread for new client
00723       pthread_attr_t attr;  
00724       pthread_attr_init(&attr);
00725       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00726       pthread_t clientthread;
00727       int rc = pthread_create(&clientthread, &attr, NDeviceReply,cstate);
00728       pthread_attr_destroy(&attr);
00729       cstate->mThread=clientthread;
00730       // unlock for client data base
00731       TUNLOCK_E;
00732       // pthread error 
00733       if(rc) {
00734         std::stringstream errstr;
00735         errstr << "Simplenet fatal pthread error (cannot create thread)";
00736         throw Exception("nDevice::Listen()", errstr.str(), 554);
00737       }
00738     }
00739 
00740     // handle incomming broadcast
00741     if(avail>0)  
00742     if(FD_ISSET(ndevice->mBroadcastSocket,&mysocks)) {
00743       // get message
00744       char data[1024]; 
00745       int data_len=1023;
00746       struct sockaddr_in fromaddr;
00747       socklen_t fromaddr_len = sizeof(fromaddr);
00748       data_len=recvfrom(ndevice->mBroadcastSocket,data,data_len,0, (struct sockaddr*) &fromaddr,&fromaddr_len);
00749       if(data_len<0) data_len=0; // todo:  eof
00750       data[data_len]=0;
00751       if(data_len>=1) if(data[data_len-1]=='\n') data[data_len-1]=0;
00752       FD_DH("nDevice::Listen(): received udp datagram " << data << 
00753          " from " << inet_ntoa(fromaddr.sin_addr));
00754       // interpret message
00755       TokenReader tr(TokenReader::String,std::string(data));
00756       try {
00757         Token token;
00758         tr.Peek(token);
00759         // interpret udp request ...
00760         if(token.Type()==Token::Begin && token.StringValue()=="Request") {
00761     tr.ReadBegin("Request");
00762           if(tr.ReadString()==ndevice->mNetwork) {
00763             // set up advert
00764             std::string message= "<Advert> \"" 
00765                 + ndevice->mNetwork + "\" \"" 
00766                 + ndevice->mName    + "\"" +
00767           " \"" + ndevice->mEffectiveAddress.IpColonPort() +"\"" +  
00768                 "  </Advert>\n"; 
00769             FD_DH("nDevice::Listen(): reply advert: " <<  message.substr(0,message.length()-1));
00770             // udp broadcast
00771             struct sockaddr_in broadcastaddr;
00772             broadcastaddr.sin_family=AF_INET;
00773             broadcastaddr.sin_port=htons(FAUDES_IODEVICE_BROADCASTPORT);
00774             broadcastaddr.sin_addr.s_addr=htonl(INADDR_BROADCAST);
00775             TLOCK_E;
00776             sendto(ndevice->mBroadcastSocket,message.c_str(),message.length(),0,(struct sockaddr *) & broadcastaddr, sizeof(broadcastaddr));
00777       TUNLOCK_E
00778           } else {
00779             FD_DH("nDevice::Listen(): ingoring request from other network");
00780     }
00781   }
00782         // interpret udp advert ...
00783         if(token.Type()==Token::Begin && token.StringValue()=="Advert") {
00784     tr.ReadBegin("Advert");
00785           if(tr.ReadString()==ndevice->mNetwork) {
00786             std::string node = tr.ReadString();
00787             std::string saddr = tr.ReadString();
00788             SimplenetAddress addr(saddr);
00789             addr.Ip(inet_ntoa(fromaddr.sin_addr)); // overwrite with actual ip
00790             FD_DH("nDevice::Listen(): accepting advert from my network");
00791             ndevice->InsertNodeAddress(node,addr);
00792     } else {
00793             FD_DH("nDevice::Listen(): ingoring advert from other network");
00794           }
00795         }
00796       } catch (faudes::Exception&) {
00797         FD_DH("nDevice::Listen(): invalid udp message");
00798       }
00799     }
00800        
00801 
00802     // handle event notification and other commands from remote sensor servers
00803     if(avail>0)  
00804     if(!FD_ISSET(ndevice->mServerSocket,&mysocks)) 
00805     if(!FD_ISSET(ndevice->mBroadcastSocket,&mysocks)) {
00806       for(sit=ndevice->mSensorServerStates.begin(); sit!=ndevice->mSensorServerStates.end(); sit++) {
00807         int serversock=sit->second.mServerSocket;
00808   if(serversock<0) continue;
00809   if(FD_ISSET(serversock, &mysocks)) {
00810           FD_DH("nDevice::Listen(): reading sock " <<  serversock);
00811           // buffer data in line buffer
00812           char buffer[1025];
00813           int count = recv(serversock, buffer, 1024, 0);
00814           if(count<=0) { // todo: test eof
00815             FD_DH("nDevice::Listen(): reading sock " <<  serversock << " : eof");
00816             close(serversock); 
00817             sit->second.mServerSocket=-1;
00818             continue;
00819           } 
00820           FD_DH("nDevice::Listen(): reading sock " <<  serversock  << ": #" << count);
00821           buffer[count]=0;
00822           sit->second.mLineBuffer +=std::string(buffer);
00823           // interpret line(s)
00824           if(count>0) 
00825           if(buffer[count-1]=='\n') 
00826           if(sit->second.mLineBuffer.length()>0) 
00827           {
00828             const std::string& linebuffer = sit->second.mLineBuffer;
00829             FD_DH("nDevice::Listen(): " <<  serversock  << ": line: " << linebuffer);
00830             // tokenise notification
00831             TokenReader tr(TokenReader::String,linebuffer);
00832             int ncount=0;
00833             try {
00834               Token token;
00835               while(tr.Peek(token)) {
00836                 // its an event notify
00837                 if(token.Type()==Token::Begin && token.StringValue()=="Notify") {
00838                   tr.ReadBegin("Notify");
00839               std::string event = tr.ReadString();
00840                   tr.ReadEnd("Notify");
00841                   pthread_mutex_lock(ndevice->pBufferMutex);
00842                   FD_DH("nDevice::Listen(): found event " << event);
00843                   Idx sev=ndevice->mSensors.Index(event);
00844                   if(sev) ndevice->pSensorBuffer->push_back(sev);
00845                   pthread_mutex_unlock(ndevice->pBufferMutex);
00846                   ncount++;
00847                 }
00848                 // its an info
00849                 if(token.Type()==Token::Begin && token.StringValue()=="SimplenetDevice") {
00850                   FD_DH("nDevice::Listen(): found device info");
00851       nDevice remote;
00852                   remote.Read(tr);
00853                   FD_DH("nDevice::Listen(): found device with actuators " << remote.Actuators().ToString());      
00854                   EventSet sevents=ndevice->Sensors();
00855                   sevents.SetIntersection(remote.Actuators());
00856       sevents.Name("Subscribe");
00857       std::string message=sevents.ToString();
00858                   FD_DH("nDevice::Listen(): subscribing events " << message);
00859                   message += "\n";
00860                   syncSend(serversock,message.c_str(), message.length(),0);
00861                 }
00862               }
00863             } catch (faudes::Exception&) {
00864               FD_DH("nDevice::Listen(): " <<  serversock  << ": invalid notification");
00865       }
00866             sit->second.mLineBuffer.clear();
00867             // signal condition
00868             if(ncount>0) {
00869               FD_DH("nDevice::Listen(): broadcast condition");
00870               pthread_mutex_lock(ndevice->pWaitMutex);
00871               pthread_cond_broadcast(ndevice->pWaitCondition);
00872               pthread_mutex_unlock(ndevice->pWaitMutex);
00873             }
00874     }
00875   }
00876       }
00877     }
00878 
00879     // some error
00880     if(avail<0) {
00881       FD_DH("nDevice::Listen(): select error");
00882     }
00883 
00884     // terminate thread on request
00885     TLOCK_E;
00886     term= ndevice->mStopListen;
00887     TUNLOCK_E; 
00888     if(term) break;
00889   }
00890 
00891   // enforce reply threads to terminate
00892   FD_DH("nDevice::Listen(): cancel reply threads");
00893   TLOCK_E;
00894   for(cit=ndevice->mActuatorClientStates.begin(); cit!=ndevice->mActuatorClientStates.end(); cit++) {
00895     pthread_cancel(cit->second.mThread);
00896   }
00897   TUNLOCK_E; 
00898   FD_DH("nDevice::Listen(): close reply sockts");
00899   TLOCK_E;
00900   for(cit=ndevice->mActuatorClientStates.begin(); cit!=ndevice->mActuatorClientStates.end(); cit++) {
00901     int clientsock= cit->second.mClientSocket;
00902     if(clientsock>0) close(clientsock);
00903     cit->second.mClientSocket=-1;
00904   }
00905   TUNLOCK_E; 
00906   FD_DH("nDevice::Listen(): discard client data");
00907   TLOCK_E;
00908   ndevice->mActuatorClientStates.clear();
00909   TUNLOCK_E; 
00910   // done
00911   FD_DH("nDevice::Listen(): terminating listen thread");
00912   for(sit=ndevice->mSensorServerStates.begin(); sit!=ndevice->mSensorServerStates.end(); sit++) {
00913     int serversock=sit->second.mServerSocket;
00914     if(serversock>0) close(serversock);
00915     sit->second.mServerSocket=-1;
00916   }
00917   pthread_exit(NULL);
00918   return NULL;
00919 }
00920 
00921 
00922 
00923 
00924 
00925 // background thread, reply on client request
00926 void* NDeviceReply(void* arg) {
00927   bool term=false;
00928   // cast my state
00929   nDevice::ClientState* cstate= static_cast<nDevice::ClientState*>(arg);
00930   nDevice* ndevice = cstate->mDevice;
00931   // get my socket
00932   TLOCK_E;
00933   int clientsock = cstate->mClientSocket;
00934   TUNLOCK_E; 
00935   FD_DH("nDevice::Reply(" <<  clientsock  << "): start");
00936   // say hello
00937   std::string hello;
00938   hello="% Simplenet Event Server: \""+ndevice->mName+"\" providing events\n";
00939   send(clientsock, hello.c_str(), hello.length(), 0);
00940   hello="% Notifications will have format '<Notify> \"event_name\" </Notify>'\n";
00941   syncSend(clientsock, hello.c_str(), hello.length(), 0);
00942   hello="% Commands are accepted in format '<Cmd> \"cmd_name\" </Cmd>'\n";
00943   syncSend(clientsock, hello.c_str(), hello.length(), 0);
00944   hello="% Supported commands are \"Info\" and \"Status\"\n";
00945   syncSend(clientsock, hello.c_str(), hello.length(), 0);
00946   // have a linebuffer
00947   std::string linebuffer;
00948   // loop forever
00949   while(true) {
00950     FD_DH("nDevice::Reply(" <<  clientsock  << "): waiting");
00951     // allow for cancel
00952     pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);
00953     // select my socket with moderate time out
00954     fd_set mysock;
00955     FD_ZERO(&mysock);
00956     FD_SET(clientsock, &mysock);
00957     struct timeval tv;
00958     tv.tv_sec = 100;
00959     tv.tv_usec = 0;
00960     pthread_testcancel(); // fix LinuxThread were select is no cancelation point
00961     int avail=select(clientsock+1, &mysock, NULL, NULL, &tv);
00962     pthread_testcancel();
00963     // dont cancle
00964     pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);
00965     // read data to buffer
00966     FD_DH("nDevice::Reply(" <<  clientsock  << "): release");
00967     if(avail>0) {
00968       char buffer[1025];
00969       int count = recv(clientsock, buffer, 1024, 0);
00970       if(count<=0) { // todo: test eof
00971         FD_DH("nDevice::Reply(" <<  clientsock  << "): eof");
00972         term=true;
00973         break;
00974       } 
00975       FD_DH("nDevice::Reply(" <<  clientsock  << "): count: " << count);
00976       buffer[count]=0;
00977       linebuffer +=std::string(buffer);
00978       avail=0;
00979       // pass on complete lines for interpretation
00980       if(count>0) if(buffer[count-1]=='\n') avail=1;
00981     }
00982     // evaluate linebuffer
00983     if(avail>0) {
00984       FD_DH("nDevice::Reply(" <<  clientsock  << "): line: " << linebuffer);
00985       // tokenise command
00986       TokenReader tr(TokenReader::String,linebuffer);
00987       try {
00988         Token token;
00989         while(tr.Peek(token)) {
00990           // its a command
00991           if(token.Type()==Token::Begin && token.StringValue()=="Cmd") { 
00992         tr.ReadBegin("Cmd");
00993       std::string cmd = tr.ReadString();
00994         tr.ReadEnd("Cmd");
00995             std::string response="<NAck> </NAck>\n";
00996             // command: info
00997             if(cmd=="Info") {
00998               TLOCK_E;
00999               response=ndevice->ToString() + "\n";
01000               TUNLOCK_E;
01001             }
01002             // command: status
01003             if(cmd=="Status") {
01004               TLOCK_E;
01005               if(ndevice->mState==vDevice::Up) response="<Ack> \"Up\" </Ack>\n";
01006               if(ndevice->mState==vDevice::StartUp) response="<Ack> \"StartUp\" </Ack>\n";
01007               if(ndevice->mState==vDevice::ShutDown) response="<Ack> \"ShutDown\" </Ack>\n";
01008               TUNLOCK_E;
01009             }
01010             // send reply
01011             syncSend(clientsock, response.c_str(), response.length(), 0);
01012     }
01013           // its a event subscription
01014           if(token.Type()==Token::Begin && token.StringValue()=="Subscribe") { 
01015       EventSet sevents;
01016             sevents.Read(tr,"Subscribe");
01017             FD_DH("nDevice::Reply(" <<  clientsock  << "): providing events " << sevents.ToString());
01018             TLOCK_E;
01019             cstate->mEvents.InsertSet(sevents);
01020             TUNLOCK_E;
01021     }
01022   }
01023       } catch (faudes::Exception&) {
01024         FD_DH("nDevice::Reply(" <<  clientsock  << "): invalid cmd");
01025       }
01026       // done
01027       linebuffer="";
01028     }
01029     // lost connection / socket closed
01030     if(avail<0) {
01031       FD_DH("nDevice::Reply(" <<  clientsock  << "): socket closed");
01032       break;
01033     }
01034   } // loop
01035   // remove client state
01036   TLOCK_E;
01037   if(cstate->mClientSocket>0) close(clientsock);
01038   cstate->mClientSocket=-1;
01039   ndevice->mActuatorClientStates.erase(clientsock); 
01040   TUNLOCK_E;
01041   // done
01042   FD_DH("nDevice::Reply(" << clientsock << "): terminate");
01043   pthread_exit(NULL);
01044   return NULL;
01045 }
01046 
01047 // reset dynamic faudes state (buffered events, current time)
01048 void nDevice::Reset(void) {
01049   // call base for time and sensor buffer
01050   vDevice::Reset();
01051 }
01052 
01053 
01054 
01055 } // name space
01056 
01057 
01058 

libFAUDES 2.14g --- 2009-12-3 --- c++ source docu by doxygen 1.5.6