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
38namespace 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 */
113void
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 */
152void
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 */
227void
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 */
237void
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 */
249void
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 */
259void
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 */
269Uuid
271{
272 return instance_serial_;
273}
274
275/** Get client ID of assigned client.
276 * @return client ID
277 */
278Uuid
280{
281 return instance_serial_;
282}
283
284/** Get instance serial of interface.
285 * @return instance serial
286 */
287Interface *
289{
290 return interface_;
291}
292
293/* InterfaceMediator */
294bool
296{
297 return has_writer_;
298}
299
300unsigned int
302{
303 return num_readers_;
304}
305
306std::list<std::string>
308{
309 throw NotImplementedException("Reader information not available for remote blackboard");
310}
311
312std::string
314{
315 throw NotImplementedException("Writer information not available for remote blackboard");
316}
317
318void
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
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 */
339void
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