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