libFAUDES
Sections
Index
|
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 #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.20d --- 2011.04.26 --- c++ source docu by doxygen