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
41namespace 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{
65public:
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
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();
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() */
163protected:
164 virtual void
166 {
167 Thread::run();
168 }
169
170private:
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{
188public:
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() */
282protected:
283 virtual void
285 {
286 Thread::run();
287 }
288
289private:
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 */
308FawkesNetworkClient::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 */
373FawkesNetworkClient::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 */
423void
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 */
490void
491FawkesNetworkClient::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 */
505void
506FawkesNetworkClient::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 */
523void
524FawkesNetworkClient::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. */
538void
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 */
575void
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 */
595void
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 */
613void
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 */
657void
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 */
675void
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
692void
693FawkesNetworkClient::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
703void
704FawkesNetworkClient::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
714void
715FawkesNetworkClient::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
732void
733FawkesNetworkClient::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
742void
743FawkesNetworkClient::connection_died()
744{
745 connection_died_recently = true;
746 notify_of_connection_dead();
747}
748
749void
750FawkesNetworkClient::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
763void
764FawkesNetworkClient::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 */
784void
785FawkesNetworkClient::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 */
813void
814FawkesNetworkClient::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 */
827bool
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 */
836bool
838{
839 return _has_id;
840}
841
842/** Get the client's ID.
843 * @return the ID
844 */
845unsigned 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 */
858const char *
860{
861 return host_;
862}
863
864} // end namespace fawkes
Thrown if the connection died during an operation.
Definition: exceptions.h:32
Base class for exceptions in Fawkes.
Definition: exception.h:36
Message handler for FawkesNetworkClient.
Fawkes network client receive thread.
Definition: client.cpp:187
virtual void run()
Stub to see name in backtrace for easier debugging.
Definition: client.cpp:284
virtual void once()
Execute an action exactly once.
Definition: client.cpp:248
virtual void loop()
Code to execute in the thread.
Definition: client.cpp:254
void recv()
Receive and process messages.
Definition: client.cpp:216
FawkesNetworkClientRecvThread(StreamSocket *s, FawkesNetworkClient *parent, Mutex *recv_mutex)
Constructor.
Definition: client.cpp:194
Fawkes network client send thread.
Definition: client.cpp:64
void enqueue(FawkesNetworkMessage *message)
Enqueue message to send and take ownership.
Definition: client.cpp:153
FawkesNetworkClientSendThread(StreamSocket *s, FawkesNetworkClient *parent)
Constructor.
Definition: client.cpp:70
void force_send()
Force sending of messages.
Definition: client.cpp:133
virtual void loop()
Code to execute in the thread.
Definition: client.cpp:105
virtual void once()
Execute an action exactly once.
Definition: client.cpp:99
virtual void run()
Stub to see name in backtrace for easier debugging.
Definition: client.cpp:165
~FawkesNetworkClientSendThread()
Destructor.
Definition: client.cpp:84
Simple Fawkes network client.
Definition: client.h:52
void wake(unsigned int component_id)
Wake a waiting thread.
Definition: client.cpp:814
void register_handler(FawkesNetworkClientHandler *handler, unsigned int component_id)
Register handler.
Definition: client.cpp:658
~FawkesNetworkClient()
Destructor.
Definition: client.cpp:402
const char * get_hostname() const
Get the client's hostname.
Definition: client.cpp:859
void wait(unsigned int component_id, unsigned int timeout_sec=15)
Wait for messages for component ID.
Definition: client.cpp:785
bool has_id() const
Check whether the client has an id.
Definition: client.cpp:837
void enqueue_and_wait(FawkesNetworkMessage *message, unsigned int timeout_sec=15)
Enqueue message to send and wait for answer.
Definition: client.cpp:614
void connect()
Connect to remote.
Definition: client.cpp:424
FawkesNetworkClient()
Constructor.
Definition: client.cpp:340
void disconnect()
Disconnect socket.
Definition: client.cpp:539
void deregister_handler(unsigned int component_id)
Deregister handler.
Definition: client.cpp:676
unsigned int id() const
Get the client's ID.
Definition: client.cpp:846
bool connected() const noexcept
Check if connection is alive.
Definition: client.cpp:828
void enqueue(FawkesNetworkMessage *message)
Enqueue message to send.
Definition: client.cpp:596
void interrupt_connect()
Interrupt connect().
Definition: client.cpp:576
A LockQueue of FawkesNetworkMessage to hold messages in inbound and outbound queues.
Definition: message_queue.h:33
Representation of a message that is sent over the network.
Definition: message.h:77
unsigned short int msgid() const
Get message type ID.
Definition: message.cpp:294
unsigned short int cid() const
Get component ID.
Definition: message.cpp:285
static void send(StreamSocket *s, FawkesNetworkMessageQueue *msgq)
Send messages.
Definition: transceiver.cpp:51
static void recv(StreamSocket *s, FawkesNetworkMessageQueue *msgq, unsigned int max_num_msgs=8)
Receive data.
Definition: transceiver.cpp:85
Client handler has already been registered.
Definition: client.h:44
The current system call has been interrupted (for instance by a signal).
Definition: system.h:39
void lock() const
Lock list.
Definition: lock_map.h:91
void unlock() const
Unlock list.
Definition: lock_map.h:109
void lock() const
Lock queue.
Definition: lock_queue.h:114
void unlock() const
Unlock list.
Definition: lock_queue.h:128
Mutex locking helper.
Definition: mutex_locker.h:34
void unlock()
Unlock the mutex.
Mutex mutual exclusion lock.
Definition: mutex.h:33
bool try_lock()
Tries to lock the mutex.
Definition: mutex.cpp:117
void lock()
Lock this mutex.
Definition: mutex.cpp:87
void unlock()
Unlock the mutex.
Definition: mutex.cpp:131
A NULL pointer was supplied where not allowed.
Definition: software.h:32
void unref()
Decrement reference count and conditionally delete this instance.
Definition: refcount.cpp:95
Socket exception.
Definition: socket.h:57
static const short POLL_RDHUP
Stream socket peer closed connection, or shut down writing half of connection.
Definition: socket.h:69
virtual void connect(const char *hostname, const unsigned short int port)
Connect socket.
Definition: socket.cpp:376
static const short POLL_HUP
Hang up.
Definition: socket.h:71
static const short POLL_IN
Data can be read.
Definition: socket.h:66
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
static const short POLL_ERR
Error condition.
Definition: socket.h:70
TCP stream socket over IP.
Definition: stream.h:32
Thread class encapsulation of pthreads.
Definition: thread.h:46
Mutex * loop_mutex
Mutex that is used to protect a call to loop().
Definition: thread.h:152
void start(bool wait=true)
Call this method to start the thread.
Definition: thread.cpp:499
void join()
Join the thread.
Definition: thread.cpp:597
void exit()
Exit the thread.
Definition: thread.cpp:582
void wakeup()
Wake up thread.
Definition: thread.cpp:995
void cancel()
Cancel a thread.
Definition: thread.cpp:646
virtual void run()
Code to execute in the thread.
Definition: thread.cpp:918
@ OPMODE_WAITFORWAKEUP
operate in wait-for-wakeup mode
Definition: thread.h:58
The current system call has timed out before completion.
Definition: system.h:46
Wait until a given condition holds.
void wait()
Wait for the condition forever.
void wake_all()
Wake up all waiting threads.
bool reltimed_wait(unsigned int sec, unsigned int nanosec)
Wait with relative timeout.
Fawkes library namespace.