Fawkes API  Fawkes Development Version
interface_proxy.cpp
1 
2 /***************************************************************************
3  * interface_proxy.cpp - BlackBoard interface proxy for RemoteBlackBoard
4  *
5  * Created: Tue Mar 04 11:40:18 2008
6  * Copyright 2006-2008 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 <arpa/inet.h>
25 #include <blackboard/internal/instance_factory.h>
26 #include <blackboard/internal/interface_mem_header.h>
27 #include <blackboard/internal/notifier.h>
28 #include <blackboard/net/interface_proxy.h>
29 #include <blackboard/net/messages.h>
30 #include <core/threading/refc_rwlock.h>
31 #include <logging/liblogger.h>
32 #include <netcomm/fawkes/client.h>
33 #include <netcomm/fawkes/message.h>
34 
35 #include <cstdlib>
36 #include <cstring>
37 
38 namespace fawkes {
39 
40 /** @class BlackBoardInterfaceProxy <blackboard/net/interface_proxy.h>
41  * Interface proxy for remote BlackBoard.
42  * This proxy is used internally by RemoteBlackBoard to interact with an interface
43  * on the one side and the remote BlackBoard on the other side.
44  * @author Tim Niemueller
45  */
46 
47 /** Constructor.
48  * @param client Fawkes network client
49  * @param msg must be a MSG_BB_OPEN_SUCCESS message describing the interface in question
50  * @param notifier BlackBoard notifier to use to notify of interface events
51  * @param interface interface instance of the correct type, will be initialized in
52  * this ctor and can be used afterwards.
53  * @param writer true to make this a writing instance, false otherwise
54  */
57  BlackBoardNotifier * notifier,
58  Interface * interface,
59  bool writer)
60 {
61  fnc_ = client;
62  if (msg->msgid() != MSG_BB_OPEN_SUCCESS) {
63  throw Exception("Expected open success message");
64  }
65 
66  void * payload = msg->payload();
67  bb_iopensucc_msg_t *osm = (bb_iopensucc_msg_t *)payload;
68 
69  notifier_ = notifier;
70  interface_ = interface;
71  instance_serial_ = osm->serial;
72  has_writer_ = osm->writer_readers & htonl(0x80000000);
73  num_readers_ = ntohl(osm->writer_readers & htonl(0x7FFFFFFF));
74  data_size_ = ntohl(osm->data_size);
75  clid_ = msg->clid();
76  next_msg_id_ = 1;
77 
78  if (interface->datasize() != data_size_) {
79  // Boom, sizes do not match
80  throw Exception("Network message does not carry chunk of expected size");
81  }
82 
83  rwlock_ = new RefCountRWLock();
84  mem_chunk_ = malloc(sizeof(interface_header_t) + data_size_);
85  data_chunk_ = (char *)mem_chunk_ + sizeof(interface_header_t);
86  memset(mem_chunk_, 0, sizeof(interface_header_t) + data_size_);
87  memcpy(data_chunk_, (char *)payload + sizeof(bb_iopensucc_msg_t), data_size_);
88 
89  interface_header_t *ih = (interface_header_t *)mem_chunk_;
90 
91  strncpy(ih->type, interface->type(), INTERFACE_TYPE_SIZE_ - 1);
92  strncpy(ih->id, interface->id(), INTERFACE_ID_SIZE_ - 1);
93  memcpy(ih->hash, interface->hash(), INTERFACE_HASH_SIZE_);
94  ih->flag_writer_active = (has_writer_ ? 1 : 0);
95  ih->num_readers = num_readers_;
96  ih->refcount = 1;
97 
98  interface->set_instance_serial(instance_serial_);
99  interface->set_memory(0, mem_chunk_, data_chunk_);
100  interface->set_mediators(this, this);
101  interface->set_readwrite(writer, rwlock_);
102 }
103 
104 /** Destructor. */
106 {
107  free(mem_chunk_);
108 }
109 
110 /** Process MSG_BB_DATA_CHANGED/REFRESHED message.
111  * @param msg message to process.
112  */
113 void
115 {
116  if (msg->msgid() != MSG_BB_DATA_CHANGED && msg->msgid() != MSG_BB_DATA_REFRESHED) {
117  LibLogger::log_error("BlackBoardInterfaceProxy",
118  "Expected data changed BB message, but "
119  "received message of type %u, ignoring.",
120  msg->msgid());
121  return;
122  }
123 
124  void * payload = msg->payload();
125  bb_idata_msg_t *dm = (bb_idata_msg_t *)payload;
126  if (dm->serial != instance_serial_) {
127  LibLogger::log_error("BlackBoardInterfaceProxy",
128  "Serial mismatch, expected %s, "
129  "but got %s, ignoring.",
130  instance_serial_.get_string().c_str(),
131  dm->serial.get_string().c_str());
132  return;
133  }
134 
135  if (ntohl(dm->data_size) != data_size_) {
136  LibLogger::log_error("BlackBoardInterfaceProxy",
137  "Data size mismatch, expected %zu, "
138  "but got %zu, ignoring.",
139  data_size_,
140  ntohl(dm->data_size));
141  return;
142  }
143 
144  memcpy(data_chunk_, (char *)payload + sizeof(bb_idata_msg_t), data_size_);
145 
146  notifier_->notify_of_data_refresh(interface_, msg->msgid() == MSG_BB_DATA_CHANGED);
147 }
148 
149 /** Process MSG_BB_INTERFACE message.
150  * @param msg message to process.
151  */
152 void
154 {
155  if (msg->msgid() != MSG_BB_INTERFACE_MESSAGE) {
156  LibLogger::log_error("BlackBoardInterfaceProxy",
157  "Expected interface BB message, but "
158  "received message of type %u, ignoring.",
159  msg->msgid());
160  return;
161  }
162 
163  void * payload = msg->payload();
164  bb_imessage_msg_t *mm = (bb_imessage_msg_t *)payload;
165  if (mm->serial != instance_serial_) {
166  LibLogger::log_error("BlackBoardInterfaceProxy",
167  "Serial mismatch (msg), expected %s, "
168  "but got %s, ignoring.",
169  instance_serial_.get_string().c_str(),
170  mm->serial.get_string().c_str());
171  return;
172  }
173 
174  if (!interface_->is_writer()) {
175  LibLogger::log_error("BlackBoardInterfaceProxy",
176  "Received interface message, but this"
177  "is a reading instance (%s), ignoring.",
178  interface_->uid());
179  return;
180  }
181 
182  try {
183  Message *im = interface_->create_message(mm->msg_type);
184  im->set_id(ntohl(mm->msgid));
185  im->set_hops(ntohl(mm->hops) + 1);
186  im->set_sender_id(mm->serial);
187  im->set_source_id(mm->source);
188  LibLogger::log_debug("BlackBoardInterfaceProxy",
189  "Setting sender id to %s, source id to %s",
190  mm->serial.get_string().c_str(),
191  mm->source.get_string().c_str());
192 
193  if (im->hops() > 1) {
194  LibLogger::log_warn("BlackBoardInterfaceProxy",
195  "Message IDs are not stable across more than one hop, "
196  "message of type %s for interface %s has %u hops",
197  im->type(),
198  interface_->uid(),
199  im->hops());
200  }
201 
202  if (ntohl(mm->data_size) != im->datasize()) {
203  LibLogger::log_error("BlackBoardInterfaceProxy",
204  "Message data size mismatch, expected "
205  "%zu, but got %zu, ignoring.",
206  im->datasize(),
207  ntohl(mm->data_size));
208  delete im;
209  return;
210  }
211 
212  im->set_from_chunk((char *)payload + sizeof(bb_imessage_msg_t));
213 
214  if (notifier_->notify_of_message_received(interface_, im)) {
215  interface_->msgq_append(im);
216  im->unref();
217  }
218  } catch (Exception &e) {
219  e.append("Failed to enqueue interface message for %s, ignoring", interface_->uid());
220  LibLogger::log_error("BlackBoardInterfaceProxy", e);
221  }
222 }
223 
224 /** Reader has been added.
225  * @param event_serial instance serial of the interface that caused the event
226  */
227 void
229 {
230  ++num_readers_;
231  notifier_->notify_of_reader_added(interface_, event_serial);
232 }
233 
234 /** Reader has been removed.
235  * @param event_serial instance serial of the interface that caused the event
236  */
237 void
239 {
240  if (num_readers_ > 0) {
241  --num_readers_;
242  }
243  notifier_->notify_of_reader_removed(interface_, event_serial);
244 }
245 
246 /** Writer has been added.
247  * @param event_serial instance serial of the interface that caused the event
248  */
249 void
251 {
252  has_writer_ = true;
253  notifier_->notify_of_writer_added(interface_, event_serial);
254 }
255 
256 /** Writer has been removed.
257  * @param event_serial instance serial of the interface that caused the event
258  */
259 void
261 {
262  has_writer_ = false;
263  notifier_->notify_of_writer_removed(interface_, event_serial);
264 }
265 
266 /** Get instance serial of interface.
267  * @return instance serial
268  */
269 Uuid
271 {
272  return instance_serial_;
273 }
274 
275 /** Get client ID of assigned client.
276  * @return client ID
277  */
278 Uuid
280 {
281  return instance_serial_;
282 }
283 
284 /** Get instance serial of interface.
285  * @return instance serial
286  */
287 Interface *
289 {
290  return interface_;
291 }
292 
293 /* InterfaceMediator */
294 bool
296 {
297  return has_writer_;
298 }
299 
300 unsigned int
302 {
303  return num_readers_;
304 }
305 
306 std::list<std::string>
308 {
309  throw NotImplementedException("Reader information not available for remote blackboard");
310 }
311 
312 std::string
314 {
315  throw NotImplementedException("Writer information not available for remote blackboard");
316 }
317 
318 void
320 {
321  // need to send write message
322  size_t payload_size = sizeof(bb_idata_msg_t) + interface->datasize();
323  void * payload = malloc(payload_size);
324  bb_idata_msg_t *dm = (bb_idata_msg_t *)payload;
325  dm->serial = interface->serial();
326  dm->data_size = htonl(interface->datasize());
327  memcpy((char *)payload + sizeof(bb_idata_msg_t), interface->datachunk(), interface->datasize());
328 
329  FawkesNetworkMessage *omsg =
330  new FawkesNetworkMessage(clid_,
331  FAWKES_CID_BLACKBOARD,
332  has_changed ? MSG_BB_DATA_CHANGED : MSG_BB_DATA_REFRESHED,
333  payload,
334  payload_size);
335  fnc_->enqueue(omsg);
336 }
337 
338 /* MessageMediator */
339 void
341 {
342  // send out interface message
343  size_t payload_size = sizeof(bb_imessage_msg_t) + message->datasize();
344  void * payload = calloc(1, payload_size);
345  bb_imessage_msg_t *dm = (bb_imessage_msg_t *)payload;
346  dm->serial = interface_->serial();
347  dm->source = message->source_id();
348  unsigned int msgid = next_msg_id();
349  dm->msgid = htonl(msgid);
350  dm->hops = htonl(message->hops());
351  message->set_id(msgid);
352  strncpy(dm->msg_type, message->type(), INTERFACE_MESSAGE_TYPE_SIZE_ - 1);
353  dm->data_size = htonl(message->datasize());
354  memcpy((char *)payload + sizeof(bb_imessage_msg_t), message->datachunk(), message->datasize());
355 
357  clid_, FAWKES_CID_BLACKBOARD, MSG_BB_INTERFACE_MESSAGE, payload, payload_size);
358  fnc_->enqueue(omsg);
359 }
360 
361 } // end namespace fawkes
virtual void transmit(Message *message)
Transmit message.
Uuid clid() const
Get client ID of assigned client.
Interface * interface() const
Get instance serial of interface.
void process_interface_message(FawkesNetworkMessage *msg)
Process MSG_BB_INTERFACE message.
virtual bool exists_writer(const Interface *interface) const
Check if a writer exists for the given interface.
void reader_removed(Uuid event_serial)
Reader has been removed.
void reader_added(Uuid event_serial)
Reader has been added.
Uuid serial() const
Get instance serial of interface.
void process_data_refreshed(FawkesNetworkMessage *msg)
Process MSG_BB_DATA_CHANGED/REFRESHED message.
virtual void notify_of_data_refresh(const Interface *interface, bool has_changed)
Notify of data change.
virtual unsigned int num_readers(const Interface *interface) const
Get number of readers.
BlackBoardInterfaceProxy(FawkesNetworkClient *client, FawkesNetworkMessage *msg, BlackBoardNotifier *notifier, Interface *interface, bool readwrite)
Constructor.
virtual std::list< std::string > readers(const Interface *interface) const
Get owners of interfaces who opened for reading.
virtual std::string writer(const Interface *interface) const
Get writer of interface.
void writer_added(Uuid event_serial)
Writer has been added.
void writer_removed(Uuid event_serial)
Writer has been removed.
BlackBoard notifier.
Definition: notifier.h:44
void notify_of_writer_added(const Interface *interface, Uuid event_instance_serial) noexcept
Notify that writer has been added.
Definition: notifier.cpp:495
void notify_of_writer_removed(const Interface *interface, Uuid event_instance_serial) noexcept
Notify that writer has been removed.
Definition: notifier.cpp:532
void notify_of_reader_added(const Interface *interface, Uuid event_instance_serial) noexcept
Notify that reader has been added.
Definition: notifier.cpp:589
void notify_of_reader_removed(const Interface *interface, Uuid event_instance_serial) noexcept
Notify that reader has been removed.
Definition: notifier.cpp:626
void notify_of_data_refresh(const Interface *interface, bool has_changed)
Notify of data change.
Definition: notifier.cpp:689
bool notify_of_message_received(const Interface *interface, Message *message)
Notify of message received Notify all subscribers of the given interface of an incoming message This ...
Definition: notifier.cpp:744
Base class for exceptions in Fawkes.
Definition: exception.h:36
void append(const char *format,...) noexcept
Append messages to the message list.
Definition: exception.cpp:333
Simple Fawkes network client.
Definition: client.h:52
void enqueue(FawkesNetworkMessage *message)
Enqueue message to send.
Definition: client.cpp:596
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 int clid() const
Get client ID.
Definition: message.cpp:276
void * payload() const
Get payload buffer.
Definition: message.cpp:312
Base class for all Fawkes BlackBoard interfaces.
Definition: interface.h:80
const void * datachunk() const
Get data chunk.
Definition: interface.cpp:436
const char * type() const
Get type of interface.
Definition: interface.cpp:652
virtual Message * create_message(const char *type) const =0
Create message based on type name.
bool is_writer() const
Check if this is a writing instance.
Definition: interface.cpp:445
const unsigned char * hash() const
Get interface hash.
Definition: interface.cpp:305
void msgq_append(Message *message)
Enqueue message.
Definition: interface.cpp:986
const char * id() const
Get identifier of interface.
Definition: interface.cpp:661
Uuid serial() const
Get instance serial of interface.
Definition: interface.cpp:695
const char * uid() const
Get unique identifier of interface.
Definition: interface.cpp:686
unsigned int datasize() const
Get data size.
Definition: interface.cpp:540
static void log_warn(const char *component, const char *format,...)
Log warning message.
Definition: liblogger.cpp:156
static void log_error(const char *component, const char *format,...)
Log error message.
Definition: liblogger.cpp:174
static void log_debug(const char *component, const char *format,...)
Log debug message.
Definition: liblogger.cpp:120
Base class for all messages passed through interfaces in Fawkes BlackBoard.
Definition: message.h:44
const char * type() const
Get message type.
Definition: message.cpp:381
const void * datachunk() const
Get pointer to data.
Definition: message.cpp:281
unsigned int datasize() const
Get size of data.
Definition: message.cpp:290
Uuid source_id() const
Get ID of the original source of the message.
Definition: message.cpp:346
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 set_hops(unsigned int hops)
Set number of hops.
Definition: message.cpp:227
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
Called method has not been implemented.
Definition: software.h:105
Read/write lock with reference counting.
Definition: refc_rwlock.h:33
void unref()
Decrement reference count and conditionally delete this instance.
Definition: refcount.cpp:95
A convenience class for universally unique identifiers (UUIDs).
Definition: uuid.h:29
std::string get_string() const
Get the string representation of the Uuid.
Definition: uuid.cpp:107
Fawkes library namespace.
Interface data message.
Definition: messages.h:165
uint32_t data_size
size in bytes of the following data.
Definition: messages.h:167
Uuid serial
instance serial to unique identify this instance
Definition: messages.h:166
Interface message.
Definition: messages.h:175
Uuid serial
interface instance serial
Definition: messages.h:176
uint32_t msgid
message ID
Definition: messages.h:179
Uuid source
serial of the original message source
Definition: messages.h:177
uint32_t data_size
data for message
Definition: messages.h:181
char msg_type[INTERFACE_MESSAGE_TYPE_SIZE_]
message type
Definition: messages.h:178
uint32_t hops
number of hops this message already passed
Definition: messages.h:180
Interface open success The serial denotes a unique instance of an interface within the (remote) Black...
Definition: messages.h:142
Uuid serial
instance serial to unique identify this instance
Definition: messages.h:143
uint32_t data_size
size in bytes of the following data.
Definition: messages.h:148
uint32_t writer_readers
combined writer reader information.
Definition: messages.h:144
This struct is used as header for interfaces in memory chunks.
char type[INTERFACE_TYPE_SIZE_]
interface type
uint32_t refcount
reference count
uint16_t num_readers
number of active readers
uint16_t flag_writer_active
1 if there is a writer, 0 otherwise
unsigned char hash[INTERFACE_HASH_SIZE_]
interface type version hash
char id[INTERFACE_ID_SIZE_]
interface identifier