Branch data Line data Source code
1 : : /*
2 : : * Copyright 2006-2009 Savarese Software Research Corporation
3 : : *
4 : : * Licensed under the Apache License, Version 2.0 (the "License");
5 : : * you may not use this file except in compliance with the License.
6 : : * You may obtain a copy of the License at
7 : : *
8 : : * http://www.savarese.com/software/ApacheLicense-2.0
9 : : *
10 : : * Unless required by applicable law or agreed to in writing, software
11 : : * distributed under the License is distributed on an "AS IS" BASIS,
12 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 : : * See the License for the specific language governing permissions and
14 : : * limitations under the License.
15 : : */
16 : :
17 : : /**
18 : : * @file
19 : : * This header defines the GroupSession messaging protocol.
20 : : */
21 : :
22 : : #ifndef __SSRC_WSPR_GROUP_SESSION_PROTOCOL_H
23 : : #define __SSRC_WSPR_GROUP_SESSION_PROTOCOL_H
24 : :
25 : : #include <ssrc/wispers/protocol.h>
26 : : #include <ssrc/wispers/utility/Properties.h>
27 : : #include <ssrc/wispers/utility/ToString.h>
28 : : #include <ssrc/wispers/group_session/types.h>
29 : :
30 : : // Includes serialize function for std::pair.
31 : : #include <boost/serialization/utility.hpp>
32 : :
33 : : __BEGIN_NS_SSRC_WSPR_PROTOCOL
34 : :
35 : : WSPR_DEFINE_PROTOCOL(GroupSession,group_session);
36 : :
37 : : __END_NS_SSRC_WSPR_PROTOCOL
38 : :
39 : : __BEGIN_NS_SSRC_WSPR_GROUP_SESSION
40 : :
41 : : using NS_SSRC_WSPR::ByteBuffer;
42 : : using NS_SSRC_WSPR_UTILITY::Properties;
43 : : using NS_SSRC_WSPR_UTILITY::properties_ptr;
44 : : using NS_SSRC_WSPR_UTILITY::ToString;
45 : : using NS_SSRC_WISP_PROTOCOL::wisp_message_protocol;
46 : :
47 : : typedef std::vector<gsid_type> gsid_container;
48 : : typedef std::vector<uid_type> uid_container;
49 : : typedef std::vector<GroupSession> group_session_container;
50 : : typedef std::vector<Reservation> reservation_container;
51 : : typedef std::vector<Member> member_container;
52 : :
53 : : struct GroupSessionProtocol :
54 : : public protocol::ServiceProtocol<protocol::GroupSession>
55 : : {
56 : : typedef protocol::ServiceProtocol<protocol::GroupSession> super;
57 : :
58 : : WISP_IMPORT(super, caller_type);
59 : :
60 : : /** The maximum value a gsid can have. */
61 : : static const gsid_type GSIDMax = boost::integer_traits<gsid_type>::const_max;
62 : :
63 : : /** The minimum value a gsid can have. */
64 : : static const gsid_type GSIDMin = boost::integer_traits<gsid_type>::const_min;
65 : :
66 : : /**
67 : : * The size of a gsid protocol partition. For example, the first protocol
68 : : * partition is assigned the range:
69 : : * @verbatim (GSIDMin, GSIDMin + GSIDSpace] @endverbatim
70 : : */
71 : : // Calculation is independent of whether gsid_type is signed or unsigned.
72 : : // Protocol numbers start at 0, which is why we use
73 : : // boost::integer_traits<wisp_message_protocol>::const_max without respect
74 : : // to the distance to const_min.
75 : : static const gsid_type GSIDSpace =
76 : : (((boost::integer_traits<gsid_type>::const_max >> 2) + 1)
77 : : - (boost::integer_traits<gsid_type>::const_min >> 2)) /
78 : : ((boost::integer_traits<wisp_message_protocol>::const_max >> 2) + 1);
79 : :
80 : : static string event_group_expire() {
81 : : return WSPR_EVENT_GROUP("group_session", "expire");
82 : : }
83 : :
84 : : enum {
85 : : RelayEvent,
86 : : RelayEventSelfDiscard,
87 : : CreateGroupSession,
88 : : EndGroupSession,
89 : : ExpireGroupSession,
90 : : FindGroupSessions,
91 : : FindGroupSessionsResult,
92 : : FindGroupSessionsForMember,
93 : : ReturnGroupSessionsForMember,
94 : : FindGroupSessionsByType,
95 : : ReturnGroupSessionsByType,
96 : : CreateReservation,
97 : : CancelReservation,
98 : : StartGroupSession,
99 : : FindMembers,
100 : : FindMembersResult,
101 : : AddMembers,
102 : : RemoveMembers,
103 : : AddMember,
104 : : AddMemberConfirm,
105 : : RemoveMember,
106 : : RemoveMemberConfirm
107 : : };
108 : :
109 : : enum { DefaultPayloadCapacity = NS_SSRC_SPREAD::Message::DefaultCapacity };
110 : :
111 : : enum MemberType { Participant, Observer };
112 : :
113 : : struct MessageCreateGroupSession :
114 : : public protocol::MessageGroupSession<CreateGroupSession>
115 : : {
116 : : string session_name;
117 : : string session_group;
118 : : string session_type;
119 : : sec_type lifetime;
120 : : uid_container participants;
121 : : unsigned int max_observers;
122 : : ByteBuffer payload;
123 : :
124 : : MessageCreateGroupSession() : payload(DefaultPayloadCapacity) { }
125 : :
126 : : MessageCreateGroupSession(const string & session_name,
127 : : const string & session_group,
128 : : const string & session_type,
129 : : const sec_type lifetime,
130 : : const uid_container & participants,
131 : : const unsigned int max_observers) :
132 : : session_name(session_name),
133 : : session_group(session_group),
134 : : session_type(session_type),
135 : : lifetime(lifetime),
136 : : participants(participants),
137 : : max_observers(max_observers),
138 : : payload(DefaultPayloadCapacity)
139 : : { }
140 : :
141 : : template<class Archive>
142 : : void serialize(Archive & ar, const unsigned int) {
143 : : ar & session_name & session_group & session_type & lifetime
144 : : & participants & max_observers & payload;
145 : : }
146 : : };
147 : :
148 : : struct MessageCreateReservation :
149 : : public protocol::MessageGroupSession<CreateReservation>
150 : : {
151 : : string session_name;
152 : : string session_group;
153 : : string session_type;
154 : : sec_type gs_lifetime;
155 : : uid_type creator_uid;
156 : : sec_type reservation_lifetime;
157 : : unsigned int max_observers;
158 : : ByteBuffer payload;
159 : :
160 : : MessageCreateReservation() : payload(DefaultPayloadCapacity) { }
161 : :
162 : : MessageCreateReservation(const string & session_name,
163 : : const string & session_group,
164 : : const string & session_type,
165 : : const sec_type gs_lifetime,
166 : : const uid_type creator_uid,
167 : : const sec_type reservation_lifetime,
168 : : const unsigned int max_observers) :
169 : : session_name(session_name),
170 : : session_group(session_group),
171 : : session_type(session_type),
172 : : gs_lifetime(gs_lifetime),
173 : : creator_uid(creator_uid),
174 : : reservation_lifetime(reservation_lifetime),
175 : : max_observers(max_observers),
176 : : payload(DefaultPayloadCapacity)
177 : : { }
178 : :
179 : : template<class Archive>
180 : : void serialize(Archive & ar, const unsigned int) {
181 : : ar & session_name & session_group & session_type & gs_lifetime
182 : : & creator_uid & reservation_lifetime & max_observers & payload;
183 : : }
184 : : };
185 : :
186 : : WISP_PROTOCOL_MESSAGE(EndGroupSession, protocol::MessageGroupSession,
187 : : ((gsid_type, gsid)));
188 : :
189 : : WISP_PROTOCOL_MESSAGE(CancelReservation, protocol::MessageGroupSession,
190 : : ((gsid_type, gsid))((uid_type, requestor)));
191 : :
192 : : WISP_PROTOCOL_MESSAGE(StartGroupSession,
193 : : protocol::MessageGroupSession,
194 : : ((GroupSession, session)));
195 : :
196 : : WISP_STRUCT(ExpirationNotification,
197 : : ((gsid_type, gsid))
198 : : ((uid_container, uids)));
199 : : typedef
200 : : std::vector<ExpirationNotification> expiration_notification_container;
201 : : /**
202 : : * Expires both active sessions and reservations.
203 : : */
204 : : WISP_PROTOCOL_MESSAGE(ExpireGroupSession, protocol::MessageGroupSession,
205 : : ((expiration_notification_container, notifications)));
206 : :
207 : : WISP_PROTOCOL_MESSAGE_WITH_INIT(RelayEvent, protocol::MessageGroupSession,
208 : : ((gsid_type, gsid))
209 : : ((string, event_queue))
210 : : ((properties_ptr, event)),
211 : : ((gsid_type()))
212 : : ((string()))
213 : : ((properties_ptr(new Properties))));
214 : :
215 : : WISP_PROTOCOL_MESSAGE_WITH_INIT(RelayEventSelfDiscard,
216 : : protocol::MessageGroupSession,
217 : : ((uid_type, source))
218 : : ((gsid_type, gsid))
219 : : ((string, event_queue))
220 : : ((properties_ptr, event)),
221 : : ((uid_type()))
222 : : ((gsid_type()))
223 : : ((string()))
224 : : ((properties_ptr(new Properties))));
225 : :
226 : : WISP_PROTOCOL_MESSAGE(FindGroupSessions, protocol::MessageGroupSession,
227 : : ((uid_type, requestor))
228 : : ((db_limit_type, limit))
229 : : ((db_offset_type, offset)));
230 : :
231 : : WISP_PROTOCOL_MESSAGE(FindGroupSessionsResult, protocol::MessageGroupSession,
232 : : ((uid_type, requestor))
233 : : ((unsigned int, total_sessions))
234 : : ((db_limit_type, limit))
235 : : ((db_offset_type, offset))
236 : : ((group_session_container, sessions)));
237 : :
238 : : WISP_PROTOCOL_MESSAGE(FindGroupSessionsForMember,
239 : : protocol::MessageGroupSession,
240 : : ((uid_type, uid)));
241 : :
242 : : WISP_PROTOCOL_MESSAGE(ReturnGroupSessionsForMember,
243 : : protocol::MessageGroupSession,
244 : : ((uid_type, uid))
245 : : ((group_session_container, participating))
246 : : ((group_session_container, observing))
247 : : ((reservation_container, awaiting)));
248 : :
249 : : typedef std::vector<string> query_list;
250 : : WISP_PROTOCOL_MESSAGE(FindGroupSessionsByType, protocol::MessageGroupSession,
251 : : ((query_list, keys)));
252 : : WISP_PROTOCOL_MESSAGE(ReturnGroupSessionsByType,
253 : : protocol::MessageGroupSession,
254 : : ((group_session_container, sessions)));
255 : :
256 : : WISP_PROTOCOL_MESSAGE(FindMembers,
257 : : protocol::MessageGroupSession,
258 : : ((uid_type, requestor))
259 : : ((gsid_container, sessions)));
260 : :
261 : : WISP_PROTOCOL_MESSAGE(FindMembersResult,
262 : : protocol::MessageGroupSession,
263 : : ((uid_type, requestor))
264 : : ((member_container, participants))
265 : : ((member_container, observers)));
266 : :
267 : : WISP_PROTOCOL_MESSAGE(AddMembers,
268 : : protocol::MessageGroupSession,
269 : : ((member_container, participants))
270 : : ((member_container, observers)));
271 : :
272 : : WISP_PROTOCOL_MESSAGE(RemoveMembers,
273 : : protocol::MessageGroupSession,
274 : : ((member_container, participants))
275 : : ((member_container, observers)));
276 : :
277 : : WISP_PROTOCOL_MESSAGE(AddMember,
278 : : protocol::MessageGroupSession,
279 : : ((MemberType, member_type))
280 : : ((Member, member)));
281 : :
282 : : enum AddMemberResultCode {
283 : : AddMemberInternalError,
284 : : AddMemberNonexistentGroupSession,
285 : : AddMemberDuplicateEntry,
286 : : AddMemberMaxObserversReached,
287 : : AddMemberSuccess
288 : : };
289 : :
290 : : WISP_PROTOCOL_MESSAGE(AddMemberConfirm,
291 : : protocol::MessageGroupSession,
292 : : ((AddMemberResultCode, result))
293 : : ((MemberType, member_type))
294 : : ((uid_type, uid))
295 : : ((GroupSession, session)));
296 : :
297 : : WISP_PROTOCOL_MESSAGE(RemoveMember,
298 : : protocol::MessageGroupSession,
299 : : ((MemberType, member_type))
300 : : ((Member, member)));
301 : :
302 : : WISP_PROTOCOL_MESSAGE(RemoveMemberConfirm,
303 : : protocol::MessageGroupSession,
304 : : ((MemberType, member_type))
305 : : ((Member, member)));
306 : :
307 : : WISP_ONE_WAY_CALL(caller_type, CreateGroupSession);
308 : : WISP_ONE_WAY_CALL(caller_type, EndGroupSession);
309 : : WISP_ONE_WAY_CALL(caller_type, ExpireGroupSession);
310 : : WISP_ONE_WAY_CALL(caller_type, RelayEvent);
311 : : WISP_ONE_WAY_CALL(caller_type, RelayEventSelfDiscard);
312 : :
313 : : WISP_ONE_WAY_CALL(caller_type, CreateReservation);
314 : : WISP_ONE_WAY_CALL(caller_type, CancelReservation);
315 : : WISP_ONE_WAY_CALL(caller_type, StartGroupSession);
316 : :
317 : : WISP_TWO_WAY_CALL(caller_type, FindGroupSessionsForMember,
318 : : ReturnGroupSessionsForMember);
319 : : WISP_ONE_WAY_CALL(caller_type, ReturnGroupSessionsForMember);
320 : :
321 : : WISP_TWO_WAY_CALL(caller_type, FindGroupSessionsByType,
322 : : ReturnGroupSessionsByType);
323 : : WISP_ONE_WAY_CALL(caller_type, ReturnGroupSessionsByType);
324 : :
325 : : // Conceptually these are two-way calls, but we don't invoke them that way.
326 : : WISP_ONE_WAY_CALL(caller_type, FindGroupSessions);
327 : : WISP_ONE_WAY_CALL(caller_type, FindGroupSessionsResult);
328 : : WISP_ONE_WAY_CALL(caller_type, FindMembers);
329 : : WISP_ONE_WAY_CALL(caller_type, FindMembersResult);
330 : :
331 : :
332 : : WISP_ONE_WAY_CALL(caller_type, AddMembers);
333 : : WISP_ONE_WAY_CALL(caller_type, RemoveMembers);
334 : : WISP_ONE_WAY_CALL(caller_type, AddMember);
335 : : WISP_ONE_WAY_CALL(caller_type, AddMemberConfirm);
336 : : WISP_ONE_WAY_CALL(caller_type, RemoveMember);
337 : : WISP_ONE_WAY_CALL(caller_type, RemoveMemberConfirm);
338 : : };
339 : :
340 : : /**
341 : : * Binds the public properties of a GroupSession instance to a Properties
342 : : * node for use with a WebServiceEvent. You should use this function instead
343 : : * of visit(BindProperties(node)) to avoid leaking internal information
344 : : * such as the session group name.
345 : : *
346 : : * @param session The GroupSession to bind.
347 : : * @param node The Properties node that will store the session properties.
348 : : */
349 : : template<typename session_type>
350 : : inline void bind_group_session_properties(const session_type & session,
351 : : Properties & node)
352 : : {
353 : : node.set(session.gsid, "gsid");
354 : : node.set(session.created, "created");
355 : : node.set(session.expires, "expires");
356 : : node.set(session.type, "type");
357 : : node.set(session.name, "name");
358 : : }
359 : :
360 : : /**
361 : : * Returns the minimum gsid value associated with the specified protocol.
362 : : *
363 : : * @param protocol A Wispers protocol number.
364 : : * @return The minimum gsid value associated with the specified protocol.
365 : : */
366 : 49 : inline gsid_type gsid_min(const wisp_message_protocol protocol) {
367 : : return
368 : : (GroupSessionProtocol::GSIDMin +
369 : 49 : (static_cast<gsid_type>(protocol) * GroupSessionProtocol::GSIDSpace));
370 : : }
371 : :
372 : : /**
373 : : * Returns the maximum gsid value associated with the specified protocol.
374 : : *
375 : : * @param protocol A Wispers protocol number.
376 : : * @return The maximum gsid value associated with the specified protocol.
377 : : */
378 : 29 : inline gsid_type gsid_max(const wisp_message_protocol protocol) {
379 : : return
380 : : ((GroupSessionProtocol::GSIDMin +
381 : 29 : (static_cast<gsid_type>(protocol) + 1) * GroupSessionProtocol::GSIDSpace) - 1);
382 : : }
383 : :
384 : : /**
385 : : * Returns the minimum gsid value associated with a partition of the
386 : : * specified protocol.
387 : : *
388 : : * @param protocol A Wispers protocol number.
389 : : * @param partition_id The partiion number (0 to num_partions - 1).
390 : : * @param num_partitions The number of partitions the protocol has
391 : : * been divided into.
392 : : * @return The minimum gsid value associated with a partition of the
393 : : * specified protocol.
394 : : */
395 : 18 : inline gsid_type gsid_min(const wisp_message_protocol protocol,
396 : : const unsigned int partition_id,
397 : : const unsigned int num_partitions)
398 : : {
399 : 18 : const gsid_type min_gsid = gsid_min(protocol);
400 : 18 : const gsid_type space = GroupSessionProtocol::GSIDSpace / num_partitions;
401 : :
402 : 18 : return (min_gsid + space * partition_id);
403 : : }
404 : :
405 : : /**
406 : : * Returns the maximum gsid value associated with a partition of the
407 : : * specified protocol.
408 : : *
409 : : * @param protocol A Wispers protocol number.
410 : : * @param partition_id The partiion number (0 to num_partions - 1).
411 : : * @param num_partitions The number of partitions the protocol has
412 : : * been divided into.
413 : : * @return The maximum gsid value associated with a partition of the
414 : : * specified protocol.
415 : : */
416 : 16 : inline gsid_type gsid_max(const wisp_message_protocol protocol,
417 : : const unsigned int partition_id,
418 : : const unsigned int num_partitions)
419 : : {
420 : : // Spill over space rounding error to last partition.
421 [ + + ]: 16 : if(partition_id >= (num_partitions - 1))
422 : 14 : return gsid_max(protocol);
423 : :
424 : 2 : return gsid_min(protocol, partition_id + 1, num_partitions) - 1;
425 : : }
426 : :
427 : : /**
428 : : * Returns the protocol number that a specified gsid belongs to.
429 : : *
430 : : * @param gsid_type The gsid to convert.
431 : : * @return The protocol number that a specified gsid belongs to.
432 : : */
433 : 31 : inline wisp_message_protocol gsid_to_protocol(const gsid_type gsid) {
434 : : // Can't use basic algebra because of overflow.
435 : 31 : gsid_type result(gsid);
436 : :
437 [ + + ]: 31 : if(gsid < 0)
438 : 24 : result-=GroupSessionProtocol::GSIDMin;
439 : :
440 : 31 : result /= GroupSessionProtocol::GSIDSpace;
441 : :
442 [ + + ]: 31 : if(gsid >= 0) {
443 : : const gsid_type midpoint =
444 : 7 : (boost::integer_traits<wisp_message_protocol>::const_min / -2);
445 : 7 : result+=midpoint;
446 : : }
447 : :
448 : 31 : return static_cast<wisp_message_protocol>(result);
449 : : }
450 : :
451 : : /**
452 : : * Returns the protocol partition number associated with a given gsid
453 : : * for a protocol with a specified number of partitions.
454 : : *
455 : : * @param gsid The gsid to convert.
456 : : * @param num_partitions The number of partitions.
457 : : * @return The protocol partition number associated with a given gsid.
458 : : */
459 : : inline
460 : 12 : unsigned int gsid_to_protocol_partition(gsid_type gsid,
461 : : const unsigned int num_partitions)
462 : : {
463 : 12 : const wisp_message_protocol protocol = gsid_to_protocol(gsid);
464 : 12 : const gsid_type space = GroupSessionProtocol::GSIDSpace / num_partitions;
465 : :
466 : 12 : gsid-=gsid_min(protocol);
467 : 12 : gsid /= space;
468 : :
469 [ + + ]: 12 : if(gsid >= num_partitions)
470 : 1 : gsid = num_partitions - 1;
471 : :
472 : 12 : return static_cast<unsigned int>(gsid);
473 : : }
474 : :
475 : : /**
476 : : * GSToGroup is a utility class for deriving the group name for a
477 : : * group session service based on the provided gsid or protocol and/or
478 : : * partition id. It is more efficient than using the free functions
479 : : * because it hangs on to a ToString instance and a std::string instance
480 : : * instead of creating new ones on each call.
481 : : */
482 [ + - + - ]: 5 : class GSToGroup {
483 : : const string _gs_protocol_prefix;
484 : : string _gs_group;
485 : : ToString _string_cast;
486 : :
487 : : public:
488 : :
489 : 5 : GSToGroup() :
490 : : _gs_protocol_prefix("wspr.gs.protocol."),
491 : : _gs_group(_gs_protocol_prefix),
492 [ + - + - + : 5 : _string_cast()
- ]
493 : 5 : { }
494 : :
495 : 6 : const string & gs_protocol_group(const wisp_message_protocol protocol) {
496 : 6 : _gs_group.erase(_gs_protocol_prefix.size());
497 : 6 : return _gs_group.append(_string_cast(protocol));
498 : : }
499 : :
500 : : const string &
501 : 2 : gs_protocol_partition_group(const wisp_message_protocol protocol,
502 : : const unsigned int partition_id)
503 : : {
504 : 2 : _gs_group.erase(_gs_protocol_prefix.size());
505 : 2 : _gs_group.append(_string_cast(protocol)).append(".");
506 : : // Can't string together all of the appends because of undefined
507 : : // execution order of _string_cast, which returns a reference and
508 : : // can cause the protocol value to be used in each case.
509 : 2 : return _gs_group.append(_string_cast(partition_id));
510 : : }
511 : :
512 : 4 : const string & gsid_protocol_group(const gsid_type gsid) {
513 : 4 : return gs_protocol_group(gsid_to_protocol(gsid));
514 : : }
515 : : };
516 : :
517 : : /**
518 : : * Returns the group name reserved for group session services for a
519 : : * protocol. The format for the group is wspr.gs.protocol.N where N is
520 : : * the protocol number.
521 : : *
522 : : * @param protocol The protocol number.
523 : : * @return The group name reserved for group session services for the
524 : : * specified protocol.
525 : : */
526 : 1 : inline string gs_protocol_group(const wisp_message_protocol protocol) {
527 : 2 : GSToGroup gsid_to_group;
528 [ + - + - ]: 1 : return gsid_to_group.gs_protocol_group(protocol);
529 : : }
530 : :
531 : : /**
532 : : * Returns the group name reserved for the single group session
533 : : * service responsible for a partition of a protocol. The format for
534 : : * the group is wspr.gs.protocol.N.M where N is the protocol number and
535 : : * M is the partition number..
536 : : *
537 : : * @param protocol The protocol number.
538 : : * @param partition_id The parition number.
539 : : * @return The group name reserved for the single group session service
540 : : * responsible for the specified partition of a protocol.
541 : : */
542 : : inline
543 : 1 : string gs_protocol_partition_group(const wisp_message_protocol protocol,
544 : : const unsigned int partition_id)
545 : : {
546 : 2 : GSToGroup gsid_to_group;
547 [ + - + - ]: 1 : return gsid_to_group.gs_protocol_partition_group(protocol, partition_id);
548 : : }
549 : :
550 : : /**
551 : : * Returns the protocol group name reserved for the group sessions
552 : : * services for the protocol associated with the specified gsid.
553 : : *
554 : : * @param gsid The group session id.
555 : : * @return The protocol group name reserved for the group sessions
556 : : * services for the protocol associated with the specified gsid.
557 : : */
558 : 2 : inline string gsid_protocol_group(const gsid_type gsid) {
559 : 4 : GSToGroup gsid_to_group;
560 [ + - + - ]: 2 : return gsid_to_group.gsid_protocol_group(gsid);
561 : : }
562 : :
563 : : __END_NS_SSRC_WSPR_GROUP_SESSION
564 : :
565 : : #endif
|