libFAUDES

Sections

Index

iop_simplenet.h

Go to the documentation of this file.
00001 /** @file iop_simplenet.h 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 #ifndef FAUDES_IOP_SIMPLENET_H
00014 #define FAUDES_IOP_SIMPLENET_H
00015 
00016 #include "corefaudes.h"
00017 #include "iop_vdevice.h"
00018 
00019 
00020 #ifndef FAUDES_WINEXTRA
00021 #include <sys/socket.h>
00022 #include <arpa/inet.h>
00023 #include <netdb.h>
00024 #include <cerrno>
00025 #else
00026 #include <winsock2.h>
00027 #include <pthread.h>
00028 #endif
00029 
00030  
00031 
00032 namespace faudes {
00033 
00034 
00035 /**
00036  * Simplenet node address.
00037  *
00038  * A node address consists of an ip address and a tcp port.
00039  * This convenience class implements string based access to both components.
00040  *
00041  */
00042 
00043 class SimplenetAddress {
00044 
00045 public:
00046 
00047   /** Default constructor */
00048   SimplenetAddress(void);
00049 
00050   /** Copy construct */
00051   SimplenetAddress(const SimplenetAddress& rOther);
00052 
00053   /** Construct from string */
00054   SimplenetAddress(const std::string& rString);
00055 
00056   /** Return true if valid */
00057   bool Valid(void) const;
00058 
00059   /** Get ip address */
00060   std::string Ip(void) const { return mIp; };
00061 
00062   /** Get tcp port */
00063   int Port(void) const { return mPort; };
00064 
00065   /** Get as colon seperated string */
00066   std::string IpColonPort(void) const;
00067 
00068   /** Set ip address */
00069   void Ip(std::string ip) { mIp=ip; };
00070 
00071   /** Set tcp port  */
00072   void Port(int port) { mPort=port; };
00073 
00074   /** Set from colon seperated string */
00075   void IpColonPort(std::string ipcolonport);
00076   
00077   /** Order for sorting containers of addresses */
00078   bool operator < (const SimplenetAddress& rOther) const;
00079 
00080  protected:
00081 
00082   /** Ip address */  
00083   std::string mIp;
00084 
00085   /** Tcp port */
00086   int mPort;
00087 
00088 };
00089 
00090 
00091 /**
00092  * Configuration of a network actuator mapping.
00093  *
00094  * There is nothing to configure here: any client that
00095  * connects to this device can subscribe to any actuator event.
00096  * Future versions of libFAUDES may specify a set of receipent
00097  * clients.
00098  *
00099  */
00100 
00101 class AttributeSimplenetActuator : public AttributeVoid {
00102 
00103 FAUDES_TYPE_DECLARATION(AttributeSimplenetActuator,AttributeVoid)
00104 
00105 public:
00106 
00107   /** Default constructor */
00108   AttributeSimplenetActuator(void) : AttributeVoid() {}; 
00109 
00110   /** Test for default value (never) */
00111   virtual bool IsDefault(void) const {return false;};
00112 
00113   /** Clear to default */
00114   virtual void Clear(void) {};
00115 
00116 protected:
00117 
00118   /** Copy method 
00119    *
00120    * @param rSrcAttr
00121    *   Source to copy from
00122    * @return
00123    *   Ref to this attribute
00124    */
00125   virtual AttributeSimplenetActuator& DoAssign(const AttributeSimplenetActuator& rSrcAttr) 
00126   {(void) rSrcAttr; return *this;};
00127 
00128   /**
00129    * Reads the attribute from TokenReader, see AttributeVoid for public wrappers.
00130    * 
00131    * If the current token indicates a sensor mapping, the method reads that
00132    * section. Else it does nothing. Exceptions may only be thrown
00133    * on invalid data within the section. The label argument is ignored, we use the 
00134    * hardcoded section "Actuator" for actuator attributes. The context argument is ignored.
00135    *
00136    * @param rTr
00137    *   TokenReader to read from
00138    * @param rLabel
00139    *   Section to read
00140    * @param pContext
00141    *   Read context to provide contextual information
00142    *
00143    * @exception Exception
00144    *   - IO error (id 1)
00145    */
00146   virtual void DoRead(TokenReader& rTr,const std::string& rLabel="", const Type* pContext=0);
00147  
00148   /**
00149    * Writes the attribute to TokenWriter, see AttributeVoid for public wrappers.
00150    *
00151    * Writes the actuator mapping data. The label argument is ignored, we use 
00152    * the hardcoded section "Actuator". The context argument is ignored.  
00153    *
00154    * @param rTw
00155    *   TokenWriter to write to
00156    * @param rLabel
00157    *   Section to write
00158    * @param pContext
00159    *   Read context to provide contextual information
00160    *
00161    * @exception Exception
00162    *   - IO error (id 2)
00163    */
00164   virtual void DoWrite(TokenWriter& rTw,const std::string& rLabel="", const Type* pContext=0) const;
00165 
00166 }; // end class AttributeSimplenetActuator
00167 
00168 
00169 /**
00170  * Configuration of a network sensor mapping.
00171  *
00172  * There is nothing to configure here: any server that
00173  * provides the repective event will be accepted. Future versions 
00174  * of libFAUDES may specify a set of servers here.
00175  *
00176  */
00177 
00178 class AttributeSimplenetSensor : public AttributeVoid {
00179 
00180 FAUDES_TYPE_DECLARATION(AttributeSimplenetSensor,AttributeVoid)
00181 
00182 public:
00183 
00184   /** Default constructor (no triggers) */
00185  AttributeSimplenetSensor(void) : AttributeVoid() {}; 
00186 
00187   /** Test for default value (never) */
00188   virtual bool IsDefault(void) const {return false;};
00189 
00190   /** Clear to default */
00191   virtual void Clear(void) {};
00192 
00193 protected:
00194 
00195   /** Copy method 
00196    *
00197    * @param rSrcAttr
00198    *   Source to copy from
00199    * @return
00200    *   Ref to this attribute
00201    */
00202   virtual AttributeSimplenetSensor& DoAssign(const AttributeSimplenetSensor& rSrcAttr) 
00203   {(void) rSrcAttr; return *this;};
00204 
00205 
00206   /**
00207    * Reads the attribute from TokenReader, see AttributeVoid for public wrappers.
00208    * 
00209    * If the current token indicates a sensor mapping, the method reads that
00210    * section. Else it does nothing. Exceptions may only be thrown
00211    * on invalid data within the section. The label argument is ignored, we the hardcoded
00212    * section "Sensor" for sensor device attributes. The context argument is ignored.
00213    *
00214    * @param rTr
00215    *   TokenReader to read from
00216    * @param rLabel
00217    *   Section to read
00218    * @param pContext
00219    *   Read context to provide contextual information
00220    *
00221    * @exception Exception
00222    *   - IO error (id 1)
00223    */
00224   virtual void DoRead(TokenReader& rTr,const std::string& rLabel="", const Type* pContext=0);
00225  
00226   /**
00227    * Writes the attribute to TokenWriter, see AttributeVoid for public wrappers.
00228    *
00229    * Writes the sensor mapping data.The label argument is ignored, we use 
00230    * the hardcoded section "Sensor". The context argument is ignored.  
00231    *
00232    * @param rTw
00233    *   TokenWriter to write to
00234    * @param rLabel
00235    *   Section to write
00236    * @param pContext
00237    *   Read context to provide contextual information
00238    *
00239    * @exception Exception
00240    *   - IO error (id 2)
00241    */
00242   virtual void DoWrite(TokenWriter& rTw,const std::string& rLabel="", const Type* pContext=0) const;
00243 
00244 }; // end class AttributeSimplenetSensor
00245 
00246 
00247 
00248 /**
00249  * Configuration of a networked sensor or actuator 
00250  *
00251  * This class is derived from the AttributeDeviceEvent to specialise
00252  * for networked sensor and actuator mapping.
00253  *
00254  */
00255 
00256 class AttributeSimplenetEvent : public AttributeDeviceEvent {
00257 
00258  FAUDES_TYPE_DECLARATION(AttributeSimplenetEvent,AttributeDeviceEvent)
00259 
00260 public:
00261 
00262   /** Default constructor (no mapping at all) */
00263   AttributeSimplenetEvent(void);
00264 
00265   /** Copy constructor */
00266   AttributeSimplenetEvent(const AttributeSimplenetEvent& rOtherAttr);
00267 
00268   /** Test for default value (never) */
00269   virtual bool IsDefault(void) const {return false;};
00270 
00271   /** Clear */
00272   virtual void Clear(void)  { AttributeDeviceEvent::Clear(); };
00273 
00274   /**  Get actuator mapping */
00275   const AttributeSimplenetActuator*  Actuatorp(void) const {
00276     return static_cast<AttributeSimplenetActuator*>(mpActuatorAttribute); };
00277 
00278   /**  Get sensor mapping */
00279   const AttributeSimplenetSensor*  Sensorp(void) const {
00280     return static_cast<AttributeSimplenetSensor*>(mpSensorAttribute); };
00281 
00282 protected:
00283 
00284   /** DoAssign */
00285   virtual AttributeSimplenetEvent& DoAssign(const AttributeSimplenetEvent& rSrc)  
00286   { AttributeDeviceEvent::DoAssign(rSrc); return *this;};
00287 
00288   /** Prototype, sensor */
00289   static AttributeSimplenetSensor sSensorPrototype;
00290 
00291   /** Prototype, actuator */
00292   static AttributeSimplenetActuator sActuatorPrototype;
00293 
00294 }; // class AttributeSimplenetEvent
00295 
00296 
00297 /**
00298  * An nDevice implements networked IO via a simple tcp/ip protocol. 
00299  *
00300  * @section SecIodeviceNDev1 Networking
00301  *
00302  * The purpose of this implementation of networked discrete events is to provide
00303  * a basis for case studies. However, simple networked events via nDevice must not 
00304  * be confused with ongoing research that addresses synchronisation and real 
00305  * time behaviour. We take a really pragmatic approach here.
00306  *
00307  * Our <em>network</em> is identified by its <em>network name</em>. It consists
00308  * a number of <em>nodes</em>, each identified by its <em>node name</em>. In the current implementation,
00309  * each node knows about the entire network ie knows about all other nodes. Each node plays two roles:
00310  * - the <em>server</em> role to send event notifications, and
00311  * - the <em>client</em> role to receive event notifications.
00312  *
00313  * As a server, the node is configured to listen on its <em>server port</em> for incomming 
00314  * tcp connections. When a client (eg some other node in client role) connects to the tcp port, the server 
00315  * replies to a simple command set in order to allow the client to subscribe to the nodes actuator events.
00316  * When the application executes an actuator on the node, this is notified to all connected clients and
00317  * the clients will interpret the event as a sensor reading. Vice versa, the node itself has the 
00318  * role of a client and subscribes its sensor events from all other nodes. 
00319  *
00320  * @section SecIodeviceNDev2 Protocol Details
00321  *
00322  * The protocol for commands and notification is libFAUDES-token based and can be inspected eg via nc or telnet; 
00323  * see the shell script in the tutorial. 
00324  * Event notifications are sent spontaneous to all subscribing nodes in the format 
00325  * <tt><Notify> "event" </Notify></tt>.
00326  * Commands are accepted in the format <tt><Cmd> "command" </Cmd></tt> and will be
00327  * answered accordingly.
00328  *
00329  * <table>
00330  * <tr>
00331  * <td> Command on tcp server port</td>
00332  * <td> Reply </td>
00333  * </tr>
00334  * <tr>
00335  * <td>  <tt><Cmd> "Info"  </Cmd></tt> </td>
00336  * <td> Configuration of node as token string </td>
00337  * </tr>
00338  * <tr>
00339  * <td> <tt><Cmd> "Status"  </Cmd></tt>  </td>
00340  * <td> Up/StartUop/Down/ShutDown </td>
00341  * </tr>
00342  * <td> <tt><Cmd> "ResetRequest"  </Cmd></tt>  </td>
00343  * <td> acknowledge </td>
00344  * <tr>
00345  * <td> <tt><Subscribe> "ev1" ... "evN"  </Subscribe></tt> </td>
00346  * <td> Positive Acknowledge to accept subscription of events </td>
00347  * </tr>
00348  * </table>
00349  *
00350  * @section SecIodeviceNDev3 Name Resolution
00351  *
00352  * On the technical side, each node needs to figure the ip addresses incl tcp ports on which the 
00353  * other nodes provide their service. To ease configuration, this information is distributed by 
00354  * udp datagrams. In order to locate the other nodes within the network, a node may  broadcasts a 
00355  * network <em>request</em> datagramm. Each node that receives such a request, replies with an 
00356  * <em>advert</em> datagramm to provide its address. Thus, the simple net nodes rely on some 
00357  * underlying name resolution by dns services, but node configuration itself refers to simple-net node names
00358  * only. Since each node knows about the names of all participating nodes, each node will know when 
00359  * all connections are up. 
00360  * 
00361  * <table>
00362  * <tr>
00363  * <td> Broadcast on simplenet udp port</td>
00364  * <td> Reply </td>
00365  * </tr>
00366  * <tr>
00367  * <td> <tt><Request> "network"  </Request></tt> </td>
00368  * <td> Advertisement of networkname, nodename and ip-address:port </td>
00369  * </tr>
00370  * </table>
00371  * <p>
00372  *
00373  * @section SecIodeviceNDev4 File IO
00374  *
00375  * For token IO, the nDevice reads and writes a section with label  
00376  * "SimplenetDevice". There are no relevant attributes yet. Simple machine example:
00377  *
00378  * @code
00379  * <SimplenetDevice>
00380  *
00381  * "simplemachine"     % node id
00382  * 1000                % time scale (ms/ftu)
00383  * "localhost:40000"   % server tcp port 
00384  * "simpleloop"        % network id
00385  *
00386  * <Network>           
00387  * "simplemachine"     % other nodes ..,
00388  * "simplesupervisor"  % ... in this network
00389  * </Network>
00390  *
00391  * <SimplenetEvents>
00392  * "alpha"  <Input></Input>
00393  * "beta"   <Output></Output>
00394  * "mue"    <Output></Output>
00395  * "lambda" <Input></Input>
00396  * </SimplenetEvents>
00397  *
00398  * </SimplenetDevice>
00399  * @endcode
00400  *
00401  * @section SecIodeviceNDev5 Implementation Notes
00402  *
00403  * The current status of the code is premature; network io
00404  * assumes reasonably large buffers; thread/select mechanism is inefficient; 
00405  * exception handling wont work; etc etc
00406  * 
00407  *
00408  * @ingroup IODevicePlugin 
00409  */
00410 
00411 class nDevice : public vDevice {    
00412 
00413   // provide all access to background tasks
00414   friend void* NDeviceListen(void*);
00415   friend void* NDeviceServer(void*);
00416   friend void* NDeviceReply(void*);
00417 
00418  public:
00419   /**
00420    * Default constructor
00421    */
00422   nDevice(void);
00423 
00424   /**
00425    * Explicit destructor.
00426    */
00427   virtual ~nDevice(void);
00428 
00429   /**
00430    * Clear all configuration.
00431    * This implies Stop().
00432    */
00433   virtual void Clear(void);
00434 
00435   /**
00436    * Set up internal data structures
00437    *
00438    */
00439   virtual void Compile(void);
00440 
00441   /**
00442    * Add entry to node name resolution
00443    *
00444    * @param rNode
00445    *   Name of node to register
00446    * @param rAddress 
00447    *  Address incl port 
00448    */
00449   void InsertNodeAddress(const std::string& rNode, const SimplenetAddress& rAddress);
00450  
00451 
00452   /**
00453    * Activate the device. This function enables actuator execution and sensor reading.
00454    * It starts the background thread for incomming connections and tries to connect to relevant servers.
00455    *
00456    * @exception Exception
00457    *   - Not yet configured (id 551)
00458    *   - Fatal network error (id 553)
00459    *   - Fatal pthread error (id 554)
00460    */
00461   virtual void Start(void);
00462 
00463   /**
00464    * Deactivate the device. This function disables actuator execution and sensor reading.
00465    * It stops the backhround thread to provide connections and disconnects from any servers.
00466    */
00467   virtual void Stop(void);
00468 
00469   /**
00470    * Reset device. Resets buffered sensor events and current time.
00471    *
00472    */
00473   virtual void Reset(void);
00474 
00475   /**
00476    * Run actuator command.
00477    *
00478    * @exception Exception
00479    *   - unknown actuator event (id 65)
00480    */
00481   virtual void WriteActuator(Idx actuator);
00482 
00483 
00484 
00485  protected:
00486 
00487   /**
00488    * Actual method to read device configuration from tokenreader.
00489    *
00490    * This method calls the base class to read the device name and the
00491    * the timescale. It then reads address, networkid and nodes.
00492    * Overall device configuration is consists of DoReadPreface,
00493    * DoReadConfiguration and Compile. It isimplemented in vDevice.
00494    * The label and context parameters are ignored.
00495    *
00496    * @param rTr
00497    *   TokenReader to read from
00498    * @param rLabel
00499    *   Section to read
00500    * @param pContext
00501    *   Read context to provide contextual information
00502    *
00503    * @exception Exception
00504    *   - IO error (id 1)
00505    */
00506   virtual void DoReadPreface(TokenReader& rTr,  const std::string& rLabel = "", const Type* pContext=0);
00507  
00508   /**
00509    * Actual method to write the device configuration to a TokenWriter.
00510    *
00511    * This method calls the base class vDevice to write the device name and
00512    * the time scale. It then writes network related data. The label and
00513    * context parameters are ignored.
00514    *
00515    * @param rTw
00516    *   Reference to TokenWriter
00517    * @param rLabel
00518    *   Label of section to write
00519    * @param pContext
00520    *   Read context to provide contextual information
00521    * @exception Exception 
00522    *   - IO errors (id 2)
00523    */
00524   virtual void DoWritePreface(TokenWriter& rTw, const std::string& rLabel="", const Type* pContext=0) const;
00525 
00526 
00527   /** Overall configuration (with actual type) */
00528   TaNameSet<AttributeSimplenetEvent>* pConfiguration ;
00529 
00530   /** Simplenet: network id */
00531   std::string mNetwork;
00532 
00533   /** Simplenet: address of my server port */
00534   SimplenetAddress mAddress;
00535 
00536   /** Simplenet: effective address of my server port */
00537   SimplenetAddress mEffectiveAddress;
00538 
00539   /** Simplenet: list of nodes in this network */
00540   std::set<std::string> mNetworkNodes;
00541   
00542   /** Simplenet: list of event server addresses */
00543   std::set<std::string> mSensorServers;
00544   
00545   /** Compiled data: map subscriptions */
00546   std::map<std::string,EventSet> mSensorSubscriptions;
00547 
00548   /** Background: mutex for below shared variables*/
00549   pthread_mutex_t mMutex;
00550 
00551   /** Background: thread handle (global) */
00552   pthread_t mThreadListen; 
00553 
00554   /** Background: request to join via flag (mutexed) */
00555   bool mStopListen;
00556 
00557   /** Background: server socket to listen (background only) */
00558   int mServerSocket;
00559   
00560   /** Background: server port to bind (background only) */
00561   struct sockaddr_in mServerAddress;
00562 
00563   /** Background: udp broadcast socket (background only) */
00564   int mBroadcastSocket;
00565   
00566   /** Background: state of a connection to a client (shared) */
00567   typedef struct {
00568     nDevice* mDevice;        // refernce to this device
00569     int  mClientSocket;      // the socket the client is connected to
00570     pthread_t mThread;       // the thread we run to reply to client requests
00571     EventSet mEvents;        // events the client has subscribed to 
00572   } ClientState;  
00573 
00574   /** Background: map sockets to connection states (shared) */
00575   std::map<int, ClientState> mActuatorClientStates;
00576 
00577   /** Background: state of a connection to an event server (shared)*/
00578   typedef struct {
00579     SimplenetAddress mAddress;  // ip address incland tcp port of remote server
00580     EventSet mEvents;           // events we have subscribed to
00581     int  mServerSocket;         // socket used to connect with provider
00582     std::string mLineBuffer;    // buffer to receive one line
00583   } ServerState;  
00584 
00585   /** Background: connection states to event servers (by node name)*/
00586   std::map<std::string,ServerState> mSensorServerStates;
00587 
00588 
00589 
00590 }; // end class nDevice
00591 
00592 // declare background threads
00593 void* NDeviceListen(void*);
00594 void* NDeviceServer(void*);
00595 void* NDeviceReply(void*);
00596 
00597 } // namespace faudes
00598 
00599 
00600 #endif // include

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