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 <blackboard/net/interface_proxy.h>
25 #include <blackboard/internal/instance_factory.h>
26 #include <blackboard/net/messages.h>
27 #include <blackboard/internal/interface_mem_header.h>
28 #include <blackboard/internal/notifier.h>
29 
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 #include <arpa/inet.h>
38 
39 namespace fawkes {
40 
41 /** @class BlackBoardInterfaceProxy <blackboard/net/interface_proxy.h>
42  * Interface proxy for remote BlackBoard.
43  * This proxy is used internally by RemoteBlackBoard to interact with an interface
44  * on the one side and the remote BlackBoard on the other side.
45  * @author Tim Niemueller
46  */
47 
48 /** Constructor.
49  * @param client Fawkes network client
50  * @param msg must be a MSG_BB_OPEN_SUCCESS message describing the interface in question
51  * @param notifier BlackBoard notifier to use to notify of interface events
52  * @param interface interface instance of the correct type, will be initialized in
53  * this ctor and can be used afterwards.
54  * @param writer true to make this a writing instance, false otherwise
55  */
58  BlackBoardNotifier *notifier,
59  Interface *interface, 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);
92  strncpy(ih->id, interface->id(), __INTERFACE_ID_SIZE);
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 
111 /** Process MSG_BB_DATA_CHANGED message.
112  * @param msg message to process.
113  */
114 void
116 {
117  if ( msg->msgid() != MSG_BB_DATA_CHANGED ) {
118  LibLogger::log_error("BlackBoardInterfaceProxy", "Expected data changed BB message, but "
119  "received message of type %u, ignoring.", msg->msgid());
120  return;
121  }
122 
123  void *payload = msg->payload();
124  bb_idata_msg_t *dm = (bb_idata_msg_t *)payload;
125  if ( ntohl(dm->serial) != __instance_serial ) {
126  LibLogger::log_error("BlackBoardInterfaceProxy", "Serial mismatch, expected %u, "
127  "but got %u, ignoring.", __instance_serial, ntohl(dm->serial));
128  return;
129  }
130 
131  if ( ntohl(dm->data_size) != __data_size ) {
132  LibLogger::log_error("BlackBoardInterfaceProxy", "Data size mismatch, expected %zu, "
133  "but got %zu, ignoring.", __data_size, ntohl(dm->data_size));
134  return;
135  }
136 
137  memcpy(__data_chunk, (char *)payload + sizeof(bb_idata_msg_t), __data_size);
138 
139  __notifier->notify_of_data_change(__interface);
140 }
141 
142 
143 /** Process MSG_BB_INTERFACE message.
144  * @param msg message to process.
145  */
146 void
148 {
149  if ( msg->msgid() != MSG_BB_INTERFACE_MESSAGE ) {
150  LibLogger::log_error("BlackBoardInterfaceProxy", "Expected interface BB message, but "
151  "received message of type %u, ignoring.", msg->msgid());
152  return;
153  }
154 
155  void *payload = msg->payload();
156  bb_imessage_msg_t *mm = (bb_imessage_msg_t *)payload;
157  if ( ntohl(mm->serial) != __instance_serial ) {
158  LibLogger::log_error("BlackBoardInterfaceProxy", "Serial mismatch (msg), expected %u, "
159  "but got %u, ignoring.", __instance_serial, ntohl(mm->serial));
160  return;
161  }
162 
163  if ( ! __interface->is_writer() ) {
164  LibLogger::log_error("BlackBoardInterfaceProxy", "Received interface message, but this"
165  "is a reading instance (%s), ignoring.", __interface->uid());
166  return;
167  }
168 
169  try {
170  Message *im = __interface->create_message(mm->msg_type);
171  im->set_id(ntohl(mm->msgid));
172  im->set_hops(ntohl(mm->hops) + 1);
173 
174  if (im->hops() > 1) {
175  LibLogger::log_warn("BlackBoardInterfaceProxy", "Message IDs are not stable across more than one hop, "
176  "message of type %s for interface %s has %u hops",
177  im->type(), __interface->uid(), im->hops());
178  }
179 
180  if ( ntohl(mm->data_size) != im->datasize() ) {
181  LibLogger::log_error("BlackBoardInterfaceProxy", "Message data size mismatch, expected "
182  "%zu, but got %zu, ignoring.", im->datasize(), ntohl(mm->data_size));
183  delete im;
184  return;
185  }
186 
187  im->set_from_chunk((char *)payload + sizeof(bb_imessage_msg_t));
188 
189  if ( __notifier->notify_of_message_received(__interface, im) ) {
190  __interface->msgq_append(im);
191  im->unref();
192  }
193  } catch (Exception &e) {
194  e.append("Failed to enqueue interface message for %s, ignoring", __interface->uid());
195  LibLogger::log_error("BlackBoardInterfaceProxy", e);
196  }
197 }
198 
199 
200 /** Reader has been added.
201  * @param event_serial instance serial of the interface that caused the event
202  */
203 void
204 BlackBoardInterfaceProxy::reader_added(unsigned int event_serial)
205 {
206  ++__num_readers;
207  __notifier->notify_of_reader_added(__interface, event_serial);
208 }
209 
210 /** Reader has been removed.
211  * @param event_serial instance serial of the interface that caused the event
212  */
213 void
215 {
216  if ( __num_readers > 0 ) {
217  --__num_readers;
218  }
219  __notifier->notify_of_reader_removed(__interface, event_serial);
220 }
221 
222 /** Writer has been added.
223  * @param event_serial instance serial of the interface that caused the event
224  */
225 void
226 BlackBoardInterfaceProxy::writer_added(unsigned int event_serial)
227 {
228  __has_writer = true;
229  __notifier->notify_of_writer_added(__interface, event_serial);
230 }
231 
232 /** Writer has been removed.
233  * @param event_serial instance serial of the interface that caused the event
234  */
235 void
237 {
238  __has_writer = false;
239  __notifier->notify_of_writer_removed(__interface, event_serial);
240 }
241 
242 
243 /** Get instance serial of interface.
244  * @return instance serial
245  */
246 unsigned int
248 {
249  return __instance_serial;
250 }
251 
252 
253 /** Get client ID of assigned client.
254  * @return client ID
255  */
256 unsigned int
258 {
259  return __instance_serial;
260 }
261 
262 /** Get instance serial of interface.
263  * @return instance serial
264  */
265 Interface *
267 {
268  return __interface;
269 }
270 
271 
272 /* InterfaceMediator */
273 bool
275 {
276  return __has_writer;
277 }
278 
279 unsigned int
281 {
282  return __num_readers;
283 }
284 
285 std::list<std::string>
287 {
288  throw NotImplementedException("Reader information not available for remote blackboard");
289 }
290 
291 
292 std::string
294 {
295  throw NotImplementedException("Writer information not available for remote blackboard");
296 }
297 
298 void
300 {
301  // need to send write message
302  size_t payload_size = sizeof(bb_idata_msg_t) + interface->datasize();
303  void *payload = malloc(payload_size);
304  bb_idata_msg_t *dm = (bb_idata_msg_t *)payload;
305  dm->serial = htonl(interface->serial());
306  dm->data_size = htonl(interface->datasize());
307  memcpy((char *)payload + sizeof(bb_idata_msg_t), interface->datachunk(),
308  interface->datasize());
309 
310  FawkesNetworkMessage *omsg = new FawkesNetworkMessage(__clid, FAWKES_CID_BLACKBOARD,
311  MSG_BB_DATA_CHANGED,
312  payload, payload_size);
313  __fnc->enqueue(omsg);
314 }
315 
316 
317 /* MessageMediator */
318 void
320 {
321  // send out interface message
322  size_t payload_size = sizeof(bb_imessage_msg_t) + message->datasize();
323  void *payload = calloc(1, payload_size);
324  bb_imessage_msg_t *dm = (bb_imessage_msg_t *)payload;
325  dm->serial = htonl(__interface->serial());
326  unsigned int msgid = next_msg_id();
327  dm->msgid = htonl(msgid);
328  dm->hops = htonl(message->hops());
329  message->set_id(msgid);
330  strncpy(dm->msg_type, message->type(), __INTERFACE_MESSAGE_TYPE_SIZE);
331  dm->data_size = htonl(message->datasize());
332  memcpy((char *)payload + sizeof(bb_imessage_msg_t), message->datachunk(),
333  message->datasize());
334 
335  FawkesNetworkMessage *omsg = new FawkesNetworkMessage(__clid, FAWKES_CID_BLACKBOARD,
336  MSG_BB_INTERFACE_MESSAGE,
337  payload, payload_size);
338  __fnc->enqueue(omsg);
339 }
340 
341 } // end namespace fawkes
uint32_t msgid
message ID
Definition: messages.h:173
void * payload() const
Get payload buffer.
Definition: message.cpp:321
void notify_of_reader_added(const Interface *interface, unsigned int event_instance_serial)
Notify that reader has been added.
Definition: notifier.cpp:559
unsigned char hash[__INTERFACE_HASH_SIZE]
interface type version hash
unsigned int datasize() const
Get data size.
Definition: interface.cpp:534
unsigned int clid() const
Get client ID of assigned client.
Base class for all messages passed through interfaces in Fawkes BlackBoard.
Definition: message.h:44
void writer_removed(unsigned int event_serial)
Writer has been removed.
virtual std::string writer(const Interface *interface) const
Get writer of interface.
Simple Fawkes network client.
Definition: client.h:52
void unref()
Decrement reference count and conditionally delete this instance.
Definition: refcount.cpp:99
uint32_t serial
instance serial to unique identify this instance
Definition: messages.h:138
void notify_of_writer_added(const Interface *interface, unsigned int event_instance_serial)
Notify that writer has been added.
Definition: notifier.cpp:463
Fawkes library namespace.
virtual bool exists_writer(const Interface *interface) const
Check if a writer exists for the given interface.
unsigned int clid() const
Get client ID.
Definition: message.cpp:281
char type[__INTERFACE_TYPE_SIZE]
interface type
void process_interface_message(FawkesNetworkMessage *msg)
Process MSG_BB_INTERFACE message.
uint16_t flag_writer_active
1 if there is a writer, 0 otherwise
Called method has not been implemented.
Definition: software.h:107
const char * id() const
Get identifier of interface.
Definition: interface.cpp:661
void enqueue(FawkesNetworkMessage *message)
Enqueue message to send.
Definition: client.cpp:587
unsigned int serial() const
Get instance serial of interface.
uint16_t num_readers
number of active readers
Representation of a message that is sent over the network.
Definition: message.h:75
virtual unsigned int num_readers(const Interface *interface) const
Get number of readers.
void notify_of_writer_removed(const Interface *interface, unsigned int event_instance_serial)
Notify that writer has been removed.
Definition: notifier.cpp:501
virtual void notify_of_data_change(const Interface *interface)
Notify of data change.
BlackBoard notifier.
Definition: notifier.h:43
void notify_of_data_change(const Interface *interface)
Notify of data change.
Definition: notifier.cpp:660
char msg_type[__INTERFACE_MESSAGE_TYPE_SIZE]
message type
Definition: messages.h:172
virtual Message * create_message(const char *type) const =0
Create message based on type name.
void msgq_append(Message *message)
Enqueue message.
Definition: interface.cpp:976
Base class for all Fawkes BlackBoard interfaces.
Definition: interface.h:79
const void * datachunk() const
Get pointer to data.
Definition: message.cpp:285
const unsigned char * hash() const
Get interface hash.
Definition: interface.cpp:294
static void log_error(const char *component, const char *format,...)
Log error message.
Definition: liblogger.cpp:180
This struct is used as header for interfaces in memory chunks.
const char * type() const
Get type of interface.
Definition: interface.cpp:651
Base class for exceptions in Fawkes.
Definition: exception.h:36
unsigned short serial() const
Get instance serial of interface.
Definition: interface.cpp:697
void set_from_chunk(const void *chunk)
Set from raw data chunk.
Definition: message.cpp:307
unsigned int hops() const
Get number of hops.
Definition: message.cpp:207
Interface open success The serial denotes a unique instance of an interface within the (remote) Black...
Definition: messages.h:137
void reader_removed(unsigned int event_serial)
Reader has been removed.
Read/write lock with reference counting.
Definition: refc_rwlock.h:33
uint32_t data_size
data for message
Definition: messages.h:175
const char * uid() const
Get unique identifier of interface.
Definition: interface.cpp:687
uint32_t data_size
size in bytes of the following data.
Definition: messages.h:143
static void log_warn(const char *component, const char *format,...)
Log warning message.
Definition: liblogger.cpp:162
Interface data message.
Definition: messages.h:160
Interface message.
Definition: messages.h:170
bool is_writer() const
Check if this is a writing instance.
Definition: interface.cpp:440
void writer_added(unsigned int event_serial)
Writer has been added.
void reader_added(unsigned int event_serial)
Reader has been added.
uint32_t refcount
reference count
char id[__INTERFACE_ID_SIZE]
interface identifier
uint32_t serial
interface instance serial
Definition: messages.h:171
unsigned short int msgid() const
Get message type ID.
Definition: message.cpp:301
uint32_t serial
instance serial to unique identify this instance
Definition: messages.h:161
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:714
unsigned int datasize() const
Get size of data.
Definition: message.cpp:295
virtual std::list< std::string > readers(const Interface *interface) const
Get owners of interfaces who opened for reading.
const void * datachunk() const
Get data chunk.
Definition: interface.cpp:430
Interface * interface() const
Get instance serial of interface.
virtual void transmit(Message *message)
Transmit message.
void notify_of_reader_removed(const Interface *interface, unsigned int event_instance_serial)
Notify that reader has been removed.
Definition: notifier.cpp:597
void set_hops(unsigned int hops)
Set number of hops.
Definition: message.cpp:227
uint32_t data_size
size in bytes of the following data.
Definition: messages.h:162
void process_data_changed(FawkesNetworkMessage *msg)
Process MSG_BB_DATA_CHANGED message.
const char * type() const
Get message type.
Definition: message.cpp:378
uint32_t writer_readers
combined writer reader information.
Definition: messages.h:139
void set_id(unsigned int message_id)
Set message ID.
Definition: message.cpp:217
void append(const char *format,...)
Append messages to the message list.
Definition: exception.cpp:341
uint32_t hops
number of hops this message already passed
Definition: messages.h:174
BlackBoardInterfaceProxy(FawkesNetworkClient *client, FawkesNetworkMessage *msg, BlackBoardNotifier *notifier, Interface *interface, bool readwrite)
Constructor.