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 namespace faudes {
00021 
00022 
00023 /**
00024  * Simplenet node address.
00025  *
00026  * A node address consists of an IP address and a TCP port.
00027  * This convenience class implements string based access to both components.
00028  *
00029  */
00030 
00031 class SimplenetAddress {
00032 
00033 public:
00034 
00035   /** Default constructor */
00036   SimplenetAddress(void);
00037 
00038   /** Copy construct */
00039   SimplenetAddress(const SimplenetAddress& rOther);
00040 
00041   /** Construct from string */
00042   SimplenetAddress(const std::string& rString);
00043 
00044   /** Return true if valid */
00045   bool Valid(void) const;
00046 
00047   /** Get IP address */
00048   std::string Ip(void) const { return mIp; };
00049 
00050   /** Get TCP port */
00051   int Port(void) const { return mPort; };
00052 
00053   /** Get as colon seperated string */
00054   std::string IpColonPort(void) const;
00055 
00056   /** Set IP address */
00057   void Ip(std::string ip) { mIp=ip; };
00058 
00059   /** Set TCP port  */
00060   void Port(int port) { mPort=port; };
00061 
00062   /** Set from colon seperated string */
00063   void IpColonPort(std::string ipcolonport);
00064   
00065   /** Order for sorting containers of addresses */
00066   bool operator < (const SimplenetAddress& rOther) const;
00067 
00068  protected:
00069 
00070   /** Ip address */  
00071   std::string mIp;
00072 
00073   /** TCP port */
00074   int mPort;
00075 
00076 };
00077 
00078 
00079 
00080 // only compile for simplenet support
00081 #ifdef FAUDES_IODEVICE_SIMPLENET
00082 
00083 
00084 
00085 
00086 /**
00087  * Configuration of a network output mapping.
00088  *
00089  * There is nothing to configure here: any client that
00090  * connects to this device can subscribe to any output event.
00091  * Future versions of libFAUDES may specify a set of receipent
00092  * clients.
00093  *
00094  */
00095 
00096 class AttributeSimplenetOutput : public AttributeVoid {
00097 
00098 FAUDES_TYPE_DECLARATION(Void,AttributeSimplenetOutput,AttributeVoid)
00099 
00100 public:
00101 
00102   /** Default constructor */
00103   AttributeSimplenetOutput(void) : AttributeVoid() {}; 
00104 
00105   /** Test for default value (always, since we have no data) */
00106   virtual bool IsDefault(void) const {return true;};
00107 
00108   /** Clear to default */
00109   virtual void Clear(void) {};
00110 
00111 protected:
00112 
00113   /** Copy method 
00114    *
00115    * @param rSrcAttr
00116    *   Source to copy from
00117    * @return
00118    *   Ref to this attribute
00119    */
00120   virtual void DoAssign(const AttributeSimplenetOutput& rSrcAttr) 
00121   {(void) rSrcAttr;};
00122 
00123   /**
00124    * Reads the attribute from TokenReader, see AttributeVoid for public wrappers.
00125    * 
00126    * If the current token indicates a input mapping, the method reads that
00127    * section. Else it does nothing. Exceptions may only be thrown
00128    * on invalid data within the section. The label argument is ignored, we use the 
00129    * hardcoded section "Output" for output attributes. The context argument is ignored.
00130    *
00131    * @param rTr
00132    *   TokenReader to read from
00133    * @param rLabel
00134    *   Section to read
00135    * @param pContext
00136    *   Read context to provide contextual information
00137    *
00138    * @exception Exception
00139    *   - IO error (id 1)
00140    */
00141   virtual void DoRead(TokenReader& rTr,const std::string& rLabel="", const Type* pContext=0);
00142  
00143   /**
00144    * Writes the attribute to TokenWriter, see AttributeVoid for public wrappers.
00145    *
00146    * Writes the output mapping data. The label argument is ignored, we use 
00147    * the hardcoded section "Output". The context argument is ignored.  
00148    *
00149    * @param rTw
00150    *   TokenWriter to write to
00151    * @param rLabel
00152    *   Section to write
00153    * @param pContext
00154    *   Read context to provide contextual information
00155    *
00156    * @exception Exception
00157    *   - IO error (id 2)
00158    */
00159   virtual void DoWrite(TokenWriter& rTw,const std::string& rLabel="", const Type* pContext=0) const;
00160 
00161 }; // end class AttributeSimplenetOutput
00162 
00163 
00164 /**
00165  * Configuration of a network input mapping.
00166  *
00167  * There is nothing to configure here: any server that
00168  * provides the repective event will be accepted. Future versions 
00169  * of libFAUDES may specify a set of servers here.
00170  *
00171  */
00172 
00173 class AttributeSimplenetInput : public AttributeVoid {
00174 
00175 FAUDES_TYPE_DECLARATION(Void,AttributeSimplenetInput,AttributeVoid)
00176 
00177 public:
00178 
00179   /** Default constructor (no triggers) */
00180  AttributeSimplenetInput(void) : AttributeVoid() {}; 
00181 
00182   /** Test for default value (always, since we have no data) */
00183   virtual bool IsDefault(void) const {return true;};
00184 
00185   /** Clear to default */
00186   virtual void Clear(void) {};
00187 
00188 protected:
00189 
00190   /** Copy method 
00191    *
00192    * @param rSrcAttr
00193    *   Source to copy from
00194    * @return
00195    *   Ref to this attribute
00196    */
00197   virtual void DoAssign(const AttributeSimplenetInput& rSrcAttr) 
00198   {(void) rSrcAttr;};
00199 
00200 
00201   /**
00202    * Reads the attribute from TokenReader, see AttributeVoid for public wrappers.
00203    * 
00204    * If the current token indicates a input mapping, the method reads that
00205    * section. Else it does nothing. Exceptions may only be thrown
00206    * on invalid data within the section. The label argument is ignored, we the hardcoded
00207    * section "Input" for input device attributes. The context argument is ignored.
00208    *
00209    * @param rTr
00210    *   TokenReader to read from
00211    * @param rLabel
00212    *   Section to read
00213    * @param pContext
00214    *   Read context to provide contextual information
00215    *
00216    * @exception Exception
00217    *   - IO error (id 1)
00218    */
00219   virtual void DoRead(TokenReader& rTr,const std::string& rLabel="", const Type* pContext=0);
00220  
00221   /**
00222    * Writes the attribute to TokenWriter, see AttributeVoid for public wrappers.
00223    *
00224    * Writes the input mapping data.The label argument is ignored, we use 
00225    * the hardcoded section "Input". The context argument is ignored.  
00226    *
00227    * @param rTw
00228    *   TokenWriter to write to
00229    * @param rLabel
00230    *   Section to write
00231    * @param pContext
00232    *   Read context to provide contextual information
00233    *
00234    * @exception Exception
00235    *   - IO error (id 2)
00236    */
00237   virtual void DoWrite(TokenWriter& rTw,const std::string& rLabel="", const Type* pContext=0) const;
00238 
00239 }; // end class AttributeSimplenetInput
00240 
00241 
00242 
00243 /**
00244  * Configuration of a networked input or output 
00245  *
00246  * This class is derived from the AttributeDeviceEvent to specialise
00247  * for networked input and output mapping.
00248  *
00249  */
00250 
00251 class AttributeSimplenetEvent : public AttributeDeviceEvent {
00252 
00253 FAUDES_TYPE_DECLARATION(Void,AttributeSimplenetEvent,AttributeDeviceEvent)
00254 
00255 public:
00256 
00257   /** Default constructor (no mapping at all) */
00258   AttributeSimplenetEvent(void);
00259 
00260   /** Copy constructor */
00261   AttributeSimplenetEvent(const AttributeSimplenetEvent& rOtherAttr);
00262 
00263   /** Test for default value (never) */
00264   virtual bool IsDefault(void) const {return false;};
00265 
00266   /** Clear */
00267   virtual void Clear(void)  { AttributeDeviceEvent::Clear(); };
00268 
00269   /**  Get output mapping */
00270   const AttributeSimplenetOutput*  Outputp(void) const {
00271     return static_cast<AttributeSimplenetOutput*>(mpOutputAttribute); };
00272 
00273   /**  Get input mapping */
00274   const AttributeSimplenetInput*  Inputp(void) const {
00275     return static_cast<AttributeSimplenetInput*>(mpInputAttribute); };
00276 
00277 protected:
00278 
00279   /** DoAssign */
00280   virtual void DoAssign(const AttributeSimplenetEvent& rSrc)  
00281   { AttributeDeviceEvent::DoAssign(rSrc);};
00282 
00283   /** Prototype, input (construct on first use static) */
00284   static const AttributeSimplenetInput* InputPrototypep(void);
00285 
00286   /** Prototype, output (construct on first use static) */
00287   static const AttributeSimplenetOutput* OutputPrototypep(void);
00288 
00289 }; // class AttributeSimplenetEvent
00290 
00291 
00292 /**
00293  * An nDevice implements networked IO via a simple TCP/IP protocol. 
00294  *
00295  * @section SecIodeviceNDev1 Networking
00296  *
00297  * The purpose of this implementation of networked discrete events is to provide
00298  * a basis for case studies. However, simple networked events via nDevice must not 
00299  * be confused with ongoing research that addresses synchronisation and real 
00300  * time behaviour. We take a really pragmatic approach here.
00301  *
00302  * Our <em>network</em> is identified by its <em>network name</em>. It consists
00303  * a number of <em>nodes</em>, each identified by its <em>node name</em>. In the current implementation,
00304  * each node knows about the entire network ie knows about all other nodes. Each node plays two roles:
00305  * - the <em>server</em> role to send event notifications, and
00306  * - the <em>client</em> role to receive event notifications.
00307  *
00308  * In their server role, each node is configured to listen on its <em>server port</em> for incomming 
00309  * TCP connections. When a client (i.e. some other node in client role) connects to the TCP port, the server 
00310  * replies to a simple command set in order to allow the client to subscribe to the nodes output events.
00311  * When the application executes an output event on the node, this is notified to all connected clients and
00312  * the clients will interpret the event as an input reading. Vice versa, the each node itself has the 
00313  * role of a client and subscribes to relevant output events served by other nodes in their server role. 
00314  *
00315  * @section SecIodeviceNDev2 Protocol Details
00316  *
00317  * The protocol for commands and notification is libFAUDES-token based and can be inspected eg via nc 
00318  * or telnet;  see the shell script in the tutorial. 
00319  * Event notifications are sent spontaneous to all connected clients in the format 
00320  * <tt><Notify> Ev </Notify></tt>.
00321  * Commands are accepted in the format <tt><Cmd> Command </Cmd></tt> and will be
00322  * answered accordingly.
00323  *
00324  * <table valign="top">
00325  * <tr>
00326  * <td> Command via TCP</td>
00327  * <td> Reply </td>
00328  * </tr>
00329  * <tr>
00330  * <td>  <tt><Cmd> Info  </Cmd></tt> </td>
00331  * <td> configuration of node as token string  (<tt><SimplenetDevice name="SimpleMachine"> ... 
00332  *      </SimplenetDevice> </tt> ) </td>
00333  * </tr>
00334  * <tr>
00335  * <td> <tt><Cmd> Status  </Cmd></tt>  </td>
00336  * <td> acknowledgement with status string (<tt><Ack> Up </Ack></tt>, 
00337  * <tt><Ack> StartUp </Ack></tt> or <tt><Ack> ShutDown </Ack></tt>, respectively; 
00338  * will not connect/reply while Down) </td>
00339  * </tr>
00340  * <tr>
00341  * <td> <tt><Cmd> ResetRequest  </Cmd></tt>  </td>
00342  * <td> no acknowledgement </td>
00343  * </tr>
00344  * <tr>
00345  * <td> <tt><Subscribe> Ev_1 ... Ev_N  </Subscribe></tt> </td>
00346  * <td> subset of available events (e.g. <Subscribed> Ev_2 Ev_7 Ev_9  </Subscribes></tt>)</td>
00347  * </tr>
00348  * </table>
00349  *
00350  * A minimal alternative implementation for a node consists of (1) a TCP server that ignores all
00351  * incomming messages and issues event notifications to any relevant events; and, (2) a TCP client 
00352  * that subscribes to all events and then listens to event notifications. All other commands are 
00353  * optional and may change in future revisions of this protocol. 
00354  *
00355  * @section SecIodeviceNDev3 Name Resolution
00356  *
00357  * On the technical side, each node needs to figure the IP addresses incl TCP ports on which the 
00358  * other nodes provide their service. To ease configuration, this information is distributed by 
00359  * UDP datagrams. In order to locate the other nodes within the network, a node may  broadcasts a 
00360  * network <em>request</em> datagramm. Each node that receives such a request, replies with an 
00361  * <em>advert</em> datagramm to provide its address. Thus, the simple net nodes rely on some 
00362  * underlying name resolution by DNS services, but node configuration itself refers to simple-net node names
00363  * only. Since each node knows about the names of all participating nodes, each node will know when 
00364  * all connections are up. 
00365  *
00366  * By default, UDP broadcasts are addressed to 255.255.255.255:40000. Since
00367  * routers are not meant to pass-on broadcasts, nDevice name resolution is restricted to 
00368  * one subnet. If the local host is connected to multiple subnets, you need to specify the
00369  * relevant subset explicitly by setting the appropriate broadcast address, e.g. 192.168.2.255:40000.
00370  * To restrict networks to the local machine, set the broadcast address to the loopback device
00371  * 127.0.0.1:40000. To span a network accross multiple subnets, server addresses can be 
00372  * explicitly specified as an attribute in the node configuration;
00373  * e.g. <tt> <Node> name=\"SimpleSupervisor\" address=\"192.168.2.1:40000\"</Node></tt>.
00374  * This is also the preferred
00375  * fallback when address resolution fails for other reasons.
00376  * 
00377  * <table valign="top">
00378  * <tr>
00379  * <td> Broadcast via UDP</td>
00380  * <td> Reply </td>
00381  * </tr>
00382  * <tr>
00383  * <td> <tt><Request> network reqnode  </Request></tt> </td>
00384  * <td> advertisement of networkname, nodename and ip-address:port, e.g.,  
00385  * <tt> <Advert> SimpleLoop SimpleSupervisor 192.168.2.1:40000 </Advert></tt>
00386  * </td>
00387  * </tr>
00388  * </table>
00389  * <p>
00390  *
00391  * @section SecIodeviceNDev4 File IO
00392  *
00393  * For token IO, the nDevice reads and writes a section with label  
00394  * "SimplenetDevice". There are no relevant attributes yet. Simple machine example:
00395  *
00396  * @code
00397  * <SimplenetDevice name="SimpleMachine"> 
00398  *
00399  * <!-- Time scale in ms/ftiu -->
00400  * <TimeScale value="1000"/> 
00401  *
00402  * <!-- IP address of this node, incl. server TCP port -->
00403  * <ServerAddress value="localhost:40000"/> 
00404 
00405  * <!-- Broadcaset address for node resolution (optional)
00406  * <BroadcastAddress value="255.255.255.255:40000"/> 
00407  *
00408  * <!-- Network topology -->
00409  * <Network name="SimpleLoop"> 
00410  * <Node name="SimpleMachine"/> 
00411  * <Node name="SimpleSupervisor"/> 
00412  * </Network> 
00413  *
00414  * <!-- Event configuration -->
00415  * <EventConfiguration> 
00416  * <Event name="alpha" iotype="input"/> 
00417  * <Event name="beta" iotype="output"/> 
00418  * <Event name="mue" iotype="output"/> 
00419  * <Event name="lambda" iotype="input"/> 
00420  * </EventConfiguration> 
00421  *
00422  * </SimplenetDevice> 
00423  * @endcode
00424  *
00425  * @section SecIodeviceNDev5 Implementation Notes
00426  *
00427  * The current status of the code is premature; network io
00428  * assumes reasonably large buffers; thread/select mechanism is inefficient; 
00429  * exception handling wont work; etc etc
00430  * 
00431  *
00432  * @ingroup IODevicePlugin 
00433  */
00434 
00435 class nDevice : public vDevice {    
00436 
00437 FAUDES_TYPE_DECLARATION(SimplenetDevice,nDevice,vDevice)
00438 
00439   // provide all access to background tasks
00440   friend void* NDeviceListen(void*);
00441   friend void* NDeviceServer(void*);
00442   friend void* NDeviceReply(void*);
00443 
00444  public:
00445   /**
00446    * Default constructor
00447    */
00448   nDevice(void);
00449 
00450   /**
00451    * Explicit destructor.
00452    */
00453   virtual ~nDevice(void);
00454 
00455   /**
00456    * Clear all configuration.
00457    * This implies Stop().
00458    */
00459   virtual void Clear(void);
00460 
00461   /**
00462    * Set server address of this node.
00463    * Note: you can only set th server address while the
00464    * device is down.
00465    *
00466    * @param rAddr 
00467    *   Address on which to run this server, e.g. "localhost:40000"
00468    * @exception Exception
00469    *   - No valid address (id 551) (NOT IMPLEMENTED)
00470    */
00471   void ServerAddress(const std::string& rAddr);
00472 
00473   /**
00474    * Set broadcast address for address resolution
00475    * Note: you can only set the broadcast address while the
00476    * device is down.
00477    *
00478    * @param rAddr 
00479    *   Address for UDP broadcasts e.g. "255.255.255.255:40000"
00480    * @exception Exception
00481    *   - No valid address (id 551) (NOT IMPLEMENTED)
00482    */
00483   void BroadcastAddress(const std::string& rAddr);
00484 
00485   /**
00486    * Set network name to participate.
00487    * Note: you can only set the network name 
00488    * while the device is down.
00489    *
00490    * @param rNetwork 
00491    *   Name of network, e.g. "ElevatorNetwork"
00492    */
00493   void NetworkName(const std::string& rNetwork);
00494 
00495   /**
00496    * Add a node to the network configuration.
00497    * Note: you can only configure the network
00498    * while the device is down.
00499    *
00500    * @param rNodeName 
00501    *   Node to participate in wthe network.
00502    */
00503   void InsNode(const std::string& rNodeName);
00504 
00505   /**
00506    * Add entry to node name resolution
00507    *
00508    * Note: you can only configure the network
00509    * while the device is down.
00510    * @param rNode
00511    *   Name of node to register
00512    * @param rAddress 
00513    *  Address incl port 
00514    */
00515   void InsNodeAddress(const std::string& rNode, const std::string& rAddress);
00516  
00517 
00518   /**
00519    * Add a node to the network configuration.
00520    * Note: you can only configure the network
00521    * while the device is down.
00522    *
00523    */
00524   void ClearNodes(void);
00525 
00526   /**
00527    * Insert event as input event.
00528    * Note: you can only configure events
00529    * while the device is down.
00530    *
00531    * @param event
00532    *   Event by name.
00533    */
00534   void InsInputEvent(const std::string& event);
00535 
00536 
00537   /**
00538    * Insert event as output event.
00539    * Note: you can only configure event
00540    * while the device is down.
00541    *
00542    * @param event
00543    *   Event by name.
00544    */
00545   void InsOutputEvent(const std::string& event);
00546 
00547 
00548   /**
00549    * Set up internal data structures
00550    *
00551    */
00552   virtual void Compile(void);
00553 
00554 
00555   /**
00556    * Activate the device. This function enables output execution and input reading.
00557    * It starts the background thread for incomming connections and tries to connect to relevant servers.
00558    *
00559    * @exception Exception
00560    *   - Not yet configured  (id 551)
00561    *   - Fatal network error (id 553)
00562    *   - Fatal thread error  (id 554)
00563    */
00564   virtual void Start(void);
00565 
00566   /**
00567    * Deactivate the device. This function disables output execution and input reading.
00568    * It stops the backhround thread to provide connections and disconnects from any servers.
00569    */
00570   virtual void Stop(void);
00571 
00572   /**
00573    * Reset device. Resets buffered input events and current time.
00574    *
00575    */
00576   virtual void Reset(void);
00577 
00578   /**
00579    * Run output command.
00580    *
00581    * @exception Exception
00582    *   - unknown output event (id 65)
00583    */
00584   virtual void WriteOutput(Idx output);
00585 
00586 
00587 
00588 protected:
00589 
00590   /**
00591    * Actual method to read device configuration from tokenreader.
00592    *
00593    * This method calls the base class to read the device name and the
00594    * the timescale. It then reads address, networkid and nodes.
00595    * Overall device configuration is consists of DoReadPreface,
00596    * DoReadConfiguration and Compile. It isimplemented in vDevice.
00597    * The label and context parameters are ignored.
00598    *
00599    * @param rTr
00600    *   TokenReader to read from
00601    * @param rLabel
00602    *   Section to read
00603    * @param pContext
00604    *   Read context to provide contextual information
00605    *
00606    * @exception Exception
00607    *   - IO error (id 1)
00608    */
00609   virtual void DoReadPreface(TokenReader& rTr,  const std::string& rLabel = "", const Type* pContext=0);
00610  
00611   /**
00612    * Actual method to write the device configuration to a TokenWriter.
00613    *
00614    * This method calls the base class vDevice to write the device name and
00615    * the time scale. It then writes network related data. The label and
00616    * context parameters are ignored.
00617    *
00618    * @param rTw
00619    *   Reference to TokenWriter
00620    * @param rLabel
00621    *   Label of section to write
00622    * @param pContext
00623    *   Read context to provide contextual information
00624    * @exception Exception 
00625    *   - IO errors (id 2)
00626    */
00627   virtual void DoWritePreface(TokenWriter& rTw, const std::string& rLabel="", const Type* pContext=0) const;
00628 
00629 
00630   /** Overall configuration (with actual type) */
00631   TaNameSet<AttributeSimplenetEvent>* pConfiguration ;
00632 
00633   /** Simplenet: network id */
00634   std::string mNetwork;
00635 
00636   /** Simplenet: address of my server incl port (localhost:40000)*/
00637   SimplenetAddress mListenAddress;
00638 
00639   /** Simplenet: address for udp broadcast (255.255.255.255:40000*/
00640   SimplenetAddress mBroadcastAddress;
00641 
00642   /** Simplenet: effective address of my server port */
00643   SimplenetAddress mEffectiveListenAddress;
00644 
00645   /** Simplenet: list of nodes in this network incl default addresses*/
00646   std::map<std::string,std::string> mNetworkNodes;  
00647   
00648   /** Compiled data: map subscriptions */
00649   std::map<std::string,EventSet> mInputSubscriptions;
00650 
00651   /** Background: mutex for below shared variables*/
00652   faudes_mutex_t mMutex;
00653 
00654   /** Background: thread handle (global) */
00655   faudes_thread_t mThreadListen; 
00656 
00657   /** Background: request to join via flag (mutexed) */
00658   bool mStopListen;
00659 
00660   /** Background: server socket to listen (background only) */
00661   int mListenSocket;
00662   
00663   /** Background: udp broadcast socket (background only) */
00664   int mBroadcastSocket;
00665   
00666   /** Background: state of a connection to a client (shared) */
00667   typedef struct {
00668     int  mClientSocket;      // the socket the client is connected to
00669     EventSet mEvents;        // events the client has subscribed to 
00670     bool mConnected;         // set to true, if a subscription has been seen
00671     std::string mLineBuffer; // buffer to receive one line
00672   } ClientState;  
00673 
00674   /** Background: map sockets to connection states (shared) */
00675   std::map<int, ClientState> mOutputClientStates;
00676 
00677   /** Background: state of a connection to an event server (shared)*/
00678   typedef struct {
00679     SimplenetAddress mAddress;        // actual IP address incl TCP port of remote server
00680     SimplenetAddress mDefaultAddress; // default IP address incl TCP port of remote server
00681     EventSet mEvents;                 // events we have subscribed to
00682     int  mServerSocket;               // socket used to connect with provider
00683     std::string mLineBuffer;          // buffer to receive one line
00684   } ServerState;  
00685 
00686   /** Background: connection states to event servers (by node name)*/
00687   std::map<std::string,ServerState> mInputServerStates;
00688 
00689 
00690 
00691 }; // end class nDevice
00692 
00693 // declare background threads
00694 void* NDeviceListen(void*);
00695 
00696 #endif // configured for simplenet
00697 
00698 
00699 
00700 } // namespace faudes
00701 
00702 #endif // include

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