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>
00385  *
00386  * "simplemachine"     % node id
00387  * 1000                % time scale (ms/ftu)
00388  * "localhost:40000"   % server tcp port 
00389  * "simpleloop"        % network id
00390  *
00391  * <Network>           
00392  * "simplemachine"     % other nodes ..,
00393  * "simplesupervisor"  % ... in this network
00394  * </Network>
00395  *
00396  * <SimplenetEvents>
00397  * "alpha"  <Input></Input>
00398  * "beta"   <Output></Output>
00399  * "mue"    <Output></Output>
00400  * "lambda" <Input></Input>
00401  * </SimplenetEvents>
00402  *
00403  * </SimplenetDevice>
00404  * @endcode
00405  *
00406  * @section SecIodeviceNDev5 Implementation Notes
00407  *
00408  * The current status of the code is premature; network io
00409  * assumes reasonably large buffers; thread/select mechanism is inefficient; 
00410  * exception handling wont work; etc etc
00411  * 
00412  *
00413  * @ingroup IODevicePlugin 
00414  */
00415 
00416 class nDevice : public vDevice {    
00417 
00418 FAUDES_TYPE_DECLARATION(SimplenetDevice,nDevice,vDevice)
00419 
00420   // provide all access to background tasks
00421   friend void* NDeviceListen(void*);
00422   friend void* NDeviceServer(void*);
00423   friend void* NDeviceReply(void*);
00424 
00425  public:
00426   /**
00427    * Default constructor
00428    */
00429   nDevice(void);
00430 
00431   /**
00432    * Explicit destructor.
00433    */
00434   virtual ~nDevice(void);
00435 
00436   /**
00437    * Clear all configuration.
00438    * This implies Stop().
00439    */
00440   virtual void Clear(void);
00441 
00442   /**
00443    * Set up internal data structures
00444    *
00445    */
00446   virtual void Compile(void);
00447 
00448   /**
00449    * Add entry to node name resolution
00450    *
00451    * @param rNode
00452    *   Name of node to register
00453    * @param rAddress 
00454    *  Address incl port 
00455    */
00456   void InsertNodeAddress(const std::string& rNode, const SimplenetAddress& rAddress);
00457  
00458 
00459   /**
00460    * Activate the device. This function enables output execution and input reading.
00461    * It starts the background thread for incomming connections and tries to connect to relevant servers.
00462    *
00463    * @exception Exception
00464    *   - Not yet configured (id 551)
00465    *   - Fatal network error (id 553)
00466    *   - Fatal pthread error (id 554)
00467    */
00468   virtual void Start(void);
00469 
00470   /**
00471    * Deactivate the device. This function disables output execution and input reading.
00472    * It stops the backhround thread to provide connections and disconnects from any servers.
00473    */
00474   virtual void Stop(void);
00475 
00476   /**
00477    * Reset device. Resets buffered input events and current time.
00478    *
00479    */
00480   virtual void Reset(void);
00481 
00482   /**
00483    * Run output command.
00484    *
00485    * @exception Exception
00486    *   - unknown output event (id 65)
00487    */
00488   virtual void WriteOutput(Idx output);
00489 
00490 
00491 
00492  protected:
00493 
00494   /**
00495    * Actual method to read device configuration from tokenreader.
00496    *
00497    * This method calls the base class to read the device name and the
00498    * the timescale. It then reads address, networkid and nodes.
00499    * Overall device configuration is consists of DoReadPreface,
00500    * DoReadConfiguration and Compile. It isimplemented in vDevice.
00501    * The label and context parameters are ignored.
00502    *
00503    * @param rTr
00504    *   TokenReader to read from
00505    * @param rLabel
00506    *   Section to read
00507    * @param pContext
00508    *   Read context to provide contextual information
00509    *
00510    * @exception Exception
00511    *   - IO error (id 1)
00512    */
00513   virtual void DoReadPreface(TokenReader& rTr,  const std::string& rLabel = "", const Type* pContext=0);
00514  
00515   /**
00516    * Actual method to write the device configuration to a TokenWriter.
00517    *
00518    * This method calls the base class vDevice to write the device name and
00519    * the time scale. It then writes network related data. The label and
00520    * context parameters are ignored.
00521    *
00522    * @param rTw
00523    *   Reference to TokenWriter
00524    * @param rLabel
00525    *   Label of section to write
00526    * @param pContext
00527    *   Read context to provide contextual information
00528    * @exception Exception 
00529    *   - IO errors (id 2)
00530    */
00531   virtual void DoWritePreface(TokenWriter& rTw, const std::string& rLabel="", const Type* pContext=0) const;
00532 
00533 
00534   /** Overall configuration (with actual type) */
00535   TaNameSet<AttributeSimplenetEvent>* pConfiguration ;
00536 
00537   /** Simplenet: network id */
00538   std::string mNetwork;
00539 
00540   /** Simplenet: address of my server port */
00541   SimplenetAddress mAddress;
00542 
00543   /** Simplenet: effective address of my server port */
00544   SimplenetAddress mEffectiveAddress;
00545 
00546   /** Simplenet: list of nodes in this network */
00547   std::set<std::string> mNetworkNodes;
00548   
00549   /** Simplenet: list of event server addresses */
00550   std::set<std::string> mInputServers;
00551   
00552   /** Compiled data: map subscriptions */
00553   std::map<std::string,EventSet> mInputSubscriptions;
00554 
00555   /** Background: mutex for below shared variables*/
00556   pthread_mutex_t mMutex;
00557 
00558   /** Background: thread handle (global) */
00559   pthread_t mThreadListen; 
00560 
00561   /** Background: request to join via flag (mutexed) */
00562   bool mStopListen;
00563 
00564   /** Background: server socket to listen (background only) */
00565   int mServerSocket;
00566   
00567   /** Background: server port to bind (background only) */
00568   struct sockaddr_in mServerAddress;
00569 
00570   /** Background: udp broadcast socket (background only) */
00571   int mBroadcastSocket;
00572   
00573   /** Background: state of a connection to a client (shared) */
00574   typedef struct {
00575     nDevice* mDevice;        // refernce to this device
00576     int  mClientSocket;      // the socket the client is connected to
00577     pthread_t mThread;       // the thread we run to reply to client requests
00578     EventSet mEvents;        // events the client has subscribed to 
00579   } ClientState;  
00580 
00581   /** Background: map sockets to connection states (shared) */
00582   std::map<int, ClientState> mOutputClientStates;
00583 
00584   /** Background: state of a connection to an event server (shared)*/
00585   typedef struct {
00586     SimplenetAddress mAddress;  // ip address incland tcp port of remote server
00587     EventSet mEvents;           // events we have subscribed to
00588     int  mServerSocket;         // socket used to connect with provider
00589     std::string mLineBuffer;    // buffer to receive one line
00590   } ServerState;  
00591 
00592   /** Background: connection states to event servers (by node name)*/
00593   std::map<std::string,ServerState> mInputServerStates;
00594 
00595 
00596 
00597 }; // end class nDevice
00598 
00599 // declare background threads
00600 void* NDeviceListen(void*);
00601 void* NDeviceServer(void*);
00602 void* NDeviceReply(void*);
00603 
00604 
00605 
00606 
00607 } // namespace faudes
00608 
00609 #endif // configured
00610 #endif // include

libFAUDES 2.18b --- 2010-12-17 --- c++ source docu by doxygen 1.6.3