iop_simplenet.h
Go to the documentation of this file.
1/** @file iop_simplenet.h Simple networked events via TCP/IP */
2
3/*
4 FAU Discrete Event Systems Library (libfaudes)
5
6 Copyright (C) 2008, 2024 Thomas Moor
7 Exclusive copyright is granted to Klaus Schmidt
8
9*/
10
11
12
13#ifndef FAUDES_IOP_SIMPLENET_H
14#define FAUDES_IOP_SIMPLENET_H
15
16#include "corefaudes.h"
17#include "iop_vdevice.h"
18
19
20namespace faudes {
21
22
23/**
24 * Simplenet node address.
25 *
26 * A node address consists of an IP address and a TCP port.
27 * This convenience class implements string based access to both components.
28 *
29 */
30
32
33public:
34
35 /** Default constructor */
36 SimplenetAddress(void);
37
38 /** Copy construct */
40
41 /** Construct from string */
42 SimplenetAddress(const std::string& rString);
43
44 /** Return true if valid */
45 bool Valid(void) const;
46
47 /** Get IP address */
48 std::string Ip(void) const { return mIp; };
49
50 /** Get TCP port */
51 int Port(void) const { return mPort; };
52
53 /** Get as colon seperated string */
54 std::string IpColonPort(void) const;
55
56 /** Set IP address */
57 void Ip(std::string ip) { mIp=ip; };
58
59 /** Set TCP port */
60 void Port(int port) { mPort=port; };
61
62 /** Set from colon seperated string */
63 void IpColonPort(std::string ipcolonport);
64
65 /** Order for sorting containers of addresses */
66 bool operator < (const SimplenetAddress& rOther) const;
67
68 protected:
69
70 /** Ip address */
71 std::string mIp;
72
73 /** TCP port */
74 int mPort;
75
76};
77
78
79
80// only compile for simplenet support
81#ifdef FAUDES_IODEVICE_SIMPLENET
82
83
84
85
86/**
87 * Configuration of a network output mapping.
88 *
89 * There is nothing to configure here: any client that
90 * connects to this device can subscribe to any output event.
91 * Future versions of libFAUDES may specify a set of receipent
92 * clients.
93 *
94 */
95
97
99
100public:
101
102 /** Default constructor */
104
105 /** Copy constructor */
108
109 /** Test for default value (always, since we have no data) */
110 virtual bool IsDefault(void) const {return true;};
111
112 /** Clear to default */
113 virtual void Clear(void) {};
114
115protected:
116
117 /** Copy method
118 *
119 * @param rSrcAttr
120 * Source to copy from
121 */
122 void DoCopy(const AttributeSimplenetOutput& rSrcAttr)
123 {(void) rSrcAttr;};
124
125 /** Copy method
126 *
127 * @param rSrcAttr
128 * Source to copy from
129 */
131 {(void) rSrcAttr;};
132
133 /**
134 * Reads the attribute from TokenReader, see AttributeVoid for public wrappers.
135 *
136 * If the current token indicates a input mapping, the method reads that
137 * section. Else it does nothing. Exceptions may only be thrown
138 * on invalid data within the section. The label argument is ignored, we use the
139 * hardcoded section "Output" for output attributes. The context argument is ignored.
140 *
141 * @param rTr
142 * TokenReader to read from
143 * @param rLabel
144 * Section to read
145 * @param pContext
146 * Read context to provide contextual information
147 *
148 * @exception Exception
149 * - IO error (id 1)
150 */
151 virtual void DoRead(TokenReader& rTr,const std::string& rLabel="", const Type* pContext=0);
152
153 /**
154 * Writes the attribute to TokenWriter, see AttributeVoid for public wrappers.
155 *
156 * Writes the output mapping data. The label argument is ignored, we use
157 * the hardcoded section "Output". The context argument is ignored.
158 *
159 * @param rTw
160 * TokenWriter to write to
161 * @param rLabel
162 * Section to write
163 * @param pContext
164 * Read context to provide contextual information
165 *
166 * @exception Exception
167 * - IO error (id 2)
168 */
169 virtual void DoWrite(TokenWriter& rTw,const std::string& rLabel="", const Type* pContext=0) const;
170
171}; // end class AttributeSimplenetOutput
172
173
174/**
175 * Configuration of a network input mapping.
176 *
177 * There is nothing to configure here: any server that
178 * provides the repective event will be accepted. Future versions
179 * of libFAUDES may specify a set of servers here.
180 *
181 */
182
184
186
187public:
188
189 /** Default constructor (no triggers) */
191
192 /** Copy constructor */
194 {DoCopy(rSrcAttr);};
195
196
197 /** Test for default value (always, since we have no data) */
198 virtual bool IsDefault(void) const {return true;};
199
200 /** Clear to default */
201 virtual void Clear(void) {};
202
203protected:
204
205 /** Copy method
206 *
207 * @param rSrcAttr
208 * Source to copy from
209 */
210 void DoCopy(const AttributeSimplenetInput& rSrcAttr)
211 {(void) rSrcAttr;};
212
213
214 /** Copy method
215 *
216 * @param rSrcAttr
217 * Source to copy from
218 */
219 void DoMove(const AttributeSimplenetInput& rSrcAttr)
220 {(void) rSrcAttr;};
221
222
223 /**
224 * Reads the attribute from TokenReader, see AttributeVoid for public wrappers.
225 *
226 * If the current token indicates a input mapping, the method reads that
227 * section. Else it does nothing. Exceptions may only be thrown
228 * on invalid data within the section. The label argument is ignored, we the hardcoded
229 * section "Input" for input device attributes. The context argument is ignored.
230 *
231 * @param rTr
232 * TokenReader to read from
233 * @param rLabel
234 * Section to read
235 * @param pContext
236 * Read context to provide contextual information
237 *
238 * @exception Exception
239 * - IO error (id 1)
240 */
241 virtual void DoRead(TokenReader& rTr,const std::string& rLabel="", const Type* pContext=0);
242
243 /**
244 * Writes the attribute to TokenWriter, see AttributeVoid for public wrappers.
245 *
246 * Writes the input mapping data.The label argument is ignored, we use
247 * the hardcoded section "Input". The context argument is ignored.
248 *
249 * @param rTw
250 * TokenWriter to write to
251 * @param rLabel
252 * Section to write
253 * @param pContext
254 * Read context to provide contextual information
255 *
256 * @exception Exception
257 * - IO error (id 2)
258 */
259 virtual void DoWrite(TokenWriter& rTw,const std::string& rLabel="", const Type* pContext=0) const;
260
261}; // end class AttributeSimplenetInput
262
263
264
265/**
266 * Configuration of a networked input or output
267 *
268 * This class is derived from the AttributeDeviceEvent to specialise
269 * for networked input and output mapping.
270 *
271 */
272
274
276
277public:
278
279 /** Default constructor (no mapping at all) */
281
282 /** Copy constructor */
284
285 /** Test for default value (never) */
286 virtual bool IsDefault(void) const {return false;};
287
288 /** Clear */
289 virtual void Clear(void) { AttributeDeviceEvent::Clear(); };
290
291 /** Get output mapping */
293 return static_cast<AttributeSimplenetOutput*>(mpOutputAttribute); };
294
295 /** Get input mapping */
296 const AttributeSimplenetInput* Inputp(void) const {
297 return static_cast<AttributeSimplenetInput*>(mpInputAttribute); };
298
299protected:
300
301 /** DoCopy */
303 { AttributeDeviceEvent::DoCopy(rSrc);};
304
305 /** DoMove */
307 { AttributeDeviceEvent::DoMove(rSrc);};
308
309 /** Prototype, input (construct on first use static) */
310 static const AttributeSimplenetInput* InputPrototypep(void);
311
312 /** Prototype, output (construct on first use static) */
313 static const AttributeSimplenetOutput* OutputPrototypep(void);
314
315}; // class AttributeSimplenetEvent
316
317
318/**
319 * An nDevice implements networked IO via a simple TCP/IP protocol.
320 *
321 * @section SecIodeviceNDev1 Networking
322 *
323 * The purpose of this implementation of networked discrete events is to provide
324 * a basis for case studies. However, simple networked events via nDevice must not
325 * be confused with ongoing research that addresses synchronisation and real
326 * time behaviour. We take a really pragmatic approach here.
327 *
328 * Our <em>network</em> is identified by its <em>network name</em>. It consists
329 * a number of <em>nodes</em>, each identified by its <em>node name</em>. In the current implementation,
330 * each node knows about the entire network ie knows about all other nodes. Each node plays two roles:
331 * - the <em>server</em> role to send event notifications, and
332 * - the <em>client</em> role to receive event notifications.
333 *
334 * In their server role, each node is configured to listen on its <em>server port</em> for incomming
335 * TCP connections. When a client (i.e. some other node in client role) connects to the TCP port, the server
336 * replies to a simple command set in order to allow the client to subscribe to the nodes output events.
337 * When the application executes an output event on the node, this is notified to all connected clients and
338 * the clients will interpret the event as an input reading. Vice versa, the each node itself has the
339 * role of a client and subscribes to relevant output events served by other nodes in their server role.
340 *
341 * @section SecIodeviceNDev2 Protocol Details
342 *
343 * The protocol for commands and notification is libFAUDES-token based and can be inspected eg via nc
344 * or telnet; see the shell script in the tutorial.
345 * Event notifications are sent spontaneous to all connected clients in the format
346 * <tt><Notify> Ev </Notify></tt>.
347 * Commands are accepted in the format <tt><Cmd> Command </Cmd></tt> and will be
348 * answered accordingly.
349 *
350 * <table valign="top">
351 * <tr>
352 * <td> Command via TCP</td>
353 * <td> Reply </td>
354 * </tr>
355 * <tr>
356 * <td> <tt><Cmd> Info </Cmd></tt> </td>
357 * <td> configuration of node as token string (<tt><SimplenetDevice name="SimpleMachine"> ...
358 * </SimplenetDevice> </tt> ) </td>
359 * </tr>
360 * <tr>
361 * <td> <tt><Cmd> Status </Cmd></tt> </td>
362 * <td> acknowledgement with status string (<tt><Ack> Up </Ack></tt>,
363 * <tt><Ack> StartUp </Ack></tt> or <tt><Ack> ShutDown </Ack></tt>, respectively;
364 * will not connect/reply while Down) </td>
365 * </tr>
366 * <tr>
367 * <td> <tt><Cmd> ResetRequest </Cmd></tt> </td>
368 * <td> no acknowledgement </td>
369 * </tr>
370 * <tr>
371 * <td> <tt><Subscribe> Ev_1 ... Ev_N </Subscribe></tt> </td>
372 * <td> subset of available events (e.g. <tt><Subscribed> Ev_2 Ev_7 Ev_9 </Subscribed></tt>)</td>
373 * </tr>
374 * </table>
375 *
376 * A minimal alternative implementation for a node consists of (1) a TCP server that ignores all
377 * incomming messages and issues event notifications to any relevant events; and, (2) a TCP client
378 * that subscribes to all events and then listens to event notifications. All other commands are
379 * optional and may change in future revisions of this protocol.
380 *
381 * @section SecIodeviceNDev3 Name Resolution
382 *
383 * On the technical side, each node needs to figure the IP addresses incl TCP ports on which the
384 * other nodes provide their service. To ease configuration, this information is distributed by
385 * UDP datagrams. In order to locate the other nodes within the network, a node may broadcasts a
386 * network <em>request</em> datagramm. Each node that receives such a request, replies with an
387 * <em>advert</em> datagramm to provide its address. Thus, the simple net nodes rely on some
388 * underlying name resolution by DNS services, but node configuration itself refers to simple-net node names
389 * only. Since each node knows about the names of all participating nodes, each node will know when
390 * all connections are up.
391 *
392 * By default, UDP broadcasts are addressed to 255.255.255.255:40000. Since
393 * routers are not meant to pass-on broadcasts, nDevice name resolution is restricted to
394 * one subnet. If the local host is connected to multiple subnets, you need to specify the
395 * relevant subset explicitly by setting the appropriate broadcast address, e.g. 192.168.2.255:40000.
396 * To restrict networks to the local machine, set the broadcast address to the loopback device
397 * 127.0.0.1:40000. To span a network accross multiple subnets, server addresses can be
398 * explicitly specified as an attribute in the node configuration;
399 * e.g. <tt> <Node> name=\"SimpleSupervisor\" address=\"192.168.2.1:40000\"</Node></tt>.
400 * This is also the preferred
401 * fallback when address resolution fails for other reasons.
402 *
403 * <table valign="top">
404 * <tr>
405 * <td> Broadcast via UDP</td>
406 * <td> Reply </td>
407 * </tr>
408 * <tr>
409 * <td> <tt><Request> network reqnode </Request></tt> </td>
410 * <td> advertisement of networkname, nodename and ip-address:port, e.g.,
411 * <tt> <Advert> SimpleLoop SimpleSupervisor 192.168.2.1:40000 </Advert></tt>
412 * </td>
413 * </tr>
414 * </table>
415 * <p>
416 *
417 * @section SecIodeviceNDev4 File IO
418 *
419 * For token IO, the nDevice reads and writes a section with label
420 * "SimplenetDevice". There are no relevant attributes yet. Simple machine example:
421 *
422 * @code
423 * <SimplenetDevice name="SimpleMachine">
424 *
425 * <!-- Time scale in ms/ftiu -->
426 * <TimeScale value="1000"/>
427 *
428 * <!-- IP address of this node, incl. server TCP port -->
429 * <ServerAddress value="localhost:40000"/>
430
431 * <!-- Broadcaset address for node resolution (optional)
432 * <BroadcastAddress value="255.255.255.255:40000"/>
433 *
434 * <!-- Network topology -->
435 * <Network name="SimpleLoop">
436 * <Node name="SimpleMachine"/>
437 * <Node name="SimpleSupervisor"/>
438 * </Network>
439 *
440 * <!-- Event configuration -->
441 * <EventConfiguration>
442 * <Event name="alpha" iotype="input"/>
443 * <Event name="beta" iotype="output"/>
444 * <Event name="mue" iotype="output"/>
445 * <Event name="lambda" iotype="input"/>
446 * </EventConfiguration>
447 *
448 * </SimplenetDevice>
449 * @endcode
450 *
451 * @section SecIodeviceNDev5 Implementation Notes
452 *
453 * The current status of the code is premature; network io
454 * assumes reasonably large buffers; thread/select mechanism is inefficient;
455 * exception handling wont work; etc etc
456 *
457 *
458 * @ingroup IODevicePlugin
459 */
460
461class FAUDES_API nDevice : public vDevice {
462
464
465 // provide all access to background tasks
466 friend void* NDeviceListen(void*);
467 friend void* NDeviceServer(void*);
468 friend void* NDeviceReply(void*);
469
470 public:
471 /**
472 * Default constructor
473 */
474 nDevice(void);
475
476 /**
477 * Copy constructor
478 */
479 nDevice(const nDevice& rOther);
480
481 /**
482 * Explicit destructor.
483 */
484 virtual ~nDevice(void);
485
486 /**
487 * Clear all configuration.
488 * This implies Stop().
489 */
490 virtual void Clear(void);
491
492 /**
493 * Set server address of this node.
494 * Note: you can only set th server address while the
495 * device is down.
496 *
497 * @param rAddr
498 * Address on which to run this server, e.g. "localhost:40000"
499 * @exception Exception
500 * - No valid address (id 551) (NOT IMPLEMENTED)
501 */
502 void ServerAddress(const std::string& rAddr);
503
504 /**
505 * Set broadcast address for address resolution
506 * Note: you can only set the broadcast address while the
507 * device is down.
508 *
509 * @param rAddr
510 * Address for UDP broadcasts e.g. "255.255.255.255:40000"
511 * @exception Exception
512 * - No valid address (id 551) (NOT IMPLEMENTED)
513 */
514 void BroadcastAddress(const std::string& rAddr);
515
516 /**
517 * Set network name to participate.
518 * Note: you can only set the network name
519 * while the device is down.
520 *
521 * @param rNetwork
522 * Name of network, e.g. "ElevatorNetwork"
523 */
524 void NetworkName(const std::string& rNetwork);
525
526 /**
527 * Add a node to the network configuration.
528 * Note: you can only configure the network
529 * while the device is down.
530 *
531 * @param rNodeName
532 * Node to participate in wthe network.
533 */
534 void InsNode(const std::string& rNodeName);
535
536 /**
537 * Add entry to node name resolution
538 *
539 * Note: you can only configure the network
540 * while the device is down.
541 * @param rNode
542 * Name of node to register
543 * @param rAddress
544 * Address incl port
545 */
546 void InsNodeAddress(const std::string& rNode, const std::string& rAddress);
547
548
549 /**
550 * Add a node to the network configuration.
551 * Note: you can only configure the network
552 * while the device is down.
553 *
554 */
555 void ClearNodes(void);
556
557 /**
558 * Insert event as input event.
559 * Note: you can only configure events
560 * while the device is down.
561 *
562 * @param event
563 * Event by name.
564 */
565 void InsInputEvent(const std::string& event);
566
567
568 /**
569 * Insert event as output event.
570 * Note: you can only configure event
571 * while the device is down.
572 *
573 * @param event
574 * Event by name.
575 */
576 void InsOutputEvent(const std::string& event);
577
578
579 /**
580 * Set up internal data structures
581 *
582 */
583 virtual void Compile(void);
584
585
586 /**
587 * Activate the device. This function enables output execution and input reading.
588 * It starts the background thread for incomming connections and tries to connect to relevant servers.
589 *
590 * @exception Exception
591 * - Not yet configured (id 551)
592 * - Fatal network error (id 553)
593 * - Fatal thread error (id 554)
594 */
595 virtual void Start(void);
596
597 /**
598 * Deactivate the device. This function disables output execution and input reading.
599 * It stops the backhround thread to provide connections and disconnects from any servers.
600 */
601 virtual void Stop(void);
602
603 /**
604 * Reset device. Resets buffered input events and current time.
605 *
606 */
607 virtual void Reset(void);
608
609 /**
610 * Run output command.
611 *
612 * @exception Exception
613 * - unknown output event (id 65)
614 */
615 virtual void WriteOutput(Idx output);
616
617
618
619protected:
620
621 /**
622 * Copyment
623 *
624 * @param rSrc
625 * Source to copy from
626 */
627 void DoCopy(const nDevice& rSrc);
628
629 /**
630 * Copyment
631 *
632 * @param rSrc
633 * Source to copy from
634 */
635 void DoMove(nDevice& rSrcAttr);
636
637 /**
638 * Actual method to read device configuration from tokenreader.
639 *
640 * This method calls the base class to read the device name and the
641 * the timescale. It then reads address, networkid and nodes.
642 * Overall device configuration is consists of DoReadPreface,
643 * DoReadConfiguration and Compile. It isimplemented in vDevice.
644 * The label and context parameters are ignored.
645 *
646 * @param rTr
647 * TokenReader to read from
648 * @param rLabel
649 * Section to read
650 * @param pContext
651 * Read context to provide contextual information
652 *
653 * @exception Exception
654 * - IO error (id 1)
655 */
656 virtual void DoReadPreface(TokenReader& rTr, const std::string& rLabel = "", const Type* pContext=0);
657
658 /**
659 * Actual method to write the device configuration to a TokenWriter.
660 *
661 * This method calls the base class vDevice to write the device name and
662 * the time scale. It then writes network related data. The label and
663 * context parameters are ignored.
664 *
665 * @param rTw
666 * Reference to TokenWriter
667 * @param rLabel
668 * Label of section to write
669 * @param pContext
670 * Read context to provide contextual information
671 * @exception Exception
672 * - IO errors (id 2)
673 */
674 virtual void DoWritePreface(TokenWriter& rTw, const std::string& rLabel="", const Type* pContext=0) const;
675
676
677 /** Overall configuration (with actual type) */
679
680 /** Simplenet: network id */
681 std::string mNetwork;
682
683 /** Simplenet: address of my server incl port (localhost:40000)*/
685
686 /** Simplenet: address for udp broadcast (255.255.255.255:40000*/
688
689 /** Simplenet: effective address of my server port */
691
692 /** Simplenet: list of nodes in this network incl default addresses*/
693 std::map<std::string,std::string> mNetworkNodes;
694
695 /** Compiled data: map subscriptions */
696 std::map<std::string,EventSet> mInputSubscriptions;
697
698 /** Background: mutex for below shared variables*/
699 faudes_mutex_t mMutex;
700
701 /** Background: thread handle (global) */
702 faudes_thread_t mThreadListen;
703
704 /** Background: request to join via flag (mutexed) */
706
707 /** Background: server socket to listen (background only) */
709
710 /** Background: udp broadcast socket (background only) */
712
713 /** Background: state of a connection to a client (shared) */
714 typedef struct {
715 int mClientSocket; // the socket the client is connected to
716 EventSet mEvents; // events the client has subscribed to
717 bool mConnected; // set to true, if a subscription has been seen
718 std::string mLineBuffer; // buffer to receive one line
719 } ClientState;
720
721 /** Background: map sockets to connection states (shared) */
722 std::map<int, ClientState> mOutputClientStates;
723
724 /** Background: state of a connection to an event server (shared)*/
725 typedef struct {
726 SimplenetAddress mAddress; // actual IP address incl TCP port of remote server
727 SimplenetAddress mDefaultAddress; // default IP address incl TCP port of remote server
728 EventSet mEvents; // events we have subscribed to
729 int mServerSocket; // socket used to connect with provider
730 std::string mLineBuffer; // buffer to receive one line
731 } ServerState;
732
733 /** Background: connection states to event servers (by node name)*/
734 std::map<std::string,ServerState> mInputServerStates;
735
736
737
738}; // end class nDevice
739
740// declare background threads
741void* NDeviceListen(void*);
742
743#endif // configured for simplenet
744
745
746
747} // namespace faudes
748
749#endif // include
#define FAUDES_API
#define FAUDES_TYPE_DECLARATION(ftype, ctype, cbase)
Definition cfl_types.h:918
const AttributeSimplenetOutput * Outputp(void) const
const AttributeSimplenetInput * Inputp(void) const
void DoMove(AttributeSimplenetEvent &rSrc)
void DoCopy(const AttributeSimplenetEvent &rSrc)
virtual bool IsDefault(void) const
void DoMove(const AttributeSimplenetInput &rSrcAttr)
virtual bool IsDefault(void) const
void DoCopy(const AttributeSimplenetInput &rSrcAttr)
AttributeSimplenetInput(const AttributeSimplenetInput &rSrcAttr)
void DoMove(AttributeSimplenetOutput &rSrcAttr)
AttributeSimplenetOutput(const AttributeSimplenetOutput &rSrcAttr)
virtual bool IsDefault(void) const
void DoCopy(const AttributeSimplenetOutput &rSrcAttr)
void Ip(std::string ip)
std::string Ip(void) const
friend void * NDeviceServer(void *)
SimplenetAddress mListenAddress
TaNameSet< AttributeSimplenetEvent > * pConfiguration
std::string mNetwork
friend void * NDeviceReply(void *)
std::map< std::string, EventSet > mInputSubscriptions
faudes_thread_t mThreadListen
std::map< std::string, ServerState > mInputServerStates
std::map< int, ClientState > mOutputClientStates
faudes_mutex_t mMutex
SimplenetAddress mEffectiveListenAddress
SimplenetAddress mBroadcastAddress
std::map< std::string, std::string > mNetworkNodes
uint32_t Idx
void * NDeviceListen(void *arg)
SimplenetAddress mDefaultAddress

libFAUDES 2.34e --- 2026.03.16 --- c++ api documentaion by doxygen