Jpp
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
JControlHost.hh
Go to the documentation of this file.
1 #ifndef __JNET__JCONTROLHOST__
2 #define __JNET__JCONTROLHOST__
3 
4 #include <string>
5 #include <sstream>
6 #include <arpa/inet.h>
7 #include <set>
8 
9 #include "JNet/JPrefix.hh"
10 #include "JNet/JSocket.hh"
11 #include "JNet/JSocketBlocking.hh"
12 #include "JNet/JHostname.hh"
13 #include "JLang/JException.hh"
14 #include "JLang/JThrow.hh"
15 #include "JLang/JTimeval.hh"
16 
17 
18 /**
19  * \author mdejong
20  */
21 
22 namespace JNET {}
23 namespace JPP { using namespace JNET; }
24 
25 namespace JNET {
26 
28  using JLANG::JThrow;
29  using JLANG::JTimeval;
30 
31 
32  static const std::string CHOO_VERSION = "1.0";
33 
34 
35  /**
36  * ControlHost subscription types.
37  */
41  //SUBSCRIBE_SHARED_MEMORY = 'm'
42  };
43 
44 
45  /**
46  * ControlHost subscription.
47  */
48  class JSubscription :
49  public JTag
50  {
51  public:
52  /**
53  * Constructor.
54  *
55  * \param sub subscription
56  * \param tag tag
57  */
59  const JTag& tag) :
60  JTag (tag),
61  subscription(sub)
62  {}
63 
64 
65  /**
66  * Get subscription type.
67  *
68  * \return subscription
69  */
71  {
72  return subscription;
73  }
74 
75 
76  /**
77  * Convert subscription to string.
78  *
79  * \return subscription
80  */
81  std::string toString() const
82  {
83  return std::string(1, (char) subscription) + " " + JTag::toString();
84  }
85 
86 
87  protected:
89  };
90 
91 
92  /**
93  * Auxiliary class for all subscription.
94  */
96  public JSubscription
97  {
98  /**
99  * Constructor.
100  *
101  * \param tag tag
102  */
105  {}
106  };
107 
108 
109  /**
110  * Auxiliary class for any subscription.
111  */
113  public JSubscription
114  {
115  /**
116  * Constructor.
117  *
118  * \param tag tag
119  */
122  {}
123  };
124 
125 
126  /**
127  * Subscription list.
128  */
130  protected std::set<JSubscription>
131  {
132  public:
133  /**
134  * Default constructor.
135  */
137  std::set<JSubscription>()
138  {}
139 
140 
141  /**
142  * Add subscription.
143  *
144  * \param subscription subscription
145  */
146  JSubscriptionList& add(const JSubscription& subscription)
147  {
148  const_iterator p = this->find(subscription);
149 
150  if (p != this->end() && p->getID() == subscription.getID()) {
151 
152  if (p-> getSubscription() == SUBSCRIBE_ALL ||
153  subscription.getSubscription() == SUBSCRIBE_ANY)
154  return *this; // maintain higher subscription level
155  else
156  this->erase(p); // remove lower subscription level
157  }
158 
159  this->insert(p, subscription);
160 
161  return *this;
162  }
163 
164 
165  /**
166  * Convert subscription list to string.
167  *
168  * \return subscription
169  */
170  std::string toString() const
171  {
172  std::string buffer;
173 
174  for (const_iterator i = this->begin(); i != this->end(); ++i)
175  buffer += ' ' + i->toString();
176 
177  return buffer;
178  }
179  };
180 
181 
182  /**
183  * Add operator.
184  *
185  * \param first subscription
186  * \param second subscription
187  * \return subscription list
188  */
189  inline JSubscriptionList operator+(const JSubscription& first, const JSubscription& second)
190  {
191  JSubscriptionList buffer;
192 
193  buffer.add(first);
194  buffer.add(second);
195 
196  return buffer;
197  }
198 
199 
200  /**
201  * Add operator.
202  *
203  * \param first subscription list
204  * \param second subscription
205  * \return subscription list
206  */
207  inline JSubscriptionList operator+(const JSubscriptionList& first, const JSubscription& second)
208  {
209  JSubscriptionList buffer(first);
210 
211  buffer.add(second);
212 
213  return buffer;
214  }
215 
216 
217  /**
218  * ControlHost class.
219  */
220  class JControlHost :
221  public JSocketBlocking,
222  public JThrow<JControlHost>
223  {
224  protected:
225  /**
226  * Default constructor.
227  */
229  JSocketBlocking(JSocket(AF_INET, SOCK_STREAM))
230  {
231  configure();
232  }
233 
234 
235  public:
236  /**
237  * Check special ControlHost tags.
238  *
239  * \param tag tag
240  * \return true if possibly special tag; else false
241  */
242  static bool maybe_special(const JTag& tag)
243  {
244  return tag[0] == '_';
245  }
246 
247 
248  /**
249  * Check validity of subscription specifier.
250  *
251  * \param c subscription specifier
252  * \return true if valid; else false
253  */
254  static bool is_valid(const char c)
255  {
256  return (c == SUBSCRIBE_ALL ||
257  c == SUBSCRIBE_ANY);// ||
258  //c == SUBSCRIBE_SHARED_MEMORY);
259  }
260 
261 
262  /**
263  * Constructor.
264  *
265  * \param server host name and optional port number
266  */
267  JControlHost(const JHostname& server) :
268  JSocketBlocking(JSocket(AF_INET, SOCK_STREAM))
269  {
270  if (server.hostname != "")
271  connect(server.hostname, server.port);
272  else
273  connect(server.port);
274 
275  configure();
276  }
277 
278 
279  /**
280  * Constructor.
281  *
282  * \param server host name
283  * \param port port
284  */
285  JControlHost(const std::string& server,
286  const int port) :
287  JSocketBlocking(JSocket(AF_INET, SOCK_STREAM))
288  {
289  connect(server, port);
290 
291  configure();
292  }
293 
294 
295  /**
296  * Constructor.
297  *
298  * \param ip_number IP number
299  * \param port port
300  */
301  JControlHost(const int ip_number,
302  const int port = DISPATCH_PORT) :
303  JSocketBlocking(JSocket(AF_INET, SOCK_STREAM))
304  {
305  connect(ip_number, port);
306 
307  configure();
308  }
309 
310 
311  /**
312  * Constructor.
313  *
314  * \param socket socket
315  */
316  JControlHost(const JSocket& socket) :
317  JSocketBlocking(JSocket(socket))
318  {}
319 
320 
321  /**
322  * Destructor.
323  */
325  {
326  shutdown();
327  }
328 
329 
330  /**
331  * Subscribe to single tag.
332  *
333  * \param subscription subscription
334  * \return 0 if OK; -1 if socket error
335  */
336  int Subscribe(const JSubscription& subscription)
337  {
338  return PutFullString(DISPTAG_Subscribe, subscription.toString());
339  }
340 
341 
342  /**
343  * Subscribe to list of tags.
344  *
345  * \param subscription subscription
346  * \return 0 if OK; -1 if socket error
347  */
348  int Subscribe(const JSubscriptionList& subscription)
349  {
350  return PutFullString(DISPTAG_Subscribe, subscription.toString());
351  }
352 
353 
354  /**
355  * Identify.
356  *
357  * \param nick_name nick name
358  * \return 0 if OK; -1 if socket error
359  */
360  int MyId(const std::string& nick_name)
361  {
362  return PutFullString(DISPTAG_MyId, nick_name);
363  }
364 
365 
366  /**
367  * Tell server to send next message.
368  *
369  * \return 0 if OK; -1 if socket error
370  */
372  {
373  return PutFullData(DISPTAG_Gime, NULL, 0);
374  }
375 
376 
377  /**
378  * Tell server to send messages forever.
379  *
380  * \return 0 if OK; -1 if socket error
381  */
383  {
384  return PutFullData(DISPTAG_Always, NULL, 0);
385  }
386 
387 
388  /**
389  * Send data.
390  *
391  * \param tag tag
392  * \param buffer data
393  * \param length number of bytes
394  * \return 0 if OK; -1 if socket error; -2 if other error
395  */
396  int PutFullData(const JTag& tag,
397  const void* buffer,
398  const int length)
399  {
400  try {
401 
402  this->prefix.set(tag, length);
403 
404  write((char*) &this->prefix, sizeof(JPrefix));
405 
406  if (length != 0) {
407  write((char*) buffer, length);
408  }
409 
410  return 0;
411  }
412  catch (const JSocketException& error) {
413  return Throw(error, -1);
414  }
415  }
416 
417 
418  /**
419  * Send data.
420  *
421  * \param tag tag
422  * \param buffer data
423  * \param length number of bytes
424  * \return 0 if OK; -1 if socket error; -2 if other error
425  */
426  int PutFullData(const std::string& tag,
427  const void* buffer,
428  const int length)
429  {
430  try {
431  return PutFullData(JTag(tag), buffer, length);
432  }
433  catch (const JSocketException& error) {
434  return Throw(error, -1);
435  }
436  catch (const JControlHostException& error) {
437  return Throw(error, -2);
438  }
439  }
440 
441 
442  /**
443  * Send string.
444  *
445  * \param tag tag
446  * \param buffer data
447  * \return 0 if OK; -1 if socket error; -2 if other error
448  */
449  int PutFullString(const JTag& tag,
450  const std::string& buffer)
451  {
452  return PutFullData(tag, buffer.c_str(), buffer.size());
453  }
454 
455 
456  /**
457  * Send string.
458  *
459  * \param tag tag
460  * \param buffer data
461  * \return 0 if OK; -1 if socket error; -2 if other error
462  */
463  int PutFullString(const std::string& tag,
464  const std::string& buffer)
465  {
466  return PutFullData(tag, buffer.c_str(), buffer.size());
467  }
468 
469 
470  /**
471  * Send version.
472  *
473  * \return 0 if OK; -1 if socket error; -2 if other error
474  */
475  int Connected()
476  {
478  }
479 
480 
481  /**
482  * Wait for header.
483  *
484  * \param prefix prefix
485  * \return 0 if OK; -1 if socket error
486  */
488  {
489  try {
490 
491  read((char*) &prefix, sizeof(JPrefix));
492 
493  return 0;
494  }
495  catch (const JSocketException& error) {
496  return Throw(error, -1);
497  }
498  }
499 
500 
501  /**
502  * Wait for header.
503  *
504  * \param tag tag
505  * \param length number of bytes
506  * \return 0 if OK; -1 if socket error
507  */
508  int WaitHead(std::string& tag, int& length)
509  {
510  const int rvalue = WaitHead(this->prefix);
511 
512  if (rvalue == 0) {
513  tag = this->prefix.getTag();
514  length = this->prefix.getSize();
515  }
516 
517  return rvalue;
518  }
519 
520 
521  /**
522  * Check for header, without waiting.
523  *
524  * \param prefix prefix
525  * \param timeout timeout
526  * \return 1 if header; 0 if no header; -1 if socket error
527  */
529  {
530  try {
531 
532  if (in_avail(timeout)) {
533 
534  WaitHead(prefix);
535 
536  return 1;
537 
538  } else {
539 
540  return 0;
541  }
542  }
543  catch (const JSocketException& error) {
544  return Throw(error, -1);
545  }
546  }
547 
548 
549  /**
550  * Check for header, without waiting.
551  *
552  * \param tag tag
553  * \param length number of bytes
554  * \param timeout_us timeout [us]
555  * \return 1 if header; 0 if no header; -1 if socket error
556  */
557  int CheckHead(std::string& tag, int& length, const int timeout_us = 0)
558  {
559  const int rvalue = CheckHead(this->prefix, timeout_us);
560 
561  if (rvalue == 1) {
562  tag = this->prefix.getTag();
563  length = this->prefix.getSize();
564  }
565 
566  return rvalue;
567  }
568 
569 
570  /**
571  * Receive data.
572  *
573  * \param buffer data
574  * \param length number of bytes
575  * \return 0 if OK; -1 if socket error
576  */
577  int GetFullData(void* buffer, int length)
578  {
579  try {
580 
581  read((char*) buffer, length);
582 
583  return 0;
584  }
585  catch (const JSocketException& error) {
586  return Throw(error, -1);
587  }
588  }
589 
590 
591  /**
592  * Receive string.
593  *
594  * \param buffer data
595  * \return 0 if OK; -1 if socket error
596  */
597  int GetFullString(std::string& buffer)
598  {
599  buffer.resize(this->prefix.getSize());
600 
601  return GetFullData((char*) buffer.data(), buffer.size());
602  }
603 
604 
605  /**
606  * Locate ControlHost client(s).
607  *
608  * \param host_name host name
609  * \param nick_name nick name
610  * \param answer list of host names
611  * \return 0 if OK; -1 if socket error
612  */
613  static int WhereIs(const std::string& host_name,
614  const std::string& nick_name,
615  std::string& answer)
616  {
617  try {
618 
619  using namespace std;
620 
621  JControlHost socket(host_name);
622 
623  socket.PutFullString(DISPTAG_WhereIs, nick_name);
624 
625  string tag;
626  int length;
627 
628  socket.WaitHead(tag, length);
629  socket.GetFullString(answer);
630 
631  return 0;
632  }
633  catch (const JSocketException& error) {
634  return Throw(error, -1);
635  }
636  }
637 
638 
639  /**
640  * Configure socket (factory reset).
641  *
642  * \return 0 if OK; -1 if socket error
643  */
644  int configure()
645  {
646  try {
647 
648  setTcpNoDelay (true);
649  setReuseAddress(true);
650  setKeepAlive (true);
651  setSendBufferSize (128*1024);
652  setReceiveBufferSize(128*1024);
653  setNonBlocking (false);
654 
655  return 0;
656  }
657  catch (const JSocketException& error) {
658  return Throw(error, -1);
659  }
660  }
661 
662 
663  private:
664  mutable JPrefix prefix;
665 
666  /**
667  */
668  JControlHost(const JControlHost&);
670  };
671 
672 
673  /**
674  * Match name.
675  */
677 }
678 
679 #endif
ControlHost prefix.
Definition: JPrefix.hh:31
void setReuseAddress(const bool on)
Set reuse address.
Definition: JSocket.hh:206
static const JTag DISPTAG_Subscribe("_Subscri")
Special ControlHost tags.
JSubscription_t getSubscription() const
Get subscription type.
Definition: JControlHost.hh:70
int Subscribe(const JSubscriptionList &subscription)
Subscribe to list of tags.
static const int DISPATCH_PORT
Default ControlHost port.
Definition: JHostname.hh:24
JNET::JSubscriptionList getSubscription(const JEventTable &event_table)
Convert event table to ControlHost subscription.
Definition: JEventTable.hh:125
Exceptions.
JSubscriptionAll(const JTag &tag)
Constructor.
int MyId(const std::string &nick_name)
Identify.
ControlHost class.
JSubscription_t
ControlHost subscription types.
Definition: JControlHost.hh:38
int write(const char *buffer, const int length)
Write data to socket.
static const std::string CHOO_VERSION
Definition: JControlHost.hh:32
const char * c_str() const
C-string.
Definition: JTag.hh:195
void setSendBufferSize(const int size)
Set send buffer size.
Definition: JSocket.hh:272
int Connected()
Send version.
Auxiliary base class for controling the throwing of exceptions.
Definition: JThrow.hh:25
static JTimeval min()
Get minimal time value.
Definition: JTimeval.hh:119
int PutFullString(const std::string &tag, const std::string &buffer)
Send string.
static const JTag DISPTAG_MyId("_MyId")
std::string toString() const
Convert subscription list to string.
int Subscribe(const JSubscription &subscription)
Subscribe to single tag.
int SendMeAlways()
Tell server to send messages forever.
static const JTag DISPTAG_WhereIs("_WhereIs")
Socket class.
Definition: JSocket.hh:42
char tag[TAGSIZE]
Definition: JTag.hh:247
Auxiliary data structure for hostname and port number.
Definition: JHostname.hh:30
std::string toString() const
Convert subscription to string.
Definition: JControlHost.hh:81
int PutFullData(const std::string &tag, const void *buffer, const int length)
Send data.
int getSize() const
Get size.
Definition: JPrefix.hh:63
Subscription list.
int WaitHead(std::string &tag, int &length)
Wait for header.
JControlHost(const JSocket &socket)
Constructor.
std::string hostname
Definition: JHostname.hh:154
static const JTag DISPTAG_Version("_Version")
Auxiliary class for time values.
Definition: JTimeval.hh:26
int CheckHead(JPrefix &prefix, JTimeval timeout=JTimeval::min())
Check for header, without waiting.
bool in_avail(JTimeval timeout=JTimeval::min()) const
Check availability of input.
Definition: JFile.hh:100
JSubscription(const JSubscription_t sub, const JTag &tag)
Constructor.
Definition: JControlHost.hh:58
JSubscriptionList()
Default constructor.
JControlHost(const std::string &server, const int port)
Constructor.
JControlHost(const int ip_number, const int port=DISPATCH_PORT)
Constructor.
JControlHost(const JHostname &server)
Constructor.
int GetFullString(std::string &buffer)
Receive string.
int shutdown()
Shut down socket.
Definition: JSocket.hh:94
JControlHost ControlHost
Match name.
int SendMeNext()
Tell server to send next message.
JTag_t getID() const
Get identifier.
Definition: JTag.hh:143
Auxiliary class for any subscription.
JSubscriptionList operator+(const JSubscription &first, const JSubscription &second)
Add operator.
JControlHost & operator=(const JControlHost &)
JSubscriptionList & add(const JSubscription &subscription)
Add subscription.
Exception for ControlHost.
Definition: JException.hh:432
void set(const JTag &tag, const int length)
Set prefix.
Definition: JPrefix.hh:87
Auxiliary class for all subscription.
Definition: JControlHost.hh:95
JSubscriptionAny(const JTag &tag)
Constructor.
static bool is_valid(const char c)
Check validity of subscription specifier.
const JTag & getTag() const
Get tag.
Definition: JTag.hh:82
static bool maybe_special(const JTag &tag)
Check special ControlHost tags.
void setReceiveBufferSize(const int size)
Set receive buffer size.
Definition: JSocket.hh:250
Blocking socket I/O.
int WaitHead(JPrefix &prefix)
Wait for header.
std::string toString() const
Convert tag to string.
Definition: JTag.hh:167
int configure()
Configure socket (factory reset).
int CheckHead(std::string &tag, int &length, const int timeout_us=0)
Check for header, without waiting.
static const JTag DISPTAG_Gime("_Gime")
ControlHost subscription.
Definition: JControlHost.hh:48
Exception for socket.
Definition: JException.hh:414
void connect(const int port)
Connect to port on local host.
Definition: JSocket.hh:384
Exception handling.
void setNonBlocking(const bool on)
Set non-blocking of I/O.
Definition: JSocket.hh:109
void setKeepAlive(const bool on)
Set keep alive of socket.
Definition: JSocket.hh:151
static int WhereIs(const std::string &host_name, const std::string &nick_name, std::string &answer)
Locate ControlHost client(s).
void setTcpNoDelay(const bool on)
Set TCP no-delay.
Definition: JSocket.hh:228
ControlHost tag.
Definition: JTag.hh:35
int read(char *buffer, const int length)
Read data from socket.
static const JTag DISPTAG_Always("_Always")
~JControlHost()
Destructor.
JSubscription_t subscription
Definition: JControlHost.hh:88
static void Throw(const bool option)
Enable/disable throw option.
Definition: JThrow.hh:37
int PutFullString(const JTag &tag, const std::string &buffer)
Send string.
int GetFullData(void *buffer, int length)
Receive data.
JControlHost()
Default constructor.
int PutFullData(const JTag &tag, const void *buffer, const int length)
Send data.