Fawkes API Fawkes Development Version
message.cpp
1
2/***************************************************************************
3 * message.cpp - BlackBoard message
4 *
5 * Created: Tue Oct 17 00:52:34 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/software.h>
25#include <core/threading/mutex.h>
26#include <core/threading/thread.h>
27#include <interface/interface.h>
28#include <interface/message.h>
29#include <utils/time/time.h>
30
31#include <cstdlib>
32#include <cstring>
33#include <unistd.h>
34
35namespace fawkes {
36
37/** @class Message <interface/message.h>
38 * Base class for all messages passed through interfaces in Fawkes BlackBoard.
39 * Do not use directly, but instead use the interface generator to generate
40 * an interface with accompanying messages.
41 *
42 * The sender ID of the message is automatically determined and is the instance
43 * serial of the interface where the message was enqueued using
44 * Interface::msgq_enqueue().
45 *
46 * @author Tim Niemueller
47 */
48
49/** @var Message::data_ptr
50 * Pointer to memory that contains local data. This memory has to be allocated
51 * by deriving classes with the approppriate size!
52 */
53
54/** @var Message::data_size
55 * Size of memory needed to hold all data. This has to be set by deriving classes
56 * to the appropriate value.
57 */
58
59/** Constructor.
60 * @param type string representation of the message type
61 */
62Message::Message(const char *type)
63{
64 fieldinfo_list_ = NULL;
65
66 message_id_ = 0;
67 hops_ = 0;
68 enqueued_ = false;
69 num_fields_ = 0;
70 data_ptr = NULL;
71 data_ts = NULL;
72 _type = strdup(type);
73 time_enqueued_ = new Time();
74
75 _transmit_via_iface = NULL;
76 sender_interface_instance_serial = 0;
77 recipient_interface_mem_serial = 0;
78
79 std::string sender_name = Thread::current_thread_name();
80 if (sender_name != "") {
81 _sender_thread_name = strdup(sender_name.c_str());
82 } else {
83 _sender_thread_name = strdup("Unknown");
84 }
85}
86
87/** Copy constructor.
88 * @param mesg Message to copy.
89 */
91{
92 message_id_ = 0;
93 hops_ = mesg.hops_;
94 enqueued_ = false;
95 num_fields_ = mesg.num_fields_;
96 data_size = mesg.data_size;
97 data_ptr = malloc(data_size);
99 _sender_id = mesg.sender_id();
100 _source_id = mesg.source_id();
101 _sender_thread_name = strdup(mesg.sender_thread_name());
102 _type = strdup(mesg._type);
103 time_enqueued_ = new Time(mesg.time_enqueued_);
104 fieldinfo_list_ = NULL;
105
106 _transmit_via_iface = NULL;
107 sender_interface_instance_serial = 0;
108 recipient_interface_mem_serial = 0;
109
110 memcpy(data_ptr, mesg.data_ptr, data_size);
111
112 interface_fieldinfo_t * info_src = mesg.fieldinfo_list_;
113 interface_fieldinfo_t **info_dest = &fieldinfo_list_;
114 while (info_src) {
115 interface_fieldinfo_t *new_info =
117 memcpy(new_info, info_src, sizeof(interface_fieldinfo_t));
118 *info_dest = new_info;
119
120 info_dest = &((*info_dest)->next);
121 info_src = info_src->next;
122 }
123}
124
125/** Copy constructor.
126 * @param mesg Message to copy.
127 */
129{
130 message_id_ = 0;
131 hops_ = mesg->hops_;
132 enqueued_ = false;
133 num_fields_ = mesg->num_fields_;
134 data_size = mesg->data_size;
135 data_ptr = malloc(data_size);
137 _sender_id = mesg->sender_id();
138 _source_id = mesg->source_id();
139 _sender_thread_name = strdup(mesg->sender_thread_name());
140 _type = strdup(mesg->_type);
141 _transmit_via_iface = NULL;
142 sender_interface_instance_serial = 0;
143 recipient_interface_mem_serial = 0;
144 time_enqueued_ = new Time(mesg->time_enqueued_);
145 fieldinfo_list_ = NULL;
146
147 memcpy(data_ptr, mesg->data_ptr, data_size);
148
149 interface_fieldinfo_t * info_src = mesg->fieldinfo_list_;
150 interface_fieldinfo_t **info_dest = &fieldinfo_list_;
151 while (info_src) {
152 interface_fieldinfo_t *new_info =
154 memcpy(new_info, info_src, sizeof(interface_fieldinfo_t));
155 *info_dest = new_info;
156
157 info_dest = &((*info_dest)->next);
158 info_src = info_src->next;
159 }
160}
161
162/** Destructor. */
164{
165 free(_sender_thread_name);
166 free(_type);
167 delete time_enqueued_;
168
169 interface_fieldinfo_t *infol = fieldinfo_list_;
170 while (infol) {
171 fieldinfo_list_ = fieldinfo_list_->next;
172 free(infol);
173 infol = fieldinfo_list_;
174 }
175}
176
177/** Get message ID.
178 * @return message ID.
179 */
180unsigned int
182{
183 return message_id_;
184}
185
186/** Get number of hops.
187 * @return number of hops
188 */
189unsigned int
191{
192 return hops_;
193}
194
195/** Set message ID.
196 * @param message_id message ID
197 */
198void
199Message::set_id(unsigned int message_id)
200{
201 message_id_ = message_id;
202}
203
204/** Set sender ID.
205 * @param sender_id sender ID
206 */
207void
209{
210 _sender_id = sender_id;
211}
212
213/** Set source ID. The source is the original interface where the message comes
214 * from.
215 * @param source_id source ID
216 */
217void
219{
220 _source_id = source_id;
221}
222
223/** Set number of hops.
224 * @param hops number of hops
225 */
226void
227Message::set_hops(unsigned int hops)
228{
229 hops_ = hops;
230}
231
232/** Mark message as being enqueued. */
233void
235{
236 time_enqueued_->stamp();
237 long sec = 0, usec = 0;
238 time_enqueued_->get_timestamp(sec, usec);
239 data_ts->timestamp_sec = sec;
240 data_ts->timestamp_usec = usec;
241
242 enqueued_ = true;
243}
244
245/** Check is message has been enqueued.
246 * @return true if the message has already been enqueued, false otherwise
247 */
248bool
250{
251 return enqueued_;
252}
253
254/** Get time when message was enqueued.
255 * Note that this assumes synchronized clocks between sender and receiver.
256 * Problematic in this regard are remote network connections. For one the
257 * system times of the two system can diverge, for the other the clock on
258 * only one of the systems may be simulated.
259 * @return timestamp when message was enqueued.
260 */
261const Time *
263{
264 return time_enqueued_;
265}
266
267/** Get recipient memory serial.
268 * @return Interface memory serial of the recipient interface.
269 */
270unsigned int
272{
273 return recipient_interface_mem_serial;
274}
275
276/** Get pointer to data.
277 * Avoid usage.
278 * @return pointer to internal data
279 */
280const void *
282{
283 return data_ptr;
284}
285
286/** Get size of data.
287 * @return size in bytes of data
288 */
289unsigned int
291{
292 return data_size;
293}
294
295/** Set from raw data chunk.
296 * This sets the internal storage to the given chunk. The chunk must be exactly
297 * of the size returned by datasize().
298 * @param chunk chunk containing the data exactly of the size returned by datasize()
299 */
300void
301Message::set_from_chunk(const void *chunk)
302{
303 memcpy(data_ptr, chunk, data_size);
305}
306
307/** Assign this message to given message.
308 * Data is copied over from message if data sizes are the same.
309 * @param m Message to copy
310 * @return reference to current instance
311 */
312Message &
314{
315 if (data_size == m.data_size) {
316 memcpy(data_ptr, m.data_ptr, data_size);
318 }
319
320 return *this;
321}
322
323/** Get sender of message.
324 * @return name of sending thread
325 */
326const char *
328{
329 return _sender_thread_name;
330}
331
332/** Get ID of the immediate sender, not necessarily the creator of the message.
333 * @return unique ID of the immediate sender
334 */
335Uuid
337{
338 return _sender_id;
339}
340
341/** Get ID of the original source of the message. This differs from the sender
342 * ID if the message is relayed.
343 * @return unique ID of the source
344 */
345Uuid
347{
348 return _source_id;
349}
350
351/** Set transmitting interface.
352 * Called by Message Manager
353 * @param iface transmitting interface
354 * @param proxy if set to true, the transmitting interface is only a proxy, do
355 * not modify the sender
356 */
357void
358Message::set_interface(Interface *iface, bool proxy)
359{
360 _transmit_via_iface = iface;
361 _sender_id = iface->serial();
362 if (!proxy) {
363 _source_id = iface->serial();
364 }
365 recipient_interface_mem_serial = iface->mem_serial();
366}
367
368/** Get transmitting interface.
369 * @return transmitting interface, or NULL if message has not been enqueued, yet.
370 */
371Interface *
373{
374 return _transmit_via_iface;
375}
376
377/** Get message type.
378 * @return textual representation of the interface type
379 */
380const char *
382{
383 return _type;
384}
385
386/** Get iterator over all fields of this interface instance.
387 * @return field iterator pointing to the very first value
388 */
391{
392 return InterfaceFieldIterator(_transmit_via_iface, fieldinfo_list_);
393}
394
395/** Invalid iterator.
396 * @return invalid iterator reprensenting the end.
397 */
400{
401 return InterfaceFieldIterator();
402}
403
404/** Get the number of fields in the message.
405 * @return the number of fields
406 */
407unsigned int
409{
410 return num_fields_;
411}
412
413/** Clone this message.
414 * Shall be implemented by every sub-class to return a message of proper type.
415 * @return new message cloned from this instance
416 */
417Message *
419{
420 return new Message(this);
421}
422
423/** Add an entry to the info list.
424 * Never use directly, use the interface generator instead. The info list
425 * is used for introspection purposes to allow for iterating over all fields
426 * of an interface.
427 * @param type field type
428 * @param name name of the field, this is referenced, not copied
429 * @param length length of the field
430 * @param value pointer to the value in the data struct
431 * @param enumtype in case the type parameter is enum the name of the enum type
432 * @param enum_map enum value map
433 */
434void
436 const char * name,
437 size_t length,
438 void * value,
439 const char * enumtype,
440 const interface_enum_map_t *enum_map)
441{
442 interface_fieldinfo_t *infol = fieldinfo_list_;
444
445 newinfo->type = type;
446 newinfo->enumtype = enumtype;
447 newinfo->name = name;
448 newinfo->length = length;
449 newinfo->value = value;
450 newinfo->enum_map = enum_map;
451 newinfo->next = NULL;
452
453 if (infol == NULL) {
454 // first entry
455 fieldinfo_list_ = newinfo;
456 } else {
457 // append to list
458 while (infol->next != NULL) {
459 infol = infol->next;
460 }
461 infol->next = newinfo;
462 }
463
464 ++num_fields_;
465}
466
467} // end namespace fawkes
Interface field iterator.
Base class for all Fawkes BlackBoard interfaces.
Definition: interface.h:80
unsigned int mem_serial() const
Get memory serial of interface.
Definition: interface.cpp:704
Uuid serial() const
Get instance serial of interface.
Definition: interface.cpp:695
Base class for all messages passed through interfaces in Fawkes BlackBoard.
Definition: message.h:44
InterfaceFieldIterator fields()
Get iterator over all fields of this interface instance.
Definition: message.cpp:390
unsigned int recipient() const
Get recipient memory serial.
Definition: message.cpp:271
virtual ~Message()
Destructor.
Definition: message.cpp:163
const char * type() const
Get message type.
Definition: message.cpp:381
const void * datachunk() const
Get pointer to data.
Definition: message.cpp:281
void mark_enqueued()
Mark message as being enqueued.
Definition: message.cpp:234
unsigned int datasize() const
Get size of data.
Definition: message.cpp:290
Message(const char *type)
Constructor.
Definition: message.cpp:62
bool enqueued() const
Check is message has been enqueued.
Definition: message.cpp:249
Uuid source_id() const
Get ID of the original source of the message.
Definition: message.cpp:346
Interface * interface() const
Get transmitting interface.
Definition: message.cpp:372
void set_source_id(const Uuid &id)
Set source ID.
Definition: message.cpp:218
void set_from_chunk(const void *chunk)
Set from raw data chunk.
Definition: message.cpp:301
void set_id(unsigned int message_id)
Set message ID.
Definition: message.cpp:199
void add_fieldinfo(interface_fieldtype_t type, const char *name, size_t length, void *value, const char *enumtype=0, const interface_enum_map_t *enum_map=0)
Add an entry to the info list.
Definition: message.cpp:435
void * data_ptr
Pointer to memory that contains local data.
Definition: message.h:146
message_data_ts_t * data_ts
data timestamp aliasing pointer
Definition: message.h:156
const Time * time_enqueued() const
Get time when message was enqueued.
Definition: message.cpp:262
unsigned int num_fields() const
Get the number of fields in the message.
Definition: message.cpp:408
Uuid sender_id() const
Get ID of the immediate sender, not necessarily the creator of the message.
Definition: message.cpp:336
void set_hops(unsigned int hops)
Set number of hops.
Definition: message.cpp:227
Message & operator=(const Message &m)
Assign this message to given message.
Definition: message.cpp:313
virtual Message * clone() const
Clone this message.
Definition: message.cpp:418
InterfaceFieldIterator fields_end()
Invalid iterator.
Definition: message.cpp:399
const char * sender_thread_name() const
Get sender of message.
Definition: message.cpp:327
unsigned int id() const
Get message ID.
Definition: message.cpp:181
unsigned int hops() const
Get number of hops.
Definition: message.cpp:190
void set_sender_id(const Uuid &id)
Set sender ID.
Definition: message.cpp:208
unsigned int data_size
Size of memory needed to hold all data.
Definition: message.h:147
static std::string current_thread_name()
Get the name of the current thread.
Definition: thread.cpp:1318
A class for handling time.
Definition: time.h:93
void get_timestamp(long &sec, long &usec) const
Get time stamp.
Definition: time.h:137
Time & stamp()
Set this time to the current time.
Definition: time.cpp:704
void set_time(const timeval *tv)
Sets the time.
Definition: time.cpp:246
A convenience class for universally unique identifiers (UUIDs).
Definition: uuid.h:29
Fawkes library namespace.
std::map< int, std::string > interface_enum_map_t
Map of enum integer to string values.
Definition: types.h:54
interface_fieldtype_t
Interface field type.
Definition: types.h:36
Timestamp data, must be present and first entries for each interface data structs!...
Definition: message.h:152
int64_t timestamp_sec
time in seconds since Unix epoch
Definition: message.h:153
int64_t timestamp_usec
additional time microseconds
Definition: message.h:154
Interface field info list.
Definition: types.h:58
const char * enumtype
text representation of enum type
Definition: types.h:60
void * value
Current value of this field.
Definition: types.h:63
size_t length
Length of field (array, string)
Definition: types.h:62
const char * name
Name of this field.
Definition: types.h:61
interface_fieldtype_t type
type of this field
Definition: types.h:59
const interface_enum_map_t * enum_map
Map of possible enum values.
Definition: types.h:64
interface_fieldinfo_t * next
next field, NULL if last
Definition: types.h:65