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