iop_simplenet.hGo 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 |