message.cpp

00001
00002 /***************************************************************************
00003  *  message.cpp - BlackBoard message
00004  *
00005  *  Created: Tue Oct 17 00:52:34 2006
00006  *  Copyright  2006-2009  Tim Niemueller [www.niemueller.de]
00007  *
00008  ****************************************************************************/
00009
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version. A runtime exception applies to
00014  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU Library General Public License for more details.
00020  *
00021  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00022  */
00023
00024 #include <interface/message.h>
00025 #include <interface/interface.h>
00026
00027 #include <core/threading/thread.h>
00028 #include <core/threading/mutex.h>
00029 #include <core/exceptions/software.h>
00030
00031 #include <cstring>
00032 #include <cstdlib>
00033 #include <unistd.h>
00034
00035 namespace fawkes {
00036 
00037 /** @class Message <interface/message.h>
00038  * Base class for all messages passed through interfaces in Fawkes BlackBoard.
00039  * Do not use directly, but instead use the interface generator to generate
00040  * an interface with accompanying messages.
00041  *
00042  * The sender ID of the message is automatically determined and is the instance
00043  * serial of the interface where the message was enqueued using
00044  * Interface::msgq_enqueue().
00045  *
00046  * @author Tim Niemueller
00047  */
00048 
00049 /** @var Message::data_ptr
00050  * Pointer to memory that contains local data. This memory has to be allocated
00051  * by deriving classes with the approppriate size!
00052  */
00053 
00054 /** @var Message::data_size
00055  * Size of memory needed to hold all data. This has to be set by deriving classes
00056  * to the appropriate value.
00057  */
00058
00059 
00060 /** Constructor.
00061  * @param type string representation of the message type
00062  */
00063 Message::Message(const char *type)
00064 {
00065   __fieldinfo_list = NULL;
00066
00067   __message_id = 0;
00068   __hops       = 0;
00069   __enqueued   = false;
00070   __num_fields = 0;
00071   data_ptr     = NULL;
00072   _sender_id   = 0;
00073   _type        = strdup(type);
00074
00075   _transmit_via_iface              = NULL;
00076   sender_interface_instance_serial = 0;
00077   recipient_interface_mem_serial   = 0;
00078
00079   Thread *t = Thread::current_thread_noexc();
00080   if ( t ) {
00081     _sender_thread_name = strdup(t->name());
00082   } else {
00083     _sender_thread_name    = strdup("Unknown");
00084   }
00085 }
00086
00087 
00088 /** Copy constructor.
00089  * @param mesg Message to copy.
00090  */
00091 Message::Message(const Message &mesg)
00092 {
00093   __message_id = 0;
00094   __hops       = mesg.__hops;
00095   __enqueued   = false;
00096   __num_fields = mesg.__num_fields;
00097   data_size    = mesg.data_size;
00098   data_ptr     = malloc(data_size);
00099   _sender_id   = 0;
00100   _type        = strdup(mesg._type);
00101
00102   _transmit_via_iface              = NULL;
00103   sender_interface_instance_serial = 0;
00104   recipient_interface_mem_serial   = 0;
00105
00106   memcpy(data_ptr, mesg.data_ptr, data_size);
00107
00108   interface_fieldinfo_t  *info_src  = mesg.__fieldinfo_list;
00109   interface_fieldinfo_t **info_dest = &__fieldinfo_list;
00110   while ( info_src ) {
00111     interface_fieldinfo_t *new_info = (interface_fieldinfo_t *)malloc(sizeof(interface_fieldinfo_t));
00112     memcpy(new_info, info_src, sizeof(interface_fieldinfo_t));
00113     *info_dest = new_info;
00114
00115     info_dest = &((*info_dest)->next);
00116     info_src  = info_src->next;
00117   }
00118
00119   Thread *t = Thread::current_thread_noexc();
00120   if ( t ) {
00121     _sender_thread_name = strdup(t->name());
00122   } else {
00123     _sender_thread_name    = strdup("Unknown");
00124   }
00125 }
00126
00127 
00128 /** Copy constructor.
00129  * @param mesg Message to copy.
00130  */
00131 Message::Message(const Message *mesg)
00132 {
00133   __message_id = 0;
00134   __hops       = mesg->__hops;
00135   __enqueued   = false;
00136   __num_fields = mesg->__num_fields;
00137   data_size    = mesg->data_size;
00138   data_ptr     = malloc(data_size);
00139   _sender_id   = 0;
00140   _type        = strdup(mesg->_type);
00141   _transmit_via_iface              = NULL;
00142   sender_interface_instance_serial = 0;
00143   recipient_interface_mem_serial   = 0;
00144
00145   memcpy(data_ptr, mesg->data_ptr, data_size);
00146
00147   interface_fieldinfo_t  *info_src  = mesg->__fieldinfo_list;
00148   interface_fieldinfo_t **info_dest = &__fieldinfo_list;
00149   while ( info_src ) {
00150     interface_fieldinfo_t *new_info = (interface_fieldinfo_t *)malloc(sizeof(interface_fieldinfo_t));
00151     memcpy(new_info, info_src, sizeof(interface_fieldinfo_t));
00152     *info_dest = new_info;
00153
00154     info_dest = &((*info_dest)->next);
00155     info_src  = info_src->next;
00156   }
00157
00158   Thread *t = Thread::current_thread_noexc();
00159   if ( t ) {
00160     _sender_thread_name    = strdup(t->name());
00161   } else {
00162     _sender_thread_name    = strdup("Unknown");
00163   }
00164 }
00165
00166 
00167 /** Destructor. */
00168 Message::~Message()
00169 {
00170   free(_sender_thread_name);
00171   free(_type);
00172
00173   interface_fieldinfo_t *infol = __fieldinfo_list;
00174   while ( infol ) {
00175     __fieldinfo_list = __fieldinfo_list->next;
00176     free(infol);
00177     infol = __fieldinfo_list;
00178   }
00179 }
00180
00181 
00182 /** Get message ID.
00183  * @return message ID.
00184  */
00185 unsigned int
00186 Message::id() const
00187 {
00188   return __message_id;
00189 }
00190
00191 
00192 /** Get number of hops.
00193  * @return number of hops
00194  */
00195 unsigned int
00196 Message::hops() const
00197 {
00198   return __hops;
00199 }
00200
00201 
00202 /** Set message ID.
00203  * @param message_id message ID
00204  */
00205 void
00206 Message::set_id(unsigned int message_id)
00207 {
00208   __message_id = message_id;
00209 }
00210
00211 
00212 /** Set number of hops.
00213  * @param hops number of hops
00214  */
00215 void
00216 Message::set_hops(unsigned int hops)
00217 {
00218   __hops=hops;
00219 }
00220
00221 
00222 /** Mark message as being enqueued. */
00223 void
00224 Message::mark_enqueued()
00225 {
00226   __enqueued = false;
00227 }
00228
00229 
00230 /** Check is message has been enqueued.
00231  * @return true if the message has already been enqueued, false otherwise
00232  */
00233 bool
00234 Message::enqueued() const
00235 {
00236   return __enqueued;
00237 }
00238 
00239 /** Get recipient memory serial.
00240  * @return Interface memory serial of the recipient interface.
00241  */
00242 unsigned int
00243 Message::recipient() const
00244 {
00245   return recipient_interface_mem_serial;
00246 }
00247 
00248 /** Get pointer to data.
00249  * Avoid usage.
00250  * @return pointer to internal data
00251  */
00252 const void *
00253 Message::datachunk() const
00254 {
00255   return data_ptr;
00256 }
00257
00258 
00259 /** Get size of data.
00260  * @return size in bytes of data
00261  */
00262 unsigned int
00263 Message::datasize() const
00264 {
00265   return data_size;
00266 }
00267
00268 
00269 /** Set from raw data chunk.
00270  * This sets the internal storage to the given chunk. The chunk must be exactly
00271  * of the size returned by datasize().
00272  * @param chunk chunk containing the data exactly of the size returned by datasize()
00273  */
00274 void
00275 Message::set_from_chunk(const void *chunk)
00276 {
00277   memcpy(data_ptr, chunk, data_size);
00278 }
00279
00280 
00281 /** Assign this message to given message.
00282  * Data is copied over from message if data sizes are the same.
00283  * @param m Message to copy
00284  * @return reference to current instance
00285  */
00286 Message &
00287 Message::operator=  (const Message & m)
00288 {
00289   if ( data_size == m.data_size ) {
00290     memcpy(data_ptr, m.data_ptr, data_size);
00291   }
00292
00293   return *this;
00294 }
00295
00296 
00297 /** Get sender of message.
00298  * @return name of sending thread
00299  */
00300 const char *
00301 Message::sender_thread_name() const
00302 {
00303   return _sender_thread_name;
00304 }
00305
00306 
00307 /** Get ID of sender.
00308  * @return name of sending thread.
00309  */
00310 unsigned int
00311 Message::sender_id() const
00312 {
00313   return _sender_id;
00314 }
00315
00316 
00317 /** Set transmitting interface.
00318  * Called by Message Manager
00319  * @param iface transmitting interface
00320  */
00321 void
00322 Message::set_interface(Interface *iface)
00323 {
00324   _transmit_via_iface = iface;
00325   _sender_id = iface->serial();
00326   recipient_interface_mem_serial = iface->mem_serial();
00327 }
00328
00329 
00330 /** Get transmitting interface.
00331  * @return transmitting interface, or NULL if message has not been enqueued, yet.
00332  */
00333 Interface *
00334 Message::interface() const
00335 {
00336   return _transmit_via_iface;
00337 }
00338
00339 
00340 /** Get message type.
00341  * @return textual representation of the interface type
00342  */
00343 const char *
00344 Message::type() const
00345 {
00346   return _type;
00347 }
00348
00349 
00350 /** Get iterator over all fields of this interface instance.
00351  * @return field iterator pointing to the very first value
00352  */
00353 InterfaceFieldIterator
00354 Message::fields()
00355 {
00356   return InterfaceFieldIterator(__fieldinfo_list);
00357 }
00358
00359 
00360 /** Invalid iterator.
00361  * @return invalid iterator reprensenting the end.
00362  */
00363 InterfaceFieldIterator
00364 Message::fields_end()
00365 {
00366   return InterfaceFieldIterator();
00367 }
00368
00369 
00370 /** Get the number of fields in the message.
00371  * @return the number of fields
00372  */
00373 unsigned int
00374 Message::num_fields() const
00375 {
00376   return __num_fields;
00377 }
00378
00379 
00380 /** Clone this message.
00381  * Shall be implemented by every sub-class to return a message of proper type.
00382  */
00383 Message *
00384 Message::clone() const
00385 {
00386   return new Message(this);
00387 }
00388 
00389 /** Add an entry to the info list.
00390  * Never use directly, use the interface generator instead. The info list
00391  * is used for introspection purposes to allow for iterating over all fields
00392  * of an interface.
00393  * @param type field type
00394  * @param name name of the field, this is referenced, not copied
00395  * @param length length of the field
00396  * @param value pointer to the value in the data struct
00397  */
00398 void
00399 Message::add_fieldinfo(interface_fieldtype_t type, const char *name,
00400                        size_t length, void *value)
00401 {
00402   interface_fieldinfo_t *infol = __fieldinfo_list;
00403   interface_fieldinfo_t *newinfo = (interface_fieldinfo_t *)malloc(sizeof(interface_fieldinfo_t));
00404
00405   newinfo->type   = type;
00406   newinfo->name   = name;
00407   newinfo->length = length;
00408   newinfo->value  = value;
00409   newinfo->next   = NULL;
00410
00411   if ( infol == NULL ) {
00412     // first entry
00413     __fieldinfo_list = newinfo;
00414   } else {
00415     // append to list
00416     while ( infol->next != NULL ) {
00417       infol = infol->next;
00418     }
00419     infol->next = newinfo;
00420   }
00421
00422   ++__num_fields;
00423 }
00424
00425 } // end namespace fawkes