Fawkes API  Fawkes Development Version
client.cpp
1 
2 /***************************************************************************
3  * client.cpp - Fawkes network client
4  *
5  * Created: Tue Nov 21 18:44:58 2006
6  * Copyright 2006-2009 Tim Niemueller [www.niemueller.de]
7  *
8  ****************************************************************************/
9 
10 /* This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version. A runtime exception applies to
14  * this software (see LICENSE.GPL_WRE file mentioned below for details).
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Library General Public License for more details.
20  *
21  * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
22  */
23 
24 #include <netcomm/fawkes/client.h>
25 #include <netcomm/fawkes/client_handler.h>
26 #include <netcomm/fawkes/message_queue.h>
27 #include <netcomm/fawkes/transceiver.h>
28 #include <netcomm/socket/stream.h>
29 #include <netcomm/utils/exceptions.h>
30 
31 #include <core/threading/thread.h>
32 #include <core/threading/mutex.h>
33 #include <core/threading/mutex_locker.h>
34 #include <core/threading/wait_condition.h>
35 #include <core/exceptions/system.h>
36 
37 #include <list>
38 #include <cstring>
39 #include <cstdlib>
40 #include <unistd.h>
41 
42 namespace fawkes {
43 
44 /** @class HandlerAlreadyRegisteredException netcomm/fawkes/client.h
45  * Client handler has already been registered.
46  * Only a single client handler can be registered per component. If you try
47  * to register a handler where there is already a handler this exception
48  * is thrown.
49  * @ingroup NetComm
50  */
51 
52 /** Costructor. */
54  : Exception("A handler for this component has already been registered")
55 {
56 }
57 
58 
59 /** Fawkes network client send thread.
60  * Spawned by the FawkesNetworkClient to handle outgoing traffic.
61  *
62  * @ingroup NetComm
63  * @author Tim Niemueller
64  */
66 {
67  public:
68 
69  /** Constructor.
70  * @param s client stream socket
71  * @param parent parent FawkesNetworkClient instance
72  */
74  : Thread("FawkesNetworkClientSendThread", Thread::OPMODE_WAITFORWAKEUP)
75  {
76  __s = s;
77  __parent = parent;
78  __outbound_mutex = new Mutex();
79  __outbound_msgqs[0] = new FawkesNetworkMessageQueue();
80  __outbound_msgqs[1] = new FawkesNetworkMessageQueue();
81  __outbound_active = 0;
82  __outbound_msgq = __outbound_msgqs[0];
83  __outbound_havemore = false;
84  }
85 
86  /** Destructor. */
88  {
89  for (unsigned int i = 0; i < 2; ++i) {
90  while ( ! __outbound_msgqs[i]->empty() ) {
91  FawkesNetworkMessage *m = __outbound_msgqs[i]->front();
92  m->unref();
93  __outbound_msgqs[i]->pop();
94  }
95  }
96  delete __outbound_msgqs[0];
97  delete __outbound_msgqs[1];
98  delete __outbound_mutex;
99  }
100 
101  virtual void once()
102  {
103  __parent->set_send_slave_alive();
104  }
105 
106  virtual void loop()
107  {
108  if ( ! __parent->connected() ) return;
109 
110  while ( __outbound_havemore ) {
111  __outbound_mutex->lock();
112  __outbound_havemore = false;
113  FawkesNetworkMessageQueue *q = __outbound_msgq;
114  __outbound_active = 1 - __outbound_active;
115  __outbound_msgq = __outbound_msgqs[__outbound_active];
116  __outbound_mutex->unlock();
117 
118  if ( ! q->empty() ) {
119  try {
121  } catch (ConnectionDiedException &e) {
122  __parent->connection_died();
123  exit();
124  }
125  }
126  }
127  }
128 
129  /** Force sending of messages.
130  * All messages are sent out immediately, if loop is not running already anyway.
131  */
132  void force_send()
133  {
134  if ( loop_mutex->try_lock() ) {
135  loop();
136  loop_mutex->unlock();
137  }
138  }
139 
140  /** Enqueue message to send and take ownership.
141  * This method takes ownership of the message. If you want to use the message
142  * after enqueing you must reference:
143  * @code
144  * message->ref();
145  * send_slave->enqueue(message);
146  * // message can now still be used
147  * @endcode
148  * Without extra referencing the message may not be used after enqueuing.
149  * @param message message to send
150  */
152  {
153  __outbound_mutex->lock();
154  __outbound_msgq->push(message);
155  __outbound_havemore = true;
156  __outbound_mutex->unlock();
157  wakeup();
158  }
159 
160  /** Stub to see name in backtrace for easier debugging. @see Thread::run() */
161  protected: virtual void run() { Thread::run(); }
162 
163  private:
164  StreamSocket *__s;
165  FawkesNetworkClient *__parent;
166  Mutex *__outbound_mutex;
167  unsigned int __outbound_active;
168  bool __outbound_havemore;
169  FawkesNetworkMessageQueue *__outbound_msgq;
170  FawkesNetworkMessageQueue *__outbound_msgqs[2];
171 
172 };
173 
174 
175 /** Fawkes network client receive thread.
176  * Spawned by the FawkesNetworkClient to handle incoming traffic.
177  *
178  * @ingroup NetComm
179  * @author Tim Niemueller
180  */
182 {
183  public:
184  /** Constructor.
185  * @param s client stream socket
186  * @param parent parent FawkesNetworkClient instance
187  * @param recv_mutex receive mutex, locked while messages are received
188  */
190  Mutex *recv_mutex)
191  : Thread("FawkesNetworkClientRecvThread")
192  {
193  __s = s;
194  __parent = parent;
195  __inbound_msgq = new FawkesNetworkMessageQueue();
196  __recv_mutex = recv_mutex;
197  }
198 
199  /** Destructor. */
201  {
202  while ( ! __inbound_msgq->empty() ) {
203  FawkesNetworkMessage *m = __inbound_msgq->front();
204  m->unref();
205  __inbound_msgq->pop();
206  }
207  delete __inbound_msgq;
208  }
209 
210  /** Receive and process messages. */
211  void recv()
212  {
213  std::list<unsigned int> wakeup_list;
214 
215  try {
216  FawkesNetworkTransceiver::recv(__s, __inbound_msgq);
217 
218  MutexLocker lock(__recv_mutex);
219 
220  __inbound_msgq->lock();
221  while ( ! __inbound_msgq->empty() ) {
222  FawkesNetworkMessage *m = __inbound_msgq->front();
223  wakeup_list.push_back(m->cid());
224  __parent->dispatch_message(m);
225  m->unref();
226  __inbound_msgq->pop();
227  }
228  __inbound_msgq->unlock();
229 
230  lock.unlock();
231 
232  wakeup_list.sort();
233  wakeup_list.unique();
234  for (std::list<unsigned int>::iterator i = wakeup_list.begin(); i != wakeup_list.end(); ++i) {
235  __parent->wake_handlers(*i);
236  }
237  } catch (ConnectionDiedException &e) {
238  throw;
239  }
240  }
241 
242  virtual void once()
243  {
244  __parent->set_recv_slave_alive();
245  }
246 
247  virtual void loop()
248  {
249  // just return if not connected
250  if (! __s ) return;
251 
252  short p = 0;
253  try {
254  p = __s->poll();
255  } catch (InterruptedException &e) {
256  return;
257  }
258 
259  if ( (p & Socket::POLL_ERR) ||
260  (p & Socket::POLL_HUP) ||
261  (p & Socket::POLL_RDHUP)) {
262  __parent->connection_died();
263  exit();
264  } else if ( p & Socket::POLL_IN ) {
265  // Data can be read
266  try {
267  recv();
268  } catch (ConnectionDiedException &e) {
269  __parent->connection_died();
270  exit();
271  }
272  }
273  }
274 
275  /** Stub to see name in backtrace for easier debugging. @see Thread::run() */
276  protected: virtual void run() { Thread::run(); }
277 
278  private:
279  StreamSocket *__s;
280  FawkesNetworkClient *__parent;
281  FawkesNetworkMessageQueue * __inbound_msgq;
282  Mutex *__recv_mutex;
283 };
284 
285 
286 /** @class FawkesNetworkClient netcomm/fawkes/client.h
287  * Simple Fawkes network client. Allows access to a remote instance via the
288  * network. Encapsulates all needed interaction with the network.
289  *
290  * @ingroup NetComm
291  * @author Tim Niemueller
292  */
293 
294 /** Constructor.
295  * @param host remote host to connect to.
296  * @param port port to connect to.
297  */
298 FawkesNetworkClient::FawkesNetworkClient(const char *host, unsigned short int port)
299 {
300  __host = strdup(host);
301  __port = port;
302  addr_ = NULL;
303  addr_len_ = 0;
304 
305  s = NULL;
306  __send_slave = NULL;
307  __recv_slave = NULL;
308 
309  connection_died_recently = false;
310  __send_slave_alive = false;
311  __recv_slave_alive = false;
312 
313  slave_status_mutex = new Mutex();
314 
315  _id = 0;
316  _has_id = false;
317 
318  __recv_mutex = new Mutex();
319  __recv_waitcond = new WaitCondition(__recv_mutex);
320  __connest_mutex = new Mutex();
321  __connest_waitcond = new WaitCondition(__connest_mutex);
322  __connest = false;
323  __connest_interrupted = false;
324 }
325 
326 
327 /** Constructor.
328  * Note, you cannot call the connect() without parameters the first time you
329  * establish an connection when using this ctor!
330  */
332 {
333  __host = NULL;
334  __port = 0;
335  addr_ = NULL;
336  addr_len_ = 0;
337 
338  s = NULL;
339  __send_slave = NULL;
340  __recv_slave = NULL;
341 
342  connection_died_recently = false;
343  __send_slave_alive = false;
344  __recv_slave_alive = false;
345 
346  slave_status_mutex = new Mutex();
347 
348  _id = 0;
349  _has_id = false;
350 
351  __recv_mutex = new Mutex();
352  __recv_waitcond = new WaitCondition(__recv_mutex);
353  __connest_mutex = new Mutex();
354  __connest_waitcond = new WaitCondition(__connest_mutex);
355  __connest = false;
356  __connest_interrupted = false;
357 }
358 
359 
360 /** Constructor.
361  * @param id id of the client.
362  * @param host remote host to connect to.
363  * @param port port to connect to.
364  */
365 FawkesNetworkClient::FawkesNetworkClient(unsigned int id, const char *host,
366  unsigned short int port)
367 {
368  __host = strdup(host);
369  __port = port;
370  addr_ = NULL;
371  addr_len_ = 0;
372 
373  s = NULL;
374  __send_slave = NULL;
375  __recv_slave = NULL;
376 
377  connection_died_recently = false;
378  __send_slave_alive = false;
379  __recv_slave_alive = false;
380 
381  slave_status_mutex = new Mutex();
382 
383  _id = id;
384  _has_id = true;
385 
386  __recv_mutex = new Mutex();
387  __recv_waitcond = new WaitCondition(__recv_mutex);
388  __connest_mutex = new Mutex();
389  __connest_waitcond = new WaitCondition(__connest_mutex);
390  __connest = false;
391  __connest_interrupted = false;
392 }
393 
394 
395 /** Destructor. */
397 {
398  disconnect();
399 
400  delete s;
401  if (__host) free(__host);
402  if (addr_) free(addr_);
403  delete slave_status_mutex;
404 
405  delete __connest_waitcond;
406  delete __connest_mutex;
407  delete __recv_waitcond;
408  delete __recv_mutex;
409 }
410 
411 
412 /** Connect to remote.
413  * @exception SocketException thrown by Socket::connect()
414  * @exception NullPointerException thrown if hostname has not been set
415  */
416 void
418 {
419  if ( __host == NULL && addr_ == NULL) {
420  throw NullPointerException("Neither hostname nor sockaddr set. Cannot connect.");
421  }
422 
423  if ( s != NULL ) {
424  disconnect();
425  }
426 
427 
428  connection_died_recently = false;
429 
430  try {
431  s = new StreamSocket();
432  if (addr_) {
433  s->connect(addr_, addr_len_);
434  } else if (__host) {
435  s->connect(__host, __port);
436  } else {
437  throw NullPointerException("Nothing to connect to!?");
438  }
439  __send_slave = new FawkesNetworkClientSendThread(s, this);
440  __send_slave->start();
441  __recv_slave = new FawkesNetworkClientRecvThread(s, this, __recv_mutex);
442  __recv_slave->start();
443  } catch (SocketException &e) {
444  connection_died_recently = true;
445  if ( __send_slave ) {
446  __send_slave->cancel();
447  __send_slave->join();
448  delete __send_slave;
449  __send_slave = NULL;
450  }
451  if ( __recv_slave ) {
452  __recv_slave->cancel();
453  __recv_slave->join();
454  delete __recv_slave;
455  __recv_slave = NULL;
456  }
457  __send_slave_alive = false;
458  __recv_slave_alive = false;
459  delete s;
460  s = NULL;
461  throw;
462  }
463 
464  __connest_mutex->lock();
465  while ( ! __connest && ! __connest_interrupted ) {
466  __connest_waitcond->wait();
467  }
468  bool interrupted = __connest_interrupted;
469  __connest_interrupted = false;
470  __connest_mutex->unlock();
471  if ( interrupted ) {
472  throw InterruptedException("FawkesNetworkClient::connect()");
473  }
474 
475  notify_of_connection_established();
476 }
477 
478 
479 /** Connect to new ip and port, and set hostname.
480  * @param host remote host name
481  * @param port new port to connect to
482  * @see connect() Look there for more documentation and notes about possible
483  * exceptions.
484  */
485 void
486 FawkesNetworkClient::connect(const char *host, unsigned short int port)
487 {
488  if (__host) free(__host);
489  __host = strdup(host);
490  __port = port;
491  connect();
492 }
493 
494 /** Connect to specific endpoint.
495  * @param hostname hostname, informational only and not used for connecting
496  * @param addr sockaddr structure of specific endpoint to connect to
497  * @param addr_len length of @p addr
498  */
499 void
500 FawkesNetworkClient::connect(const char *hostname, const struct sockaddr *addr, socklen_t addr_len)
501 {
502  if (__host) free(__host);
503  if (addr_) free(addr_);
504  addr_ = (struct sockaddr *)malloc(addr_len);
505  addr_len_ = addr_len;
506  memcpy(addr_, addr, addr_len);
507  __host = strdup(hostname);
508  connect();
509 }
510 
511 /** Connect to specific endpoint.
512  * @param hostname hostname, informational only and not used for connecting
513  * @param addr sockaddr_storage structure of specific endpoint to connect to
514  */
515 void
516 FawkesNetworkClient::connect(const char *hostname, const struct sockaddr_storage &addr)
517 {
518  if (__host) free(__host);
519  if (addr_) free(addr_);
520  addr_ = (struct sockaddr *)malloc(sizeof(sockaddr_storage));
521  addr_len_ = sizeof(sockaddr_storage);
522  memcpy(addr_, &addr, addr_len_);
523  __host = strdup(hostname);
524  connect();
525 }
526 
527 /** Disconnect socket. */
528 void
530 {
531  if ( s == NULL ) return;
532 
533  if ( __send_slave_alive ) {
534  if ( ! connection_died_recently ) {
535  __send_slave->force_send();
536  // Give other side some time to read the messages just sent
537  usleep(100000);
538  }
539  __send_slave->cancel();
540  __send_slave->join();
541  delete __send_slave;
542  __send_slave = NULL;
543  }
544  if ( __recv_slave_alive ) {
545  __recv_slave->cancel();
546  __recv_slave->join();
547  delete __recv_slave;
548  __recv_slave = NULL;
549  }
550  __send_slave_alive = false;
551  __recv_slave_alive = false;
552  delete s;
553  s = NULL;
554 
555  if (! connection_died_recently) {
556  connection_died();
557  }
558 }
559 
560 
561 /** Interrupt connect().
562  * This is for example handy to interrupt in connection_died() before a
563  * connection_established() event has been received.
564  */
565 void
567 {
568  __connest_mutex->lock();
569  __connest_interrupted = true;
570  __connest_waitcond->wake_all();
571  __connest_mutex->unlock();
572 }
573 
574 
575 /** Enqueue message to send.
576  * This method takes ownership of the message. If you want to use the message
577  * after enqueing you must reference:
578  * @code
579  * message->ref();
580  * fawkes_network_client->enqueue(message);
581  * // message can now still be used
582  * @endcode
583  * Without extra referencing the message may not be used after enqueuing.
584  * @param message message to send
585  */
586 void
588 {
589  if (__send_slave) __send_slave->enqueue(message);
590 }
591 
592 
593 /** Enqueue message to send and wait for answer. It is guaranteed that an
594  * answer cannot be missed. However, if the component sends another message
595  * (which is not the answer to the query) this will also trigger the wait
596  * condition to be woken up. The component ID to wait for is taken from the
597  * message.
598  * This message also calls unref() on the message. If you want to use it
599  * after enqueuing make sure you ref() before calling this method.
600  * @param message message to send
601  * @param timeout_sec timeout for the waiting operation in seconds, 0 to wait
602  * forever (warning, this may result in a deadlock!)
603  */
604 void
606  unsigned int timeout_sec)
607 {
608  if (__send_slave && __recv_slave) {
609  __recv_mutex->lock();
610  if ( __recv_received.find(message->cid()) != __recv_received.end()) {
611  __recv_mutex->unlock();
612  unsigned int cid = message->cid();
613  throw Exception("There is already a thread waiting for messages of "
614  "component id %u", cid);
615  }
616  __send_slave->enqueue(message);
617  unsigned int cid = message->cid();
618  __recv_received[cid] = false;
619  while (!__recv_received[cid] && ! connection_died_recently) {
620  if (!__recv_waitcond->reltimed_wait(timeout_sec, 0)) {
621  __recv_received.erase(cid);
622  __recv_mutex->unlock();
623  throw TimeoutException("Timeout reached while waiting for incoming message "
624  "(outgoing was %u:%u)", message->cid(), message->msgid());
625  }
626  }
627  __recv_received.erase(cid);
628  __recv_mutex->unlock();
629  } else {
630  unsigned int cid = message->cid();
631  unsigned int msgid = message->msgid();
632  throw Exception("Cannot enqueue given message %u:%u, sender or "
633  "receiver missing", cid, msgid);
634  }
635 }
636 
637 
638 /** Register handler.
639  * Handlers are used to handle incoming packets. There may only be one handler per
640  * component!
641  * Cannot be called while processing a message.
642  * @param handler handler to register
643  * @param component_id component ID to register the handler for.
644  */
645 void
647  unsigned int component_id)
648 {
649  handlers.lock();
650  if ( handlers.find(component_id) != handlers.end() ) {
651  handlers.unlock();
653  } else {
654  handlers[component_id] = handler;
655  }
656  handlers.unlock();
657 }
658 
659 
660 /** Deregister handler.
661  * Cannot be called while processing a message.
662  * @param component_id component ID
663  */
664 void
665 FawkesNetworkClient::deregister_handler(unsigned int component_id)
666 {
667  handlers.lock();
668  if ( handlers.find(component_id) != handlers.end() ) {
669  handlers[component_id]->deregistered(_id);
670  handlers.erase(component_id);
671  }
672  handlers.unlock();
673  __recv_mutex->lock();
674  if (__recv_received.find(component_id) != __recv_received.end()) {
675  __recv_received[component_id] = true;
676  __recv_waitcond->wake_all();
677  }
678  __recv_mutex->unlock();
679 }
680 
681 
682 void
683 FawkesNetworkClient::dispatch_message(FawkesNetworkMessage *m)
684 {
685  unsigned int cid = m->cid();
686  handlers.lock();
687  if (handlers.find(cid) != handlers.end()) {
688  handlers[cid]->inbound_received(m, _id);
689  }
690  handlers.unlock();
691 }
692 
693 
694 void
695 FawkesNetworkClient::wake_handlers(unsigned int cid)
696 {
697  __recv_mutex->lock();
698  if (__recv_received.find(cid) != __recv_received.end()) {
699  __recv_received[cid] = true;
700  }
701  __recv_waitcond->wake_all();
702  __recv_mutex->unlock();
703 }
704 
705 void
706 FawkesNetworkClient::notify_of_connection_dead()
707 {
708  __connest_mutex->lock();
709  __connest = false;
710  __connest_mutex->unlock();
711 
712  handlers.lock();
713  for ( HandlerMap::iterator i = handlers.begin(); i != handlers.end(); ++i ) {
714  i->second->connection_died(_id);
715  }
716  handlers.unlock();
717 
718  __recv_mutex->lock();
719  __recv_waitcond->wake_all();
720  __recv_mutex->unlock();
721 }
722 
723 void
724 FawkesNetworkClient::notify_of_connection_established()
725 {
726  handlers.lock();
727  for ( HandlerMap::iterator i = handlers.begin(); i != handlers.end(); ++i ) {
728  i->second->connection_established(_id);
729  }
730  handlers.unlock();
731 }
732 
733 
734 void
735 FawkesNetworkClient::connection_died()
736 {
737  connection_died_recently = true;
738  notify_of_connection_dead();
739 }
740 
741 
742 void
743 FawkesNetworkClient::set_send_slave_alive()
744 {
745  slave_status_mutex->lock();
746  __send_slave_alive = true;
747  if ( __send_slave_alive && __recv_slave_alive ) {
748  __connest_mutex->lock();
749  __connest = true;
750  __connest_waitcond->wake_all();
751  __connest_mutex->unlock();
752  }
753  slave_status_mutex->unlock();
754 }
755 
756 
757 void
758 FawkesNetworkClient::set_recv_slave_alive()
759 {
760  slave_status_mutex->lock();
761  __recv_slave_alive = true;
762  if ( __send_slave_alive && __recv_slave_alive ) {
763  __connest_mutex->lock();
764  __connest = true;
765  __connest_waitcond->wake_all();
766  __connest_mutex->unlock();
767  }
768  slave_status_mutex->unlock();
769 }
770 
771 
772 /** Wait for messages for component ID.
773  * This will wait for messages of the given component ID to arrive. The calling
774  * thread is blocked until messages are available.
775  * @param component_id component ID to monitor
776  * @param timeout_sec timeout for the waiting operation in seconds, 0 to wait
777  * forever (warning, this may result in a deadlock!)
778  */
779 void
780 FawkesNetworkClient::wait(unsigned int component_id, unsigned int timeout_sec)
781 {
782  __recv_mutex->lock();
783  if ( __recv_received.find(component_id) != __recv_received.end()) {
784  __recv_mutex->unlock();
785  throw Exception("There is already a thread waiting for messages of "
786  "component id %u", component_id);
787  }
788  __recv_received[component_id] = false;
789  while (! __recv_received[component_id] && ! connection_died_recently) {
790  if (!__recv_waitcond->reltimed_wait(timeout_sec, 0)) {
791  __recv_received.erase(component_id);
792  __recv_mutex->unlock();
793  throw TimeoutException("Timeout reached while waiting for incoming message "
794  "(component %u)", component_id);
795  }
796  }
797  __recv_received.erase(component_id);
798  __recv_mutex->unlock();
799 }
800 
801 
802 /** Wake a waiting thread.
803  * This will wakeup all threads currently waiting for the specified component ID.
804  * This can be helpful to wake a sleeping thread if you received a signal.
805  * @param component_id component ID for threads to wake up
806  */
807 void
808 FawkesNetworkClient::wake(unsigned int component_id)
809 {
810  __recv_mutex->lock();
811  if ( __recv_received.find(component_id) != __recv_received.end()) {
812  __recv_received[component_id] = true;
813  }
814  __recv_waitcond->wake_all();
815  __recv_mutex->unlock();
816 }
817 
818 
819 /** Check if connection is alive.
820  * @return true if connection is alive at the moment, false otherwise
821  */
822 bool
824 {
825  return (! connection_died_recently && (s != NULL));
826 }
827 
828 
829 /** Check whether the client has an id.
830  * @return true if client has an ID
831  */
832 bool
834 {
835  return _has_id;
836 }
837 
838 
839 /** Get the client's ID.
840  * @return the ID
841  */
842 unsigned int
844 {
845  if ( !_has_id ) {
846  throw Exception("Trying to get the ID of a client that has no ID");
847  }
848 
849  return _id;
850 }
851 
852 /** Get the client's hostname
853  * @return hostname or NULL
854  */
855 const char *
857 {
858  return __host;
859 }
860 
861 } // end namespace fawkes
~FawkesNetworkClient()
Destructor.
Definition: client.cpp:396
Message handler for FawkesNetworkClient.
static const short POLL_ERR
Error condition.
Definition: socket.h:73
void wake(unsigned int component_id)
Wake a waiting thread.
Definition: client.cpp:808
void interrupt_connect()
Interrupt connect().
Definition: client.cpp:566
Wait until a given condition holds.
void enqueue(FawkesNetworkMessage *message)
Enqueue message to send and take ownership.
Definition: client.cpp:151
A LockQueue of FawkesNetworkMessage to hold messages in inbound and outbound queues.
Definition: message_queue.h:33
void enqueue_and_wait(FawkesNetworkMessage *message, unsigned int timeout_sec=15)
Enqueue message to send and wait for answer.
Definition: client.cpp:605
Simple Fawkes network client.
Definition: client.h:52
void unref()
Decrement reference count and conditionally delete this instance.
Definition: refcount.cpp:99
void unlock() const
Unlock list.
Definition: lock_queue.h:131
unsigned short int cid() const
Get component ID.
Definition: message.cpp:291
Fawkes library namespace.
static void recv(StreamSocket *s, FawkesNetworkMessageQueue *msgq, unsigned int max_num_msgs=8)
Receive data.
Definition: transceiver.cpp:86
virtual void run()
Stub to see name in backtrace for easier debugging.
Definition: client.cpp:276
Exception()
Constructor for subclasses.
Definition: exception.cpp:257
virtual void run()
Code to execute in the thread.
Definition: thread.cpp:939
Mutex locking helper.
Definition: mutex_locker.h:33
void disconnect()
Disconnect socket.
Definition: client.cpp:529
void register_handler(FawkesNetworkClientHandler *handler, unsigned int component_id)
Register handler.
Definition: client.cpp:646
static const short POLL_IN
Data can be read.
Definition: socket.h:69
void enqueue(FawkesNetworkMessage *message)
Enqueue message to send.
Definition: client.cpp:587
void wait(unsigned int component_id, unsigned int timeout_sec=15)
Wait for messages for component ID.
Definition: client.cpp:780
Representation of a message that is sent over the network.
Definition: message.h:75
void connect()
Connect to remote.
Definition: client.cpp:417
The current system call has timed out before completion.
Definition: system.h:46
bool has_id() const
Check whether the client has an id.
Definition: client.cpp:833
Fawkes network client send thread.
Definition: client.cpp:65
unsigned int id() const
Get the client&#39;s ID.
Definition: client.cpp:843
A NULL pointer was supplied where not allowed.
Definition: software.h:34
Thread class encapsulation of pthreads.
Definition: thread.h:42
~FawkesNetworkClientRecvThread()
Destructor.
Definition: client.cpp:200
virtual void loop()
Code to execute in the thread.
Definition: client.cpp:106
TCP stream socket over IP.
Definition: stream.h:31
void unlock()
Unlock the mutex.
virtual void loop()
Code to execute in the thread.
Definition: client.cpp:247
Base class for exceptions in Fawkes.
Definition: exception.h:36
void recv()
Receive and process messages.
Definition: client.cpp:211
virtual void once()
Execute an action exactly once.
Definition: client.cpp:242
The current system call has been interrupted (for instance by a signal).
Definition: system.h:39
FawkesNetworkClient()
Constructor.
Definition: client.cpp:331
Thrown if the connection died during an operation.
Definition: exceptions.h:31
static const short POLL_RDHUP
Stream socket peer closed connection, or shut down writing half of connection.
Definition: socket.h:72
FawkesNetworkClientRecvThread(StreamSocket *s, FawkesNetworkClient *parent, Mutex *recv_mutex)
Constructor.
Definition: client.cpp:189
~FawkesNetworkClientSendThread()
Destructor.
Definition: client.cpp:87
unsigned short int msgid() const
Get message type ID.
Definition: message.cpp:301
void deregister_handler(unsigned int component_id)
Deregister handler.
Definition: client.cpp:665
static void send(StreamSocket *s, FawkesNetworkMessageQueue *msgq)
Send messages.
Definition: transceiver.cpp:51
static const short POLL_HUP
Hang up.
Definition: socket.h:74
const char * get_hostname() const
Get the client&#39;s hostname.
Definition: client.cpp:856
virtual void run()
Stub to see name in backtrace for easier debugging.
Definition: client.cpp:161
bool connected() const
Check if connection is alive.
Definition: client.cpp:823
Mutex mutual exclusion lock.
Definition: mutex.h:32
FawkesNetworkClientSendThread(StreamSocket *s, FawkesNetworkClient *parent)
Constructor.
Definition: client.cpp:73
Fawkes network client receive thread.
Definition: client.cpp:181
void force_send()
Force sending of messages.
Definition: client.cpp:132
Socket exception.
Definition: socket.h:58
virtual void once()
Execute an action exactly once.
Definition: client.cpp:101