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

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