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

Sections

Index

iop_simplenet.cpp

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

libFAUDES 2.20s --- 2011.10.12 --- c++ source docu by doxygen