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