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 
35 namespace 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  */
62 Message::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 =
116  (interface_fieldinfo_t *)malloc(sizeof(interface_fieldinfo_t));
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 =
153  (interface_fieldinfo_t *)malloc(sizeof(interface_fieldinfo_t));
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  */
180 unsigned int
181 Message::id() const
182 {
183  return message_id_;
184 }
185 
186 /** Get number of hops.
187  * @return number of hops
188  */
189 unsigned int
191 {
192  return hops_;
193 }
194 
195 /** Set message ID.
196  * @param message_id message ID
197  */
198 void
199 Message::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  */
207 void
208 Message::set_sender_id(const Uuid &sender_id)
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  */
217 void
218 Message::set_source_id(const Uuid &source_id)
219 {
220  _source_id = source_id;
221 }
222 
223 /** Set number of hops.
224  * @param hops number of hops
225  */
226 void
227 Message::set_hops(unsigned int hops)
228 {
229  hops_ = hops;
230 }
231 
232 /** Mark message as being enqueued. */
233 void
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  */
248 bool
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  */
261 const Time *
263 {
264  return time_enqueued_;
265 }
266 
267 /** Get recipient memory serial.
268  * @return Interface memory serial of the recipient interface.
269  */
270 unsigned 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  */
280 const void *
282 {
283  return data_ptr;
284 }
285 
286 /** Get size of data.
287  * @return size in bytes of data
288  */
289 unsigned 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  */
300 void
301 Message::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  */
312 Message &
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  */
326 const 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  */
335 Uuid
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  */
345 Uuid
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  */
357 void
358 Message::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  */
371 Interface *
373 {
374  return _transmit_via_iface;
375 }
376 
377 /** Get message type.
378  * @return textual representation of the interface type
379  */
380 const 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  */
407 unsigned 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  */
417 Message *
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  */
434 void
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