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_ = ntohl(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 message.
111  * @param msg message to process.
112  */
113 void
115 {
116  if (msg->msgid() != MSG_BB_DATA_CHANGED) {
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 (ntohl(dm->serial) != instance_serial_) {
127  LibLogger::log_error("BlackBoardInterfaceProxy",
128  "Serial mismatch, expected %u, "
129  "but got %u, ignoring.",
130  instance_serial_,
131  ntohl(dm->serial));
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_change(interface_);
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 (ntohl(mm->serial) != instance_serial_) {
166  LibLogger::log_error("BlackBoardInterfaceProxy",
167  "Serial mismatch (msg), expected %u, "
168  "but got %u, ignoring.",
169  instance_serial_,
170  ntohl(mm->serial));
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 
187  if (im->hops() > 1) {
188  LibLogger::log_warn("BlackBoardInterfaceProxy",
189  "Message IDs are not stable across more than one hop, "
190  "message of type %s for interface %s has %u hops",
191  im->type(),
192  interface_->uid(),
193  im->hops());
194  }
195 
196  if (ntohl(mm->data_size) != im->datasize()) {
197  LibLogger::log_error("BlackBoardInterfaceProxy",
198  "Message data size mismatch, expected "
199  "%zu, but got %zu, ignoring.",
200  im->datasize(),
201  ntohl(mm->data_size));
202  delete im;
203  return;
204  }
205 
206  im->set_from_chunk((char *)payload + sizeof(bb_imessage_msg_t));
207 
208  if (notifier_->notify_of_message_received(interface_, im)) {
209  interface_->msgq_append(im);
210  im->unref();
211  }
212  } catch (Exception &e) {
213  e.append("Failed to enqueue interface message for %s, ignoring", interface_->uid());
214  LibLogger::log_error("BlackBoardInterfaceProxy", e);
215  }
216 }
217 
218 /** Reader has been added.
219  * @param event_serial instance serial of the interface that caused the event
220  */
221 void
222 BlackBoardInterfaceProxy::reader_added(unsigned int event_serial)
223 {
224  ++num_readers_;
225  notifier_->notify_of_reader_added(interface_, event_serial);
226 }
227 
228 /** Reader has been removed.
229  * @param event_serial instance serial of the interface that caused the event
230  */
231 void
233 {
234  if (num_readers_ > 0) {
235  --num_readers_;
236  }
237  notifier_->notify_of_reader_removed(interface_, event_serial);
238 }
239 
240 /** Writer has been added.
241  * @param event_serial instance serial of the interface that caused the event
242  */
243 void
244 BlackBoardInterfaceProxy::writer_added(unsigned int event_serial)
245 {
246  has_writer_ = true;
247  notifier_->notify_of_writer_added(interface_, event_serial);
248 }
249 
250 /** Writer has been removed.
251  * @param event_serial instance serial of the interface that caused the event
252  */
253 void
255 {
256  has_writer_ = false;
257  notifier_->notify_of_writer_removed(interface_, event_serial);
258 }
259 
260 /** Get instance serial of interface.
261  * @return instance serial
262  */
263 unsigned int
265 {
266  return instance_serial_;
267 }
268 
269 /** Get client ID of assigned client.
270  * @return client ID
271  */
272 unsigned int
274 {
275  return instance_serial_;
276 }
277 
278 /** Get instance serial of interface.
279  * @return instance serial
280  */
281 Interface *
283 {
284  return interface_;
285 }
286 
287 /* InterfaceMediator */
288 bool
290 {
291  return has_writer_;
292 }
293 
294 unsigned int
296 {
297  return num_readers_;
298 }
299 
300 std::list<std::string>
302 {
303  throw NotImplementedException("Reader information not available for remote blackboard");
304 }
305 
306 std::string
308 {
309  throw NotImplementedException("Writer information not available for remote blackboard");
310 }
311 
312 void
314 {
315  // need to send write message
316  size_t payload_size = sizeof(bb_idata_msg_t) + interface->datasize();
317  void * payload = malloc(payload_size);
318  bb_idata_msg_t *dm = (bb_idata_msg_t *)payload;
319  dm->serial = htonl(interface->serial());
320  dm->data_size = htonl(interface->datasize());
321  memcpy((char *)payload + sizeof(bb_idata_msg_t), interface->datachunk(), interface->datasize());
322 
324  clid_, FAWKES_CID_BLACKBOARD, MSG_BB_DATA_CHANGED, payload, payload_size);
325  fnc_->enqueue(omsg);
326 }
327 
328 /* MessageMediator */
329 void
331 {
332  // send out interface message
333  size_t payload_size = sizeof(bb_imessage_msg_t) + message->datasize();
334  void * payload = calloc(1, payload_size);
335  bb_imessage_msg_t *dm = (bb_imessage_msg_t *)payload;
336  dm->serial = htonl(interface_->serial());
337  unsigned int msgid = next_msg_id();
338  dm->msgid = htonl(msgid);
339  dm->hops = htonl(message->hops());
340  message->set_id(msgid);
341  strncpy(dm->msg_type, message->type(), INTERFACE_MESSAGE_TYPE_SIZE_ - 1);
342  dm->data_size = htonl(message->datasize());
343  memcpy((char *)payload + sizeof(bb_imessage_msg_t), message->datachunk(), message->datasize());
344 
346  clid_, FAWKES_CID_BLACKBOARD, MSG_BB_INTERFACE_MESSAGE, payload, payload_size);
347  fnc_->enqueue(omsg);
348 }
349 
350 } // end namespace fawkes
virtual void transmit(Message *message)
Transmit message.
Interface * interface() const
Get instance serial of interface.
void process_data_changed(FawkesNetworkMessage *msg)
Process MSG_BB_DATA_CHANGED message.
void process_interface_message(FawkesNetworkMessage *msg)
Process MSG_BB_INTERFACE message.
unsigned int clid() const
Get client ID of assigned client.
virtual void notify_of_data_change(const Interface *interface)
Notify of data change.
void reader_added(unsigned int event_serial)
Reader has been added.
virtual bool exists_writer(const Interface *interface) const
Check if a writer exists for the given interface.
void writer_removed(unsigned int event_serial)
Writer has been removed.
void writer_added(unsigned int event_serial)
Writer has been added.
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.
unsigned int serial() const
Get instance serial of interface.
virtual std::string writer(const Interface *interface) const
Get writer of interface.
void reader_removed(unsigned int event_serial)
Reader has been removed.
BlackBoard notifier.
Definition: notifier.h:43
void notify_of_reader_added(const Interface *interface, unsigned int event_instance_serial)
Notify that reader has been added.
Definition: notifier.cpp:589
void notify_of_data_change(const Interface *interface)
Notify of data change.
Definition: notifier.cpp:687
void notify_of_writer_removed(const Interface *interface, unsigned int event_instance_serial)
Notify that writer has been removed.
Definition: notifier.cpp:532
void notify_of_writer_added(const Interface *interface, unsigned int event_instance_serial)
Notify that writer has been added.
Definition: notifier.cpp:495
void notify_of_reader_removed(const Interface *interface, unsigned int event_instance_serial)
Notify that reader has been removed.
Definition: notifier.cpp:626
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:740
Base class for exceptions in Fawkes.
Definition: exception.h:36
void append(const char *format,...)
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:79
const void * datachunk() const
Get data chunk.
Definition: interface.cpp:429
const char * type() const
Get type of interface.
Definition: interface.cpp:643
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:438
const unsigned char * hash() const
Get interface hash.
Definition: interface.cpp:298
void msgq_append(Message *message)
Enqueue message.
Definition: interface.cpp:953
const char * id() const
Get identifier of interface.
Definition: interface.cpp:652
const char * uid() const
Get unique identifier of interface.
Definition: interface.cpp:677
unsigned short serial() const
Get instance serial of interface.
Definition: interface.cpp:686
unsigned int datasize() const
Get data size.
Definition: interface.cpp:531
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
Base class for all messages passed through interfaces in Fawkes BlackBoard.
Definition: message.h:45
const char * type() const
Get message type.
Definition: message.cpp:346
const void * datachunk() const
Get pointer to data.
Definition: message.cpp:261
unsigned int datasize() const
Get size of data.
Definition: message.cpp:270
void set_from_chunk(const void *chunk)
Set from raw data chunk.
Definition: message.cpp:281
void set_id(unsigned int message_id)
Set message ID.
Definition: message.cpp:198
void set_hops(unsigned int hops)
Set number of hops.
Definition: message.cpp:207
unsigned int hops() const
Get number of hops.
Definition: message.cpp:189
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
Fawkes library namespace.
Interface data message.
Definition: messages.h:164
uint32_t serial
instance serial to unique identify this instance
Definition: messages.h:165
uint32_t data_size
size in bytes of the following data.
Definition: messages.h:166
Interface message.
Definition: messages.h:174
uint32_t msgid
message ID
Definition: messages.h:177
uint32_t serial
interface instance serial
Definition: messages.h:175
uint32_t data_size
data for message
Definition: messages.h:179
char msg_type[INTERFACE_MESSAGE_TYPE_SIZE_]
message type
Definition: messages.h:176
uint32_t hops
number of hops this message already passed
Definition: messages.h:178
Interface open success The serial denotes a unique instance of an interface within the (remote) Black...
Definition: messages.h:141
uint32_t serial
instance serial to unique identify this instance
Definition: messages.h:142
uint32_t data_size
size in bytes of the following data.
Definition: messages.h:147
uint32_t writer_readers
combined writer reader information.
Definition: messages.h:143
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