aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabor X Toth <*@tg-x.net>2014-07-23 16:19:49 +0000
committerGabor X Toth <*@tg-x.net>2014-07-23 16:19:49 +0000
commit3cf8ba0b60f8495892fa76635e9c23555d0a304c (patch)
tree5f27648bdb3cf3409628e4e5edc26f811cbd03a5
parent252b5599987b7ba03b879a8c2d1c455ad4c9834a (diff)
downloadgnunet-3cf8ba0b60f8495892fa76635e9c23555d0a304c.tar.gz
gnunet-3cf8ba0b60f8495892fa76635e9c23555d0a304c.zip
social: implement enter/leave/messaging; psyc: improvements and fixes
- social: implement enter/leave, send/receive messages, slicer - psyc, social: add struct GNUNET_PSYC_Message for single-fragment join messages - psyc: add message callback in addition to message part callback - client_manager, social, psyc, multicast: add disconnect callback
-rwxr-xr-xcontrib/gnunet-logread2
-rw-r--r--src/include/gnunet_client_manager_lib.h6
-rw-r--r--src/include/gnunet_common.h9
-rw-r--r--src/include/gnunet_multicast_service.h8
-rw-r--r--src/include/gnunet_protocols.h22
-rw-r--r--src/include/gnunet_psyc_service.h111
-rw-r--r--src/include/gnunet_psyc_util_lib.h28
-rw-r--r--src/include/gnunet_social_service.h261
-rw-r--r--src/multicast/gnunet-service-multicast.c7
-rw-r--r--src/multicast/multicast_api.c76
-rw-r--r--src/psyc/gnunet-service-psyc.c112
-rw-r--r--src/psyc/psyc.h16
-rw-r--r--src/psyc/psyc_api.c133
-rw-r--r--src/psyc/psyc_util_lib.c268
-rw-r--r--src/psyc/test_psyc.c93
-rw-r--r--src/social/Makefile.am5
-rw-r--r--src/social/gnunet-service-social.c1219
-rw-r--r--src/social/social.h85
-rw-r--r--src/social/social_api.c1259
-rw-r--r--src/social/test_social.c686
-rw-r--r--src/util/client_manager.c56
21 files changed, 3942 insertions, 520 deletions
diff --git a/contrib/gnunet-logread b/contrib/gnunet-logread
index 773a5ff93..173ed2387 100755
--- a/contrib/gnunet-logread
+++ b/contrib/gnunet-logread
@@ -47,7 +47,7 @@ if (exists $opts{n})
47 $ipc = $opts{i} || '/tmp/gnunet-logread-ipc.sock'; 47 $ipc = $opts{i} || '/tmp/gnunet-logread-ipc.sock';
48 $msg_level = exists $levels{$opts{L}} ? $levels{$opts{L}} : 0; 48 $msg_level = exists $levels{$opts{L}} ? $levels{$opts{L}} : 0;
49 $msg_regex = $opts{m}; 49 $msg_regex = $opts{m};
50 print STDERR "RE: /$msg_regex/\n"; 50 print STDERR "RE: /$msg_regex/\n" if defined $msg_regex;
51 open IPC, '>', $ipc or die "$ipc: $!\n"; 51 open IPC, '>', $ipc or die "$ipc: $!\n";
52} 52}
53 53
diff --git a/src/include/gnunet_client_manager_lib.h b/src/include/gnunet_client_manager_lib.h
index 6ed2ddb17..07d9d2807 100644
--- a/src/include/gnunet_client_manager_lib.h
+++ b/src/include/gnunet_client_manager_lib.h
@@ -119,10 +119,14 @@ GNUNET_CLIENT_MANAGER_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
119 * 119 *
120 * @param mgr Client manager connection. 120 * @param mgr Client manager connection.
121 * @param transmit_queue Transmit pending messages in queue before disconnecting. 121 * @param transmit_queue Transmit pending messages in queue before disconnecting.
122 * @param disconnect_cb Function called after disconnected from the service.
123 * @param disconnect_cls Closure for @a disconnect_cb.
122 */ 124 */
123void 125void
124GNUNET_CLIENT_MANAGER_disconnect (struct GNUNET_CLIENT_MANAGER_Connection *mgr, 126GNUNET_CLIENT_MANAGER_disconnect (struct GNUNET_CLIENT_MANAGER_Connection *mgr,
125 int transmit_queue); 127 int transmit_queue,
128 GNUNET_ContinuationCallback disconnect_cb,
129 void *disconnect_cls);
126 130
127 131
128/** 132/**
diff --git a/src/include/gnunet_common.h b/src/include/gnunet_common.h
index d8444e100..2b501f91f 100644
--- a/src/include/gnunet_common.h
+++ b/src/include/gnunet_common.h
@@ -264,6 +264,15 @@ typedef int
264 const char *filename); 264 const char *filename);
265 265
266 266
267/**
268 * Generic continuation callback.
269 *
270 * @param cls Closure.
271 */
272typedef void
273(*GNUNET_ContinuationCallback) (void *cls);
274
275
267/* ****************************** logging ***************************** */ 276/* ****************************** logging ***************************** */
268 277
269/** 278/**
diff --git a/src/include/gnunet_multicast_service.h b/src/include/gnunet_multicast_service.h
index 41227b925..5b8ff1894 100644
--- a/src/include/gnunet_multicast_service.h
+++ b/src/include/gnunet_multicast_service.h
@@ -666,7 +666,9 @@ GNUNET_MULTICAST_origin_to_all_cancel (struct GNUNET_MULTICAST_OriginTransmitHan
666 * @param origin Multicast group to stop. 666 * @param origin Multicast group to stop.
667 */ 667 */
668void 668void
669GNUNET_MULTICAST_origin_stop (struct GNUNET_MULTICAST_Origin *origin); 669GNUNET_MULTICAST_origin_stop (struct GNUNET_MULTICAST_Origin *origin,
670 GNUNET_ContinuationCallback stop_cb,
671 void *stop_cls);
670 672
671 673
672/** 674/**
@@ -795,7 +797,9 @@ GNUNET_MULTICAST_member_replay_cancel (struct GNUNET_MULTICAST_MemberReplayHandl
795 * @param member Membership handle. 797 * @param member Membership handle.
796 */ 798 */
797void 799void
798GNUNET_MULTICAST_member_part (struct GNUNET_MULTICAST_Member *member); 800GNUNET_MULTICAST_member_part (struct GNUNET_MULTICAST_Member *member,
801 GNUNET_ContinuationCallback part_cb,
802 void *part_cls);
799 803
800 804
801/** 805/**
diff --git a/src/include/gnunet_protocols.h b/src/include/gnunet_protocols.h
index 3451cdbf4..cff78eea6 100644
--- a/src/include/gnunet_protocols.h
+++ b/src/include/gnunet_protocols.h
@@ -2158,32 +2158,34 @@ extern "C"
2158/** C->S: request to add channel slave to the membership database */ 2158/** C->S: request to add channel slave to the membership database */
2159#define GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_SLAVE_RM 690 2159#define GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_SLAVE_RM 690
2160 2160
2161 2161/** S<--C: PSYC message which contains one or more message parts. */
2162/** M<->S<->C: PSYC message which contains one or more message parts. */
2163#define GNUNET_MESSAGE_TYPE_PSYC_MESSAGE 691 2162#define GNUNET_MESSAGE_TYPE_PSYC_MESSAGE 691
2164 2163
2164/** M<->S<->C: PSYC message which contains a header and one or more message parts. */
2165#define GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_HEADER 692 // FIXME: start using this where appropriate
2166
2165/** Message part: method */ 2167/** Message part: method */
2166#define GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD 692 2168#define GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD 693
2167 2169
2168/** Message part: modifier */ 2170/** Message part: modifier */
2169#define GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER 693 2171#define GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER 694
2170 2172
2171/** Message part: modifier continuation */ 2173/** Message part: modifier continuation */
2172#define GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT 694 2174#define GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT 695
2173 2175
2174/** Message part: data */ 2176/** Message part: data */
2175#define GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA 695 2177#define GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA 696
2176 2178
2177/** Message part: end of message */ 2179/** Message part: end of message */
2178#define GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END 696 2180#define GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END 697
2179 2181
2180/** Message part: message cancelled */ 2182/** Message part: message cancelled */
2181#define GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL 697 2183#define GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL 698
2182 2184
2183/** S->C: message acknowledgement */ 2185/** S->C: message acknowledgement */
2184#define GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK 698 2186#define GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK 699
2185 2187
2186/* 699-700 */ 2188/* 700 */
2187 2189
2188/** C->S: client requests channel history from PSYCstore. */ 2190/** C->S: client requests channel history from PSYCstore. */
2189#define GNUNET_MESSAGE_TYPE_PSYC_STORY_REQUEST 701 2191#define GNUNET_MESSAGE_TYPE_PSYC_STORY_REQUEST 701
diff --git a/src/include/gnunet_psyc_service.h b/src/include/gnunet_psyc_service.h
index 2ea282fa3..7097c46a8 100644
--- a/src/include/gnunet_psyc_service.h
+++ b/src/include/gnunet_psyc_service.h
@@ -190,6 +190,24 @@ enum GNUNET_PSYC_StateDeltaValues
190GNUNET_NETWORK_STRUCT_BEGIN 190GNUNET_NETWORK_STRUCT_BEGIN
191 191
192/** 192/**
193 * A PSYC message.
194 *
195 * Used for single-fragment messages e.g. in a join request or response.
196 */
197struct GNUNET_PSYC_Message
198{
199 /**
200 * Message header with size and type information.
201 */
202 struct GNUNET_MessageHeader header;
203
204 /* Followed by concatenated PSYC message parts:
205 * messages with GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_* types
206 */
207};
208
209
210/**
193 * Header of a PSYC message. 211 * Header of a PSYC message.
194 * 212 *
195 * Only present when receiving a message. 213 * Only present when receiving a message.
@@ -215,6 +233,12 @@ struct GNUNET_PSYC_MessageHeader
215 uint64_t message_id GNUNET_PACKED; 233 uint64_t message_id GNUNET_PACKED;
216 234
217 /** 235 /**
236 * Byte offset of this @e fragment of the @e message.
237 * FIXME: use data_offset instead
238 */
239 uint64_t fragment_offset GNUNET_PACKED;
240
241 /**
218 * Sending slave's public key. 242 * Sending slave's public key.
219 * Not set if the message is from the master. 243 * Not set if the message is from the master.
220 */ 244 */
@@ -299,6 +323,9 @@ struct GNUNET_PSYC_CountersResultMessage
299}; 323};
300 324
301 325
326/**
327 * Join request sent to a PSYC master.
328 */
302struct GNUNET_PSYC_JoinRequestMessage 329struct GNUNET_PSYC_JoinRequestMessage
303{ 330{
304 /** 331 /**
@@ -314,6 +341,9 @@ struct GNUNET_PSYC_JoinRequestMessage
314}; 341};
315 342
316 343
344/**
345 * Join decision sent in reply to a join request.
346 */
317struct GNUNET_PSYC_JoinDecisionMessage 347struct GNUNET_PSYC_JoinDecisionMessage
318{ 348{
319 /** 349 /**
@@ -379,23 +409,42 @@ struct GNUNET_PSYC_JoinHandle;
379 409
380 410
381/** 411/**
382 * Method called from PSYC upon receiving part of a message. 412 * Method called from PSYC upon receiving a message.
383 * 413 *
384 * @param cls Closure. 414 * @param cls Closure.
385 * @param message_id Sequence number of the message. 415 * @param message_id Sequence number of the message.
386 * @param flags OR'ed GNUNET_PSYC_MessageFlags 416 * @param flags OR'ed GNUNET_PSYC_MessageFlags
387 * @param msg Message part, one of the following types: 417 * @param msg Message part, one of the following types:
388 * - GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_HEADER
389 * - GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD
390 * - GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER
391 * - GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT
392 * - GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA
393 */ 418 */
394typedef void 419typedef void
395(*GNUNET_PSYC_MessageCallback) (void *cls, 420(*GNUNET_PSYC_MessageCallback) (void *cls,
396 uint64_t message_id, 421 uint64_t message_id,
397 uint32_t flags, 422 uint32_t flags,
398 const struct GNUNET_MessageHeader *msg); 423 const struct GNUNET_PSYC_MessageHeader *msg);
424
425
426/**
427 * Method called from PSYC upon receiving part of a message.
428 *
429 * @param cls Closure.
430 * @param message_id Sequence number of the message.
431 * @param data_offset Byte offset of data, only set if @a msg has a type
432 * #GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA
433 * @param flags OR'ed GNUNET_PSYC_MessageFlags
434 * @param msg Message part, one of the following types:
435 * - #GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_HEADER
436 * - #GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD
437 * - #GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER
438 * - #GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT
439 * - #GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA
440 * or NULL if an error occurred while receiving a message.
441 */
442typedef void
443(*GNUNET_PSYC_MessagePartCallback) (void *cls,
444 uint64_t message_id,
445 uint64_t data_offset,
446 uint32_t flags,
447 const struct GNUNET_MessageHeader *msg);
399 448
400 449
401/** 450/**
@@ -408,10 +457,9 @@ typedef void
408 */ 457 */
409typedef void 458typedef void
410(*GNUNET_PSYC_JoinRequestCallback) (void *cls, 459(*GNUNET_PSYC_JoinRequestCallback) (void *cls,
411 const struct 460 const struct GNUNET_PSYC_JoinRequestMessage *req,
412 GNUNET_CRYPTO_EcdsaPublicKey *slave_key, 461 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
413 const struct 462 const struct GNUNET_PSYC_Message *join_msg,
414 GNUNET_PSYC_MessageHeader *join_msg,
415 struct GNUNET_PSYC_JoinHandle *jh); 463 struct GNUNET_PSYC_JoinHandle *jh);
416 464
417 465
@@ -445,7 +493,7 @@ GNUNET_PSYC_join_decision (struct GNUNET_PSYC_JoinHandle *jh,
445 int is_admitted, 493 int is_admitted,
446 uint32_t relay_count, 494 uint32_t relay_count,
447 const struct GNUNET_PeerIdentity *relays, 495 const struct GNUNET_PeerIdentity *relays,
448 const struct GNUNET_PSYC_MessageHeader *join_resp); 496 const struct GNUNET_PSYC_Message *join_resp);
449 497
450 498
451/** 499/**
@@ -501,6 +549,7 @@ GNUNET_PSYC_master_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
501 GNUNET_PSYC_MasterStartCallback master_start_cb, 549 GNUNET_PSYC_MasterStartCallback master_start_cb,
502 GNUNET_PSYC_JoinRequestCallback join_request_cb, 550 GNUNET_PSYC_JoinRequestCallback join_request_cb,
503 GNUNET_PSYC_MessageCallback message_cb, 551 GNUNET_PSYC_MessageCallback message_cb,
552 GNUNET_PSYC_MessagePartCallback message_part_cb,
504 void *cls); 553 void *cls);
505 554
506 555
@@ -645,10 +694,21 @@ GNUNET_PSYC_master_transmit_cancel (struct GNUNET_PSYC_MasterTransmitHandle *th)
645/** 694/**
646 * Stop a PSYC master channel. 695 * Stop a PSYC master channel.
647 * 696 *
648 * @param master PSYC channel master to stop. 697 * @param master
698 * PSYC channel master to stop.
699 * @param keep_active
700 * Keep place active after last application disconnected.
701 * @param stop_cb
702 * Function called after the master stopped
703 * and disconnected from the psyc service.
704 * @param stop_cls
705 * Closure for @a part_cb.
649 */ 706 */
650void 707void
651GNUNET_PSYC_master_stop (struct GNUNET_PSYC_Master *master); 708GNUNET_PSYC_master_stop (struct GNUNET_PSYC_Master *master,
709 int keep_active,
710 GNUNET_ContinuationCallback stop_cb,
711 void *stop_cls);
652 712
653 713
654/** 714/**
@@ -679,9 +739,9 @@ typedef void
679 */ 739 */
680typedef void 740typedef void
681(*GNUNET_PSYC_JoinDecisionCallback) (void *cls, 741(*GNUNET_PSYC_JoinDecisionCallback) (void *cls,
742 const struct GNUNET_PSYC_JoinDecisionMessage *dcsn,
682 int is_admitted, 743 int is_admitted,
683 const struct 744 const struct GNUNET_PSYC_Message *join_msg);
684 GNUNET_PSYC_MessageHeader *join_msg);
685 745
686 746
687/** 747/**
@@ -726,10 +786,11 @@ GNUNET_PSYC_slave_join (const struct GNUNET_CONFIGURATION_Handle *cfg,
726 uint32_t relay_count, 786 uint32_t relay_count,
727 const struct GNUNET_PeerIdentity *relays, 787 const struct GNUNET_PeerIdentity *relays,
728 GNUNET_PSYC_MessageCallback message_cb, 788 GNUNET_PSYC_MessageCallback message_cb,
789 GNUNET_PSYC_MessagePartCallback message_part_cb,
729 GNUNET_PSYC_SlaveConnectCallback slave_connect_cb, 790 GNUNET_PSYC_SlaveConnectCallback slave_connect_cb,
730 GNUNET_PSYC_JoinDecisionCallback join_decision_cb, 791 GNUNET_PSYC_JoinDecisionCallback join_decision_cb,
731 void *cls, 792 void *cls,
732 const struct GNUNET_MessageHeader *join_msg); 793 const struct GNUNET_PSYC_Message *join_msg);
733 794
734 795
735/** 796/**
@@ -738,10 +799,21 @@ GNUNET_PSYC_slave_join (const struct GNUNET_CONFIGURATION_Handle *cfg,
738 * Will terminate the connection to the PSYC service. Polite clients should 799 * Will terminate the connection to the PSYC service. Polite clients should
739 * first explicitly send a part request (via GNUNET_PSYC_slave_transmit()). 800 * first explicitly send a part request (via GNUNET_PSYC_slave_transmit()).
740 * 801 *
741 * @param slave Slave handle. 802 * @param slave
803 * Slave handle.
804 * @param keep_active
805 * Keep place active after last application disconnected.
806 * @param part_cb
807 * Function called after the slave parted the channel
808 * and disconnected from the psyc service.
809 * @param part_cls
810 * Closure for @a part_cb.
742 */ 811 */
743void 812void
744GNUNET_PSYC_slave_part (struct GNUNET_PSYC_Slave *slave); 813GNUNET_PSYC_slave_part (struct GNUNET_PSYC_Slave *slave,
814 int keep_active,
815 GNUNET_ContinuationCallback part_cb,
816 void *part_cls);
745 817
746 818
747/** 819/**
@@ -937,6 +1009,7 @@ GNUNET_PSYC_channel_story_tell (struct GNUNET_PSYC_Channel *channel,
937 uint64_t start_message_id, 1009 uint64_t start_message_id,
938 uint64_t end_message_id, 1010 uint64_t end_message_id,
939 GNUNET_PSYC_MessageCallback message_cb, 1011 GNUNET_PSYC_MessageCallback message_cb,
1012 GNUNET_PSYC_MessagePartCallback message_part_cb,
940 GNUNET_PSYC_FinishCallback finish_cb, 1013 GNUNET_PSYC_FinishCallback finish_cb,
941 void *cls); 1014 void *cls);
942 1015
diff --git a/src/include/gnunet_psyc_util_lib.h b/src/include/gnunet_psyc_util_lib.h
index f356b245b..b71f52910 100644
--- a/src/include/gnunet_psyc_util_lib.h
+++ b/src/include/gnunet_psyc_util_lib.h
@@ -55,12 +55,36 @@ extern "C"
55 * @return Message header with size information, 55 * @return Message header with size information,
56 * followed by the message parts. 56 * followed by the message parts.
57 */ 57 */
58struct GNUNET_MessageHeader * 58struct GNUNET_PSYC_Message *
59GNUNET_PSYC_message_create (const char *method_name, 59GNUNET_PSYC_message_create (const char *method_name,
60 const struct GNUNET_ENV_Environment *env, 60 const struct GNUNET_ENV_Environment *env,
61 const void *data, 61 const void *data,
62 size_t data_size); 62 size_t data_size);
63 63
64/**
65 * Parse PSYC message.
66 *
67 * @param msg
68 * The PSYC message to parse.
69 * @param env
70 * The environment for the message with a list of modifiers.
71 * @param[out] method_name
72 * Pointer to the method name inside @a pmsg.
73 * @param[out] data
74 * Pointer to data inside @a pmsg.
75 * @param[out] data_size
76 * Size of @data is written here.
77 *
78 * @return #GNUNET_OK on success,
79 * #GNUNET_SYSERR on parse error.
80 */
81int
82GNUNET_PSYC_message_parse (const struct GNUNET_PSYC_Message *msg,
83 const char **method_name,
84 struct GNUNET_ENV_Environment *env,
85 const void **data,
86 uint16_t *data_size);
87
64 88
65void 89void
66GNUNET_PSYC_log_message (enum GNUNET_ErrorType kind, 90GNUNET_PSYC_log_message (enum GNUNET_ErrorType kind,
@@ -150,7 +174,7 @@ struct GNUNET_PSYC_ReceiveHandle;
150 */ 174 */
151struct GNUNET_PSYC_ReceiveHandle * 175struct GNUNET_PSYC_ReceiveHandle *
152GNUNET_PSYC_receive_create (GNUNET_PSYC_MessageCallback message_cb, 176GNUNET_PSYC_receive_create (GNUNET_PSYC_MessageCallback message_cb,
153 GNUNET_PSYC_MessageCallback hist_message_cb, 177 GNUNET_PSYC_MessagePartCallback message_part_cb,
154 void *cb_cls); 178 void *cb_cls);
155 179
156 180
diff --git a/src/include/gnunet_social_service.h b/src/include/gnunet_social_service.h
index f8b24c161..ca1578820 100644
--- a/src/include/gnunet_social_service.h
+++ b/src/include/gnunet_social_service.h
@@ -81,6 +81,8 @@ struct GNUNET_SOCIAL_Slicer;
81 * 81 *
82 * @param cls 82 * @param cls
83 * Closure. 83 * Closure.
84 * @param msg
85 * Message part, as it arrived from the network.
84 * @param message_id 86 * @param message_id
85 * Message counter, monotonically increasing from 1. 87 * Message counter, monotonically increasing from 1.
86 * @param nym 88 * @param nym
@@ -92,12 +94,53 @@ struct GNUNET_SOCIAL_Slicer;
92 * Original method name from PSYC. 94 * Original method name from PSYC.
93 * May be more specific than the registered method name due to 95 * May be more specific than the registered method name due to
94 * try-and-slice matching. 96 * try-and-slice matching.
95 * @param env 97 */
96 * Environment with operations and variables for the message. 98typedef void
97 * Only set for the first call of this function for each @a message_id, 99(*GNUNET_SOCIAL_MethodCallback) (void *cls,
98 * NULL when notifying about further data fragments. 100 const struct GNUNET_PSYC_MessageMethod *msg,
99 * It has to be freed using GNUNET_ENV_environment_destroy() 101 uint64_t message_id,
100 * when it is not needed anymore. 102 uint32_t flags,
103 const struct GNUNET_SOCIAL_Nym *nym,
104 const char *method_name);
105
106
107/**
108 * Function called upon receiving a data fragment of a message.
109 *
110 * @param cls
111 * Closure.
112 * @param message_id
113 * Message ID this data fragment belongs to.
114 * @param msg
115 * Message part, as it arrived from the network.
116 * @param oper
117 * Operation to perform.
118 * @param name
119 * Name of the modifier.
120 * @param value
121 * Value of the modifier.
122 * @param value_size
123 * Size of @value.
124 */
125typedef void
126(*GNUNET_SOCIAL_ModifierCallback) (void *cls,
127 const struct GNUNET_PSYC_MessageModifier *msg,
128 uint64_t message_id,
129 enum GNUNET_ENV_Operator oper,
130 const char *name,
131 const void *value,
132 uint16_t value_size);
133
134
135/**
136 * Function called upon receiving a data fragment of a message.
137 *
138 * @param cls
139 * Closure.
140 * @param message_id
141 * Message ID this data fragment belongs to.
142 * @param msg
143 * Message part, as it arrived from the network.
101 * @param data_offset 144 * @param data_offset
102 * Byte offset of @a data in the overall data of the method. 145 * Byte offset of @a data in the overall data of the method.
103 * @param data_size 146 * @param data_size
@@ -106,21 +149,37 @@ struct GNUNET_SOCIAL_Slicer;
106 * Data stream given to the method. 149 * Data stream given to the method.
107 * @param end 150 * @param end
108 * End of message? 151 * End of message?
109 * #GNUNET_NO if there are further fragments, 152 * #GNUNET_NO if there are further fragments,
110 * #GNUNET_YES if this is the last fragment, 153 * #GNUNET_YES if this is the last fragment,
111 * #GNUNET_SYSERR indicates the message was cancelled by the sender. 154 * #GNUNET_SYSERR indicates the message was cancelled by the sender.
112 */ 155 */
113typedef void 156typedef void
114(*GNUNET_SOCIAL_MethodCallback) (void *cls, 157(*GNUNET_SOCIAL_DataCallback) (void *cls,
115 uint64_t message_id, 158 const struct GNUNET_MessageHeader *msg,
116 uint32_t flags, 159 uint64_t message_id,
117 const struct GNUNET_SOCIAL_Nym *nym, 160 uint64_t data_offset,
118 const char *method_name, 161 const void *data,
119 struct GNUNET_ENV_Environment *env, 162 uint16_t data_size);
120 uint64_t data_offset, 163
121 size_t data_size, 164
122 const void *data, 165/**
123 int end); 166 * End of message.
167 *
168 * @param cls
169 * Closure.
170 * @param msg
171 * Message part, as it arrived from the network.
172 * @param message_id
173 * Message ID this data fragment belongs to.
174 * @param cancelled.
175 * #GNUNET_YES if the message was cancelled,
176 * #GNUNET_NO if the message is complete.
177 */
178typedef void
179(*GNUNET_SOCIAL_EndOfMessageCallback) (void *cls,
180 const struct GNUNET_MessageHeader *msg,
181 uint64_t message_id,
182 uint8_t cancelled);
124 183
125 184
126/** 185/**
@@ -148,20 +207,27 @@ void
148GNUNET_SOCIAL_slicer_add (struct GNUNET_SOCIAL_Slicer *slicer, 207GNUNET_SOCIAL_slicer_add (struct GNUNET_SOCIAL_Slicer *slicer,
149 const char *method_name, 208 const char *method_name,
150 GNUNET_SOCIAL_MethodCallback method_cb, 209 GNUNET_SOCIAL_MethodCallback method_cb,
210 GNUNET_SOCIAL_ModifierCallback modifier_cb,
211 GNUNET_SOCIAL_DataCallback data_cb,
212 GNUNET_SOCIAL_EndOfMessageCallback eom_cb,
151 void *cls); 213 void *cls);
152 214
153 215
154/** 216/**
155 * Remove a registered method from the try-and-slice instance. 217 * Remove a registered method handler from the try-and-slice instance.
156 * 218 *
157 * @param slicer The try-and-slice instance. 219 * @param slicer The try-and-slice instance.
158 * @param method_name Name of the method to remove. 220 * @param method_name Name of the method to remove.
159 * @param method Method handler. 221 * @param method Method handler.
160 */ 222 */
161void 223int
162GNUNET_SOCIAL_slicer_remove (struct GNUNET_SOCIAL_Slicer *slicer, 224GNUNET_SOCIAL_slicer_remove (struct GNUNET_SOCIAL_Slicer *slicer,
163 const char *method_name, 225 const char *method_name,
164 GNUNET_SOCIAL_MethodCallback method_cb); 226 GNUNET_SOCIAL_MethodCallback method_cb,
227 GNUNET_SOCIAL_ModifierCallback modifier_cb,
228 GNUNET_SOCIAL_DataCallback data_cb,
229 GNUNET_SOCIAL_EndOfMessageCallback eom_cb);
230
165 231
166/** 232/**
167 * Destroy a given try-and-slice instance. 233 * Destroy a given try-and-slice instance.
@@ -257,7 +323,7 @@ typedef void
257 */ 323 */
258struct GNUNET_SOCIAL_Host * 324struct GNUNET_SOCIAL_Host *
259GNUNET_SOCIAL_host_enter (const struct GNUNET_CONFIGURATION_Handle *cfg, 325GNUNET_SOCIAL_host_enter (const struct GNUNET_CONFIGURATION_Handle *cfg,
260 struct GNUNET_IDENTITY_Ego *ego, 326 const struct GNUNET_IDENTITY_Ego *ego,
261 const struct GNUNET_CRYPTO_EddsaPrivateKey *place_key, 327 const struct GNUNET_CRYPTO_EddsaPrivateKey *place_key,
262 enum GNUNET_PSYC_Policy policy, 328 enum GNUNET_PSYC_Policy policy,
263 struct GNUNET_SOCIAL_Slicer *slicer, 329 struct GNUNET_SOCIAL_Slicer *slicer,
@@ -268,17 +334,32 @@ GNUNET_SOCIAL_host_enter (const struct GNUNET_CONFIGURATION_Handle *cfg,
268 334
269 335
270/** 336/**
271 * Admit @a nym to the place. 337 * Decision whether to admit @a nym into the place or refuse entry.
272 *
273 * The @a nym reference will remain valid until either the @a host or @a nym
274 * leaves the place.
275 * 338 *
276 * @param host Host of the place. 339 * @param hst
277 * @param nym Handle for the entity that wants to enter. 340 * Host of the place.
341 * @param nym
342 * Handle for the entity that wanted to enter.
343 * @param is_admitted
344 * #GNUNET_YES if @a nym is admitted,
345 * #GNUNET_NO if @a nym is refused entry,
346 * #GNUNET_SYSERR if we cannot answer the request.
347 * @param method_name
348 * Method name for the rejection message.
349 * @param env
350 * Environment containing variables for the message, or NULL.
351 * @param data
352 * Data for the rejection message to send back.
353 * @param data_size
354 * Number of bytes in @a data for method.
355 * @return #GNUNET_OK on success,
356 * #GNUNET_SYSERR if the message is too large.
278 */ 357 */
279void 358int
280GNUNET_SOCIAL_host_admit (struct GNUNET_SOCIAL_Host *host, 359GNUNET_SOCIAL_host_entry_decision (struct GNUNET_SOCIAL_Host *hst,
281 struct GNUNET_SOCIAL_Nym *nym); 360 struct GNUNET_SOCIAL_Nym *nym,
361 int is_admitted,
362 const struct GNUNET_PSYC_Message *entry_resp);
282 363
283 364
284/** 365/**
@@ -297,35 +378,17 @@ GNUNET_SOCIAL_host_eject (struct GNUNET_SOCIAL_Host *host,
297 378
298 379
299/** 380/**
300 * Refuse @a nym entry into the place.
301 *
302 * @param host Host of the place.
303 * @param nym Handle for the entity that wanted to enter.
304 * @param method_name Method name for the rejection message.
305 * @param env Environment containing variables for the message, or NULL.
306 * @param data Data for the rejection message to send back.
307 * @param data_size Number of bytes in @a data for method.
308 */
309void
310GNUNET_SOCIAL_host_refuse_entry (struct GNUNET_SOCIAL_Host *host,
311 struct GNUNET_SOCIAL_Nym *nym,
312 const char *method_name,
313 const struct GNUNET_ENV_Environment *env,
314 const void *data,
315 size_t data_size);
316
317
318/**
319 * Get the public key of a @a nym. 381 * Get the public key of a @a nym.
320 * 382 *
321 * Suitable, for example, to be used with GNUNET_NAMESTORE_zone_to_name(). 383 * Suitable, for example, to be used with GNUNET_NAMESTORE_zone_to_name().
322 * 384 *
323 * @param nym Pseudonym to map to a cryptographic identifier. 385 * @param nym
324 * @param[out] nym_key Set to the public key of the nym. 386 * Pseudonym to map to a cryptographic identifier.
387 *
388 * @return Public key of nym;
325 */ 389 */
326void 390struct GNUNET_CRYPTO_EcdsaPublicKey *
327GNUNET_SOCIAL_nym_get_key (struct GNUNET_SOCIAL_Nym *nym, 391GNUNET_SOCIAL_nym_get_key (struct GNUNET_SOCIAL_Nym *nym);
328 struct GNUNET_CRYPTO_EddsaPublicKey *nym_key);
329 392
330 393
331/** 394/**
@@ -418,9 +481,20 @@ GNUNET_SOCIAL_host_announce (struct GNUNET_SOCIAL_Host *host,
418 481
419 482
420/** 483/**
484 * Resume transmitting announcement.
485 *
486 * @param a
487 * The announcement to resume.
488 */
489void
490GNUNET_SOCIAL_host_announce_resume (struct GNUNET_SOCIAL_Announcement *a);
491
492
493/**
421 * Cancel announcement. 494 * Cancel announcement.
422 * 495 *
423 * @param a The announcement to cancel. 496 * @param a
497 * The announcement to cancel.
424 */ 498 */
425void 499void
426GNUNET_SOCIAL_host_announce_cancel (struct GNUNET_SOCIAL_Announcement *a); 500GNUNET_SOCIAL_host_announce_cancel (struct GNUNET_SOCIAL_Announcement *a);
@@ -431,7 +505,8 @@ GNUNET_SOCIAL_host_announce_cancel (struct GNUNET_SOCIAL_Announcement *a);
431 * 505 *
432 * The returned handle can be used to access the place API. 506 * The returned handle can be used to access the place API.
433 * 507 *
434 * @param host Handle for the host. 508 * @param host
509 * Handle for the host.
435 * 510 *
436 * @return Handle for the hosted place, valid as long as @a host is valid. 511 * @return Handle for the hosted place, valid as long as @a host is valid.
437 */ 512 */
@@ -444,11 +519,21 @@ GNUNET_SOCIAL_host_get_place (struct GNUNET_SOCIAL_Host *host);
444 * 519 *
445 * Invalidates host handle. 520 * Invalidates host handle.
446 * 521 *
447 * @param host Host leaving the place. 522 * @param host
448 * @param keep_active Keep the place active after last host disconnected. 523 * Host leaving the place.
524 * @param keep_active
525 * Keep the place active after last host disconnected.
526 * @param leave_cb
527 * Function called after the host left the place
528 * and disconnected from the social service.
529 * @param leave_cls
530 * Closure for @a leave_cb.
449 */ 531 */
450void 532void
451GNUNET_SOCIAL_host_leave (struct GNUNET_SOCIAL_Host *host, int keep_active); 533GNUNET_SOCIAL_host_leave (struct GNUNET_SOCIAL_Host *host,
534 int keep_active,
535 GNUNET_ContinuationCallback leave_cb,
536 void *leave_cls);
452 537
453 538
454/** 539/**
@@ -493,13 +578,10 @@ typedef void
493 * @param data 578 * @param data
494 * Payload of the message. 579 * Payload of the message.
495 */ 580 */
496typedef int 581typedef void
497(*GNUNET_SOCIAL_EntryDecisionCallback) (void *cls, 582(*GNUNET_SOCIAL_EntryDecisionCallback) (void *cls,
498 int is_admitted, 583 int is_admitted,
499 const char *method_name, 584 const struct GNUNET_PSYC_Message *entry_resp);
500 struct GNUNET_ENV_Environment *env,
501 size_t data_size,
502 const void *data);
503 585
504 586
505/** 587/**
@@ -521,15 +603,12 @@ typedef int
521 */ 603 */
522struct GNUNET_SOCIAL_Guest * 604struct GNUNET_SOCIAL_Guest *
523GNUNET_SOCIAL_guest_enter (const struct GNUNET_CONFIGURATION_Handle *cfg, 605GNUNET_SOCIAL_guest_enter (const struct GNUNET_CONFIGURATION_Handle *cfg,
524 struct GNUNET_IDENTITY_Ego *ego, 606 const struct GNUNET_IDENTITY_Ego *ego,
525 struct GNUNET_CRYPTO_EddsaPublicKey *place_key, 607 const struct GNUNET_CRYPTO_EddsaPublicKey *place_key,
526 struct GNUNET_PeerIdentity *origin, 608 const struct GNUNET_PeerIdentity *origin,
527 uint32_t relay_count, 609 uint32_t relay_count,
528 struct GNUNET_PeerIdentity *relays, 610 const struct GNUNET_PeerIdentity *relays,
529 const char *method_name, 611 const struct GNUNET_PSYC_Message *entry_msg,
530 const struct GNUNET_ENV_Environment *env,
531 const void *data,
532 size_t data_size,
533 struct GNUNET_SOCIAL_Slicer *slicer, 612 struct GNUNET_SOCIAL_Slicer *slicer,
534 GNUNET_SOCIAL_GuestEnterCallback local_enter_cb, 613 GNUNET_SOCIAL_GuestEnterCallback local_enter_cb,
535 GNUNET_SOCIAL_EntryDecisionCallback entry_decision_cb, 614 GNUNET_SOCIAL_EntryDecisionCallback entry_decision_cb,
@@ -558,10 +637,7 @@ struct GNUNET_SOCIAL_Guest *
558GNUNET_SOCIAL_guest_enter_by_name (const struct GNUNET_CONFIGURATION_Handle *cfg, 637GNUNET_SOCIAL_guest_enter_by_name (const struct GNUNET_CONFIGURATION_Handle *cfg,
559 struct GNUNET_IDENTITY_Ego *ego, 638 struct GNUNET_IDENTITY_Ego *ego,
560 char *gns_name, 639 char *gns_name,
561 const char *method_name, 640 const struct GNUNET_PSYC_Message *join_msg,
562 const struct GNUNET_ENV_Environment *env,
563 const void *data,
564 size_t data_size,
565 struct GNUNET_SOCIAL_Slicer *slicer, 641 struct GNUNET_SOCIAL_Slicer *slicer,
566 GNUNET_SOCIAL_GuestEnterCallback local_enter_cb, 642 GNUNET_SOCIAL_GuestEnterCallback local_enter_cb,
567 GNUNET_SOCIAL_EntryDecisionCallback entry_decision_cb, 643 GNUNET_SOCIAL_EntryDecisionCallback entry_decision_cb,
@@ -612,9 +688,20 @@ GNUNET_SOCIAL_guest_talk (struct GNUNET_SOCIAL_Guest *guest,
612 688
613 689
614/** 690/**
691 * Resume talking to the host of the place.
692 *
693 * @param tr
694 * Talk request to resume.
695 */
696void
697GNUNET_SOCIAL_guest_talk_resume (struct GNUNET_SOCIAL_TalkRequest *tr);
698
699
700/**
615 * Cancel talking to the host of the place. 701 * Cancel talking to the host of the place.
616 * 702 *
617 * @param tr Talk request to cancel. 703 * @param tr
704 * Talk request to cancel.
618 */ 705 */
619void 706void
620GNUNET_SOCIAL_guest_talk_cancel (struct GNUNET_SOCIAL_TalkRequest *tr); 707GNUNET_SOCIAL_guest_talk_cancel (struct GNUNET_SOCIAL_TalkRequest *tr);
@@ -625,11 +712,21 @@ GNUNET_SOCIAL_guest_talk_cancel (struct GNUNET_SOCIAL_TalkRequest *tr);
625 * 712 *
626 * Notifies the owner of the place about leaving, and destroys the place handle. 713 * Notifies the owner of the place about leaving, and destroys the place handle.
627 * 714 *
628 * @param place Place to leave permanently. 715 * @param place
629 * @param keep_active Keep place active after last application disconnected. 716 * Place to leave permanently.
717 * @param keep_active
718 * Keep place active after last application disconnected.
719 * @param leave_cb
720 * Function called after the guest left the place
721 * and disconnected from the social service.
722 * @param leave_cls
723 * Closure for @a leave_cb.
630 */ 724 */
631void 725void
632GNUNET_SOCIAL_guest_leave (struct GNUNET_SOCIAL_Guest *guest, int keep_active); 726GNUNET_SOCIAL_guest_leave (struct GNUNET_SOCIAL_Guest *guest,
727 int keep_active,
728 GNUNET_ContinuationCallback leave_cb,
729 void *leave_cls);
633 730
634 731
635/** 732/**
diff --git a/src/multicast/gnunet-service-multicast.c b/src/multicast/gnunet-service-multicast.c
index 1bb27f96e..1b8e5c8b6 100644
--- a/src/multicast/gnunet-service-multicast.c
+++ b/src/multicast/gnunet-service-multicast.c
@@ -423,6 +423,7 @@ client_origin_start (void *cls, struct GNUNET_SERVER_Client *client,
423 { 423 {
424 orig = GNUNET_new (struct Origin); 424 orig = GNUNET_new (struct Origin);
425 orig->priv_key = msg->group_key; 425 orig->priv_key = msg->group_key;
426 orig->max_fragment_id = GNUNET_ntohll (msg->max_fragment_id);
426 grp = &orig->grp; 427 grp = &orig->grp;
427 grp->is_origin = GNUNET_YES; 428 grp->is_origin = GNUNET_YES;
428 grp->pub_key = pub_key; 429 grp->pub_key = pub_key;
@@ -482,6 +483,7 @@ client_member_join (void *cls, struct GNUNET_SERVER_Client *client,
482 mem->priv_key = msg->member_key; 483 mem->priv_key = msg->member_key;
483 mem->pub_key = mem_pub_key; 484 mem->pub_key = mem_pub_key;
484 mem->pub_key_hash = mem_pub_key_hash; 485 mem->pub_key_hash = mem_pub_key_hash;
486 mem->max_fragment_id = 0; // FIXME
485 487
486 grp = &mem->grp; 488 grp = &mem->grp;
487 grp->is_origin = GNUNET_NO; 489 grp->is_origin = GNUNET_NO;
@@ -663,7 +665,7 @@ client_multicast_message (void *cls, struct GNUNET_SERVER_Client *client,
663 struct GNUNET_MULTICAST_MessageHeader * 665 struct GNUNET_MULTICAST_MessageHeader *
664 msg = (struct GNUNET_MULTICAST_MessageHeader *) m; 666 msg = (struct GNUNET_MULTICAST_MessageHeader *) m;
665 667
666 msg->fragment_id = GNUNET_htonll (orig->max_fragment_id++); 668 msg->fragment_id = GNUNET_htonll (++orig->max_fragment_id);
667 msg->purpose.size = htonl (sizeof (*msg) + ntohs (m->size) 669 msg->purpose.size = htonl (sizeof (*msg) + ntohs (m->size)
668 - sizeof (msg->header) 670 - sizeof (msg->header)
669 - sizeof (msg->hop_counter) 671 - sizeof (msg->hop_counter)
@@ -699,8 +701,7 @@ client_multicast_request (void *cls, struct GNUNET_SERVER_Client *client,
699 struct GNUNET_MULTICAST_RequestHeader * 701 struct GNUNET_MULTICAST_RequestHeader *
700 req = (struct GNUNET_MULTICAST_RequestHeader *) m; 702 req = (struct GNUNET_MULTICAST_RequestHeader *) m;
701 703
702 req->fragment_id = GNUNET_ntohll (mem->max_fragment_id++); 704 req->fragment_id = GNUNET_ntohll (++mem->max_fragment_id);
703
704 req->purpose.size = htonl (sizeof (*req) + ntohs (m->size) 705 req->purpose.size = htonl (sizeof (*req) + ntohs (m->size)
705 - sizeof (req->header) 706 - sizeof (req->header)
706 - sizeof (req->member_key) 707 - sizeof (req->member_key)
diff --git a/src/multicast/multicast_api.c b/src/multicast/multicast_api.c
index d2a0412bb..fb2630081 100644
--- a/src/multicast/multicast_api.c
+++ b/src/multicast/multicast_api.c
@@ -88,6 +88,16 @@ struct GNUNET_MULTICAST_Group
88 void *cb_cls; 88 void *cb_cls;
89 89
90 /** 90 /**
91 * Function called after disconnected from the service.
92 */
93 GNUNET_ContinuationCallback disconnect_cb;
94
95 /**
96 * Closure for @a disconnect_cb.
97 */
98 void *disconnect_cls;
99
100 /**
91 * Are we currently transmitting a message? 101 * Are we currently transmitting a message?
92 */ 102 */
93 uint8_t in_transmit; 103 uint8_t in_transmit;
@@ -96,6 +106,12 @@ struct GNUNET_MULTICAST_Group
96 * Is this the origin or a member? 106 * Is this the origin or a member?
97 */ 107 */
98 uint8_t is_origin; 108 uint8_t is_origin;
109
110 /**
111 * Is this channel in the process of disconnecting from the service?
112 * #GNUNET_YES or #GNUNET_NO
113 */
114 uint8_t is_disconnecting;
99}; 115};
100 116
101 117
@@ -320,8 +336,9 @@ member_recv_join_decision (void *cls,
320 mem->join_dcsn_cb (grp->cb_cls, is_admitted, &hdcsn->peer, 336 mem->join_dcsn_cb (grp->cb_cls, is_admitted, &hdcsn->peer,
321 relay_count, relays, join_resp); 337 relay_count, relays, join_resp);
322 338
323 if (GNUNET_YES != is_admitted) 339 // FIXME:
324 GNUNET_MULTICAST_member_part (mem); 340 //if (GNUNET_YES != is_admitted)
341 // GNUNET_MULTICAST_member_part (mem);
325} 342}
326 343
327 344
@@ -371,6 +388,33 @@ static struct GNUNET_CLIENT_MANAGER_MessageHandler member_handlers[] =
371}; 388};
372 389
373 390
391static void
392group_cleanup (struct GNUNET_MULTICAST_Group *grp)
393{
394 GNUNET_free (grp->connect_msg);
395 if (NULL != grp->disconnect_cb)
396 grp->disconnect_cb (grp->disconnect_cls);
397}
398
399
400static void
401origin_cleanup (void *cls)
402{
403 struct GNUNET_MULTICAST_Origin *orig = cls;
404 group_cleanup (&orig->grp);
405 GNUNET_free (orig);
406}
407
408
409static void
410member_cleanup (void *cls)
411{
412 struct GNUNET_MULTICAST_Member *mem = cls;
413 group_cleanup (&mem->grp);
414 GNUNET_free (mem);
415}
416
417
374/** 418/**
375 * Function to call with the decision made for a join request. 419 * Function to call with the decision made for a join request.
376 * 420 *
@@ -565,10 +609,18 @@ GNUNET_MULTICAST_origin_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
565 * @param origin Multicast group to stop. 609 * @param origin Multicast group to stop.
566 */ 610 */
567void 611void
568GNUNET_MULTICAST_origin_stop (struct GNUNET_MULTICAST_Origin *orig) 612GNUNET_MULTICAST_origin_stop (struct GNUNET_MULTICAST_Origin *orig,
613 GNUNET_ContinuationCallback stop_cb,
614 void *stop_cls)
569{ 615{
570 GNUNET_CLIENT_MANAGER_disconnect (orig->grp.client, GNUNET_YES); 616 struct GNUNET_MULTICAST_Group *grp = &orig->grp;
571 GNUNET_free (orig); 617
618 grp->is_disconnecting = GNUNET_YES;
619 grp->disconnect_cb = stop_cb;
620 grp->disconnect_cls = stop_cls;
621
622 GNUNET_CLIENT_MANAGER_disconnect (orig->grp.client, GNUNET_YES,
623 &origin_cleanup, orig);
572} 624}
573 625
574 626
@@ -774,10 +826,18 @@ GNUNET_MULTICAST_member_join (const struct GNUNET_CONFIGURATION_Handle *cfg,
774 * @param member Membership handle. 826 * @param member Membership handle.
775 */ 827 */
776void 828void
777GNUNET_MULTICAST_member_part (struct GNUNET_MULTICAST_Member *mem) 829GNUNET_MULTICAST_member_part (struct GNUNET_MULTICAST_Member *mem,
830 GNUNET_ContinuationCallback part_cb,
831 void *part_cls)
778{ 832{
779 GNUNET_CLIENT_MANAGER_disconnect (mem->grp.client, GNUNET_YES); 833 struct GNUNET_MULTICAST_Group *grp = &mem->grp;
780 GNUNET_free (mem); 834
835 grp->is_disconnecting = GNUNET_YES;
836 grp->disconnect_cb = part_cb;
837 grp->disconnect_cls = part_cls;
838
839 GNUNET_CLIENT_MANAGER_disconnect (mem->grp.client, GNUNET_YES,
840 &member_cleanup, mem);
781} 841}
782 842
783 843
diff --git a/src/psyc/gnunet-service-psyc.c b/src/psyc/gnunet-service-psyc.c
index 866275a79..8fc080baf 100644
--- a/src/psyc/gnunet-service-psyc.c
+++ b/src/psyc/gnunet-service-psyc.c
@@ -168,7 +168,7 @@ struct FragmentQueue
168 * Is the message queued for delivery to the client? 168 * Is the message queued for delivery to the client?
169 * i.e. added to the recv_msgs queue 169 * i.e. added to the recv_msgs queue
170 */ 170 */
171 uint8_t queued; 171 uint8_t is_queued;
172}; 172};
173 173
174 174
@@ -382,7 +382,7 @@ struct Slave
382 /** 382 /**
383 * Join request to be transmitted to the master on join. 383 * Join request to be transmitted to the master on join.
384 */ 384 */
385 struct GNUNET_MessageHeader *join_req; 385 struct GNUNET_PSYC_Message *join_msg;
386 386
387 /** 387 /**
388 * Join decision received from multicast. 388 * Join decision received from multicast.
@@ -435,7 +435,7 @@ cleanup_master (struct Master *mst)
435 struct Channel *chn = &mst->chn; 435 struct Channel *chn = &mst->chn;
436 436
437 if (NULL != mst->origin) 437 if (NULL != mst->origin)
438 GNUNET_MULTICAST_origin_stop (mst->origin); 438 GNUNET_MULTICAST_origin_stop (mst->origin, NULL, NULL); // FIXME
439 GNUNET_CONTAINER_multihashmap_destroy (mst->join_reqs); 439 GNUNET_CONTAINER_multihashmap_destroy (mst->join_reqs);
440 GNUNET_CONTAINER_multihashmap_remove (masters, &chn->pub_key_hash, chn); 440 GNUNET_CONTAINER_multihashmap_remove (masters, &chn->pub_key_hash, chn);
441} 441}
@@ -462,12 +462,21 @@ cleanup_slave (struct Slave *slv)
462 } 462 }
463 GNUNET_CONTAINER_multihashmap_remove (slaves, &chn->pub_key_hash, slv); 463 GNUNET_CONTAINER_multihashmap_remove (slaves, &chn->pub_key_hash, slv);
464 464
465 if (NULL != slv->join_req) 465 if (NULL != slv->join_msg)
466 GNUNET_free (slv->join_req); 466 {
467 GNUNET_free (slv->join_msg);
468 slv->join_msg = NULL;
469 }
467 if (NULL != slv->relays) 470 if (NULL != slv->relays)
471 {
468 GNUNET_free (slv->relays); 472 GNUNET_free (slv->relays);
473 slv->relays = NULL;
474 }
469 if (NULL != slv->member) 475 if (NULL != slv->member)
470 GNUNET_MULTICAST_member_part (slv->member); 476 {
477 GNUNET_MULTICAST_member_part (slv->member, NULL, NULL); // FIXME
478 slv->member = NULL;
479 }
471 GNUNET_CONTAINER_multihashmap_remove (slaves, &chn->pub_key_hash, chn); 480 GNUNET_CONTAINER_multihashmap_remove (slaves, &chn->pub_key_hash, chn);
472} 481}
473 482
@@ -482,7 +491,10 @@ cleanup_channel (struct Channel *chn)
482 GNUNET_CONTAINER_multihashmap_remove_all (recv_cache, &chn->pub_key_hash); 491 GNUNET_CONTAINER_multihashmap_remove_all (recv_cache, &chn->pub_key_hash);
483 492
484 if (NULL != chn->store_op) 493 if (NULL != chn->store_op)
494 {
485 GNUNET_PSYCSTORE_operation_cancel (chn->store_op); 495 GNUNET_PSYCSTORE_operation_cancel (chn->store_op);
496 chn->store_op = NULL;
497 }
486 498
487 (GNUNET_YES == chn->is_master) 499 (GNUNET_YES == chn->is_master)
488 ? cleanup_master ((struct Master *) chn) 500 ? cleanup_master ((struct Master *) chn)
@@ -574,7 +586,7 @@ struct JoinMemTestClosure
574 struct GNUNET_CRYPTO_EcdsaPublicKey slave_key; 586 struct GNUNET_CRYPTO_EcdsaPublicKey slave_key;
575 struct Channel *chn; 587 struct Channel *chn;
576 struct GNUNET_MULTICAST_JoinHandle *jh; 588 struct GNUNET_MULTICAST_JoinHandle *jh;
577 struct MasterJoinRequest *master_join_req; 589 struct GNUNET_PSYC_JoinRequestMessage *join_msg;
578}; 590};
579 591
580 592
@@ -594,14 +606,14 @@ join_mem_test_cb (void *cls, int64_t result, const char *err_msg)
594 &slave_key_hash); 606 &slave_key_hash);
595 GNUNET_CONTAINER_multihashmap_put (mst->join_reqs, &slave_key_hash, jcls->jh, 607 GNUNET_CONTAINER_multihashmap_put (mst->join_reqs, &slave_key_hash, jcls->jh,
596 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); 608 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
597 client_send_msg (jcls->chn, &jcls->master_join_req->header); 609 client_send_msg (jcls->chn, &jcls->join_msg->header);
598 } 610 }
599 else 611 else
600 { 612 {
601 // FIXME: add relays 613 // FIXME: add relays
602 GNUNET_MULTICAST_join_decision (jcls->jh, result, 0, NULL, NULL); 614 GNUNET_MULTICAST_join_decision (jcls->jh, result, 0, NULL, NULL);
603 } 615 }
604 GNUNET_free (jcls->master_join_req); 616 GNUNET_free (jcls->join_msg);
605 GNUNET_free (jcls); 617 GNUNET_free (jcls);
606} 618}
607 619
@@ -633,7 +645,8 @@ mcast_recv_join_request (void *cls,
633 } 645 }
634 } 646 }
635 647
636 struct MasterJoinRequest *req = GNUNET_malloc (sizeof (*req) + join_msg_size); 648 struct GNUNET_PSYC_JoinRequestMessage *
649 req = GNUNET_malloc (sizeof (*req) + join_msg_size);
637 req->header.size = htons (sizeof (*req) + join_msg_size); 650 req->header.size = htons (sizeof (*req) + join_msg_size);
638 req->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_JOIN_REQUEST); 651 req->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_JOIN_REQUEST);
639 req->slave_key = *slave_key; 652 req->slave_key = *slave_key;
@@ -644,7 +657,7 @@ mcast_recv_join_request (void *cls,
644 jcls->slave_key = *slave_key; 657 jcls->slave_key = *slave_key;
645 jcls->chn = chn; 658 jcls->chn = chn;
646 jcls->jh = jh; 659 jcls->jh = jh;
647 jcls->master_join_req = req; 660 jcls->join_msg = req;
648 661
649 GNUNET_PSYCSTORE_membership_test (store, &chn->pub_key, slave_key, 662 GNUNET_PSYCSTORE_membership_test (store, &chn->pub_key, slave_key,
650 chn->max_message_id, 0, 663 chn->max_message_id, 0,
@@ -780,6 +793,7 @@ client_send_mcast_msg (struct Channel *chn,
780 pmsg->header.size = htons (psize); 793 pmsg->header.size = htons (psize);
781 pmsg->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE); 794 pmsg->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE);
782 pmsg->message_id = mmsg->message_id; 795 pmsg->message_id = mmsg->message_id;
796 pmsg->fragment_offset = mmsg->fragment_offset;
783 797
784 memcpy (&pmsg[1], &mmsg[1], size - sizeof (*mmsg)); 798 memcpy (&pmsg[1], &mmsg[1], size - sizeof (*mmsg));
785 client_send_msg (chn, &pmsg->header); 799 client_send_msg (chn, &pmsg->header);
@@ -810,6 +824,7 @@ client_send_mcast_req (struct Master *mst,
810 pmsg->header.size = htons (psize); 824 pmsg->header.size = htons (psize);
811 pmsg->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE); 825 pmsg->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE);
812 pmsg->message_id = req->request_id; 826 pmsg->message_id = req->request_id;
827 pmsg->fragment_offset = req->fragment_offset;
813 pmsg->flags = htonl (GNUNET_PSYC_MESSAGE_REQUEST); 828 pmsg->flags = htonl (GNUNET_PSYC_MESSAGE_REQUEST);
814 829
815 memcpy (&pmsg[1], &req[1], size - sizeof (*req)); 830 memcpy (&pmsg[1], &req[1], size - sizeof (*req));
@@ -870,11 +885,12 @@ fragment_queue_insert (struct Channel *chn,
870 { 885 {
871 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 886 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
872 "%p Adding message fragment to cache. " 887 "%p Adding message fragment to cache. "
873 "message_id: %" PRIu64 ", fragment_id: %" PRIu64 ", " 888 "message_id: %" PRIu64 ", fragment_id: %" PRIu64 "\n",
874 "header_size: %" PRIu64 " + %u).\n",
875 chn, GNUNET_ntohll (mmsg->message_id), 889 chn, GNUNET_ntohll (mmsg->message_id),
876 GNUNET_ntohll (mmsg->fragment_id), 890 GNUNET_ntohll (mmsg->fragment_id));
877 fragq->header_size, size); 891 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
892 "%p header_size: %" PRIu64 " + %u\n",
893 chn, fragq->header_size, size);
878 cache_entry = GNUNET_new (struct RecvCacheEntry); 894 cache_entry = GNUNET_new (struct RecvCacheEntry);
879 cache_entry->ref_count = 1; 895 cache_entry->ref_count = 1;
880 cache_entry->mmsg = GNUNET_malloc (size); 896 cache_entry->mmsg = GNUNET_malloc (size);
@@ -955,11 +971,11 @@ fragment_queue_insert (struct Channel *chn,
955 case MSG_FRAG_STATE_DATA: 971 case MSG_FRAG_STATE_DATA:
956 case MSG_FRAG_STATE_END: 972 case MSG_FRAG_STATE_END:
957 case MSG_FRAG_STATE_CANCEL: 973 case MSG_FRAG_STATE_CANCEL:
958 if (GNUNET_NO == fragq->queued) 974 if (GNUNET_NO == fragq->is_queued)
959 { 975 {
960 GNUNET_CONTAINER_heap_insert (chn->recv_msgs, NULL, 976 GNUNET_CONTAINER_heap_insert (chn->recv_msgs, NULL,
961 GNUNET_ntohll (mmsg->message_id)); 977 GNUNET_ntohll (mmsg->message_id));
962 fragq->queued = GNUNET_YES; 978 fragq->is_queued = GNUNET_YES;
963 } 979 }
964 } 980 }
965 981
@@ -1034,7 +1050,7 @@ fragment_queue_run (struct Channel *chn, uint64_t msg_id,
1034 if (MSG_FRAG_STATE_END <= fragq->state) 1050 if (MSG_FRAG_STATE_END <= fragq->state)
1035 { 1051 {
1036 struct GNUNET_HashCode msg_id_hash; 1052 struct GNUNET_HashCode msg_id_hash;
1037 hash_key_from_nll (&msg_id_hash, msg_id); 1053 hash_key_from_hll (&msg_id_hash, msg_id);
1038 1054
1039 GNUNET_CONTAINER_multihashmap_remove (chn->recv_frags, &msg_id_hash, fragq); 1055 GNUNET_CONTAINER_multihashmap_remove (chn->recv_frags, &msg_id_hash, fragq);
1040 GNUNET_CONTAINER_heap_destroy (fragq->fragments); 1056 GNUNET_CONTAINER_heap_destroy (fragq->fragments);
@@ -1042,7 +1058,7 @@ fragment_queue_run (struct Channel *chn, uint64_t msg_id,
1042 } 1058 }
1043 else 1059 else
1044 { 1060 {
1045 fragq->queued = GNUNET_NO; 1061 fragq->is_queued = GNUNET_NO;
1046 } 1062 }
1047} 1063}
1048 1064
@@ -1331,13 +1347,18 @@ store_recv_slave_counters (void *cls, int result, uint64_t max_fragment_id,
1331 = GNUNET_MULTICAST_member_join (cfg, &chn->pub_key, &slv->priv_key, 1347 = GNUNET_MULTICAST_member_join (cfg, &chn->pub_key, &slv->priv_key,
1332 &slv->origin, 1348 &slv->origin,
1333 slv->relay_count, slv->relays, 1349 slv->relay_count, slv->relays,
1334 slv->join_req, 1350 &slv->join_msg->header,
1335 &mcast_recv_join_request, 1351 &mcast_recv_join_request,
1336 &mcast_recv_join_decision, 1352 &mcast_recv_join_decision,
1337 &mcast_recv_membership_test, 1353 &mcast_recv_membership_test,
1338 &mcast_recv_replay_fragment, 1354 &mcast_recv_replay_fragment,
1339 &mcast_recv_replay_message, 1355 &mcast_recv_replay_message,
1340 &mcast_recv_message, chn); 1356 &mcast_recv_message, chn);
1357 if (NULL != slv->join_msg)
1358 {
1359 GNUNET_free (slv->join_msg);
1360 slv->join_msg = NULL;
1361 }
1341 } 1362 }
1342 else 1363 else
1343 { 1364 {
@@ -1435,6 +1456,7 @@ client_recv_slave_join (void *cls, struct GNUNET_SERVER_Client *client,
1435{ 1456{
1436 const struct SlaveJoinRequest *req 1457 const struct SlaveJoinRequest *req
1437 = (const struct SlaveJoinRequest *) msg; 1458 = (const struct SlaveJoinRequest *) msg;
1459 uint16_t req_size = ntohs (req->header.size);
1438 1460
1439 struct GNUNET_CRYPTO_EcdsaPublicKey slv_pub_key; 1461 struct GNUNET_CRYPTO_EcdsaPublicKey slv_pub_key;
1440 struct GNUNET_HashCode pub_key_hash, slv_pub_key_hash; 1462 struct GNUNET_HashCode pub_key_hash, slv_pub_key_hash;
@@ -1460,15 +1482,32 @@ client_recv_slave_join (void *cls, struct GNUNET_SERVER_Client *client,
1460 slv->pub_key_hash = slv_pub_key_hash; 1482 slv->pub_key_hash = slv_pub_key_hash;
1461 slv->origin = req->origin; 1483 slv->origin = req->origin;
1462 slv->relay_count = ntohl (req->relay_count); 1484 slv->relay_count = ntohl (req->relay_count);
1485
1486 const struct GNUNET_PeerIdentity *
1487 relays = (const struct GNUNET_PeerIdentity *) &req[1];
1488 uint16_t relay_size = slv->relay_count * sizeof (*relays);
1489 uint16_t join_msg_size = 0;
1490
1491 if (sizeof (*req) + relay_size + sizeof (struct GNUNET_MessageHeader)
1492 <= req_size)
1493 {
1494 join_msg_size = ntohs (slv->join_msg->header.size);
1495 slv->join_msg = GNUNET_malloc (join_msg_size);
1496 memcpy (slv->join_msg, ((char *) &req[1]) + relay_size, join_msg_size);
1497 }
1498 if (sizeof (*req) + relay_size + join_msg_size != req_size)
1499 {
1500 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1501 "%u + %u + %u != %u\n",
1502 sizeof (*req), relay_size, join_msg_size, req_size);
1503 GNUNET_break (0);
1504 GNUNET_SERVER_client_disconnect (client);
1505 return;
1506 }
1463 if (0 < slv->relay_count) 1507 if (0 < slv->relay_count)
1464 { 1508 {
1465 const struct GNUNET_PeerIdentity *relays 1509 slv->relays = GNUNET_malloc (relay_size);
1466 = (const struct GNUNET_PeerIdentity *) &req[1]; 1510 memcpy (slv->relays, &req[1], relay_size);
1467 slv->relays
1468 = GNUNET_malloc (slv->relay_count * sizeof (struct GNUNET_PeerIdentity));
1469 uint32_t i;
1470 for (i = 0; i < slv->relay_count; i++)
1471 memcpy (&slv->relays[i], &relays[i], sizeof (*relays));
1472 } 1511 }
1473 1512
1474 chn = &slv->chn; 1513 chn = &slv->chn;
@@ -1510,14 +1549,18 @@ client_recv_slave_join (void *cls, struct GNUNET_SERVER_Client *client,
1510 = GNUNET_MULTICAST_member_join (cfg, &chn->pub_key, &slv->priv_key, 1549 = GNUNET_MULTICAST_member_join (cfg, &chn->pub_key, &slv->priv_key,
1511 &slv->origin, 1550 &slv->origin,
1512 slv->relay_count, slv->relays, 1551 slv->relay_count, slv->relays,
1513 slv->join_req, 1552 &slv->join_msg->header,
1514 &mcast_recv_join_request, 1553 &mcast_recv_join_request,
1515 &mcast_recv_join_decision, 1554 &mcast_recv_join_decision,
1516 &mcast_recv_membership_test, 1555 &mcast_recv_membership_test,
1517 &mcast_recv_replay_fragment, 1556 &mcast_recv_replay_fragment,
1518 &mcast_recv_replay_message, 1557 &mcast_recv_replay_message,
1519 &mcast_recv_message, chn); 1558 &mcast_recv_message, chn);
1520 1559 if (NULL != slv->join_msg)
1560 {
1561 GNUNET_free (slv->join_msg);
1562 slv->join_msg = NULL;
1563 }
1521 } 1564 }
1522 else if (NULL != slv->join_dcsn) 1565 else if (NULL != slv->join_dcsn)
1523 { 1566 {
@@ -1549,13 +1592,14 @@ struct JoinDecisionClosure
1549 1592
1550 1593
1551/** 1594/**
1552 * Iterator callback for responding to join requests of a slave. 1595 * Iterator callback for sending join decisions to multicast.
1553 */ 1596 */
1554static int 1597static int
1555mcast_send_join_decision (void *cls, const struct GNUNET_HashCode *pub_key_hash, 1598mcast_send_join_decision (void *cls, const struct GNUNET_HashCode *pub_key_hash,
1556 void *jh) 1599 void *value)
1557{ 1600{
1558 struct JoinDecisionClosure *jcls = cls; 1601 struct JoinDecisionClosure *jcls = cls;
1602 struct GNUNET_MULTICAST_JoinHandle *jh = value;
1559 // FIXME: add relays 1603 // FIXME: add relays
1560 GNUNET_MULTICAST_join_decision (jh, jcls->is_admitted, 0, NULL, jcls->msg); 1604 GNUNET_MULTICAST_join_decision (jh, jcls->is_admitted, 0, NULL, jcls->msg);
1561 return GNUNET_YES; 1605 return GNUNET_YES;
@@ -1579,8 +1623,7 @@ client_recv_join_decision (void *cls, struct GNUNET_SERVER_Client *client,
1579 struct JoinDecisionClosure jcls; 1623 struct JoinDecisionClosure jcls;
1580 jcls.is_admitted = ntohl (dcsn->is_admitted); 1624 jcls.is_admitted = ntohl (dcsn->is_admitted);
1581 jcls.msg 1625 jcls.msg
1582 = (sizeof (*dcsn) + sizeof (struct GNUNET_PSYC_MessageHeader) 1626 = (sizeof (*dcsn) + sizeof (*jcls.msg) <= ntohs (msg->size))
1583 <= ntohs (msg->size))
1584 ? (struct GNUNET_MessageHeader *) &dcsn[1] 1627 ? (struct GNUNET_MessageHeader *) &dcsn[1]
1585 : NULL; 1628 : NULL;
1586 1629
@@ -1901,6 +1944,9 @@ client_recv_psyc_message (void *cls, struct GNUNET_SERVER_Client *client,
1901 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); 1944 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1902 return; 1945 return;
1903 } 1946 }
1947 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1948 "%p Received message with first part type %u and last part type %u.\n",
1949 chn, first_ptype, last_ptype);
1904 1950
1905 queue_message (chn, client, size - sizeof (*msg), &msg[1], 1951 queue_message (chn, client, size - sizeof (*msg), &msg[1],
1906 first_ptype, last_ptype); 1952 first_ptype, last_ptype);
diff --git a/src/psyc/psyc.h b/src/psyc/psyc.h
index 995fb1fa4..82800a334 100644
--- a/src/psyc/psyc.h
+++ b/src/psyc/psyc.h
@@ -229,22 +229,6 @@ struct OperationResult
229 */ 229 */
230}; 230};
231 231
232
233struct MasterJoinRequest
234{
235 /**
236 * Type: GNUNET_MESSAGE_TYPE_PSYC_MASTER_JOIN_REQUEST
237 */
238 struct GNUNET_MessageHeader header;
239 /**
240 * Public key of the joining slave.
241 */
242 struct GNUNET_CRYPTO_EcdsaPublicKey slave_key;
243
244 /* Followed by struct GNUNET_MessageHeader join_request */
245};
246
247
248GNUNET_NETWORK_STRUCT_END 232GNUNET_NETWORK_STRUCT_END
249 233
250#endif 234#endif
diff --git a/src/psyc/psyc_api.c b/src/psyc/psyc_api.c
index 88b007a0f..a43b1ef5f 100644
--- a/src/psyc/psyc_api.c
+++ b/src/psyc/psyc_api.c
@@ -74,6 +74,16 @@ struct GNUNET_PSYC_Channel
74 struct GNUNET_MessageHeader *connect_msg; 74 struct GNUNET_MessageHeader *connect_msg;
75 75
76 /** 76 /**
77 * Function called after disconnected from the service.
78 */
79 GNUNET_ContinuationCallback disconnect_cb;
80
81 /**
82 * Closure for @a disconnect_cb.
83 */
84 void *disconnect_cls;
85
86 /**
77 * Are we polling for incoming messages right now? 87 * Are we polling for incoming messages right now?
78 */ 88 */
79 uint8_t in_receive; 89 uint8_t in_receive;
@@ -82,6 +92,12 @@ struct GNUNET_PSYC_Channel
82 * Is this a master or slave channel? 92 * Is this a master or slave channel?
83 */ 93 */
84 uint8_t is_master; 94 uint8_t is_master;
95
96 /**
97 * Is this channel in the process of disconnecting from the service?
98 * #GNUNET_YES or #GNUNET_NO
99 */
100 uint8_t is_disconnecting;
85}; 101};
86 102
87 103
@@ -232,19 +248,26 @@ master_recv_join_request (void *cls,
232 struct GNUNET_PSYC_Master * 248 struct GNUNET_PSYC_Master *
233 mst = GNUNET_CLIENT_MANAGER_get_user_context_ (client, 249 mst = GNUNET_CLIENT_MANAGER_get_user_context_ (client,
234 sizeof (struct GNUNET_PSYC_Channel)); 250 sizeof (struct GNUNET_PSYC_Channel));
235 251 if (NULL == mst->join_req_cb)
236 const struct MasterJoinRequest *req = (const struct MasterJoinRequest *) msg; 252 return;
237 253
238 struct GNUNET_PSYC_MessageHeader *pmsg = NULL; 254 const struct GNUNET_PSYC_JoinRequestMessage *
239 if (ntohs (req->header.size) <= sizeof (*req) + sizeof (*pmsg)) 255 req = (const struct GNUNET_PSYC_JoinRequestMessage *) msg;
240 pmsg = (struct GNUNET_PSYC_MessageHeader *) &req[1]; 256 const struct GNUNET_PSYC_Message *join_msg = NULL;
257 if (sizeof (*req) + sizeof (*join_msg) <= ntohs (req->header.size))
258 {
259 join_msg = (struct GNUNET_PSYC_Message *) &req[1];
260 LOG (GNUNET_ERROR_TYPE_ERROR,
261 "Received join_msg of type %u and size %u.\n",
262 ntohs (join_msg->header.type), ntohs (join_msg->header.size));
263 }
241 264
242 struct GNUNET_PSYC_JoinHandle *jh = GNUNET_malloc (sizeof (*jh)); 265 struct GNUNET_PSYC_JoinHandle *jh = GNUNET_malloc (sizeof (*jh));
243 jh->mst = mst; 266 jh->mst = mst;
244 jh->slave_key = req->slave_key; 267 jh->slave_key = req->slave_key;
245 268
246 if (NULL != mst->join_req_cb) 269 if (NULL != mst->join_req_cb)
247 mst->join_req_cb (mst->cb_cls, &req->slave_key, pmsg, jh); 270 mst->join_req_cb (mst->cb_cls, req, &req->slave_key, join_msg, jh);
248} 271}
249 272
250 273
@@ -273,13 +296,12 @@ slave_recv_join_decision (void *cls,
273 const struct GNUNET_PSYC_JoinDecisionMessage * 296 const struct GNUNET_PSYC_JoinDecisionMessage *
274 dcsn = (const struct GNUNET_PSYC_JoinDecisionMessage *) msg; 297 dcsn = (const struct GNUNET_PSYC_JoinDecisionMessage *) msg;
275 298
276 struct GNUNET_PSYC_MessageHeader *pmsg = NULL; 299 struct GNUNET_PSYC_Message *pmsg = NULL;
277 if (ntohs (dcsn->header.size) <= sizeof (*dcsn) + sizeof (*pmsg)) 300 if (ntohs (dcsn->header.size) <= sizeof (*dcsn) + sizeof (*pmsg))
278 pmsg = (struct GNUNET_PSYC_MessageHeader *) &dcsn[1]; 301 pmsg = (struct GNUNET_PSYC_Message *) &dcsn[1];
279 302
280 struct GNUNET_PSYC_JoinHandle *jh = GNUNET_malloc (sizeof (*jh));
281 if (NULL != slv->join_dcsn_cb) 303 if (NULL != slv->join_dcsn_cb)
282 slv->join_dcsn_cb (slv->cb_cls, ntohl (dcsn->is_admitted), pmsg); 304 slv->join_dcsn_cb (slv->cb_cls, dcsn, ntohl (dcsn->is_admitted), pmsg);
283} 305}
284 306
285 307
@@ -299,7 +321,7 @@ static struct GNUNET_CLIENT_MANAGER_MessageHandler master_handlers[] =
299 321
300 { &master_recv_join_request, NULL, 322 { &master_recv_join_request, NULL,
301 GNUNET_MESSAGE_TYPE_PSYC_JOIN_REQUEST, 323 GNUNET_MESSAGE_TYPE_PSYC_JOIN_REQUEST,
302 sizeof (struct MasterJoinRequest), GNUNET_YES }, 324 sizeof (struct GNUNET_PSYC_JoinRequestMessage), GNUNET_YES },
303 325
304 { &channel_recv_disconnect, NULL, 0, 0, GNUNET_NO }, 326 { &channel_recv_disconnect, NULL, 0, 0, GNUNET_NO },
305 327
@@ -331,6 +353,35 @@ static struct GNUNET_CLIENT_MANAGER_MessageHandler slave_handlers[] =
331}; 353};
332 354
333 355
356static void
357channel_cleanup (struct GNUNET_PSYC_Channel *chn)
358{
359 GNUNET_PSYC_transmit_destroy (chn->tmit);
360 GNUNET_PSYC_receive_destroy (chn->recv);
361 GNUNET_free (chn->connect_msg);
362 if (NULL != chn->disconnect_cb)
363 chn->disconnect_cb (chn->disconnect_cls);
364}
365
366
367static void
368master_cleanup (void *cls)
369{
370 struct GNUNET_PSYC_Master *mst = cls;
371 channel_cleanup (&mst->chn);
372 GNUNET_free (mst);
373}
374
375
376static void
377slave_cleanup (void *cls)
378{
379 struct GNUNET_PSYC_Slave *slv = cls;
380 channel_cleanup (&slv->chn);
381 GNUNET_free (slv);
382}
383
384
334/** 385/**
335 * Start a PSYC master channel. 386 * Start a PSYC master channel.
336 * 387 *
@@ -367,6 +418,7 @@ GNUNET_PSYC_master_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
367 GNUNET_PSYC_MasterStartCallback start_cb, 418 GNUNET_PSYC_MasterStartCallback start_cb,
368 GNUNET_PSYC_JoinRequestCallback join_request_cb, 419 GNUNET_PSYC_JoinRequestCallback join_request_cb,
369 GNUNET_PSYC_MessageCallback message_cb, 420 GNUNET_PSYC_MessageCallback message_cb,
421 GNUNET_PSYC_MessagePartCallback message_part_cb,
370 void *cls) 422 void *cls)
371{ 423{
372 struct GNUNET_PSYC_Master *mst = GNUNET_malloc (sizeof (*mst)); 424 struct GNUNET_PSYC_Master *mst = GNUNET_malloc (sizeof (*mst));
@@ -390,7 +442,7 @@ GNUNET_PSYC_master_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
390 GNUNET_CLIENT_MANAGER_set_user_context_ (chn->client, mst, sizeof (*chn)); 442 GNUNET_CLIENT_MANAGER_set_user_context_ (chn->client, mst, sizeof (*chn));
391 443
392 chn->tmit = GNUNET_PSYC_transmit_create (chn->client); 444 chn->tmit = GNUNET_PSYC_transmit_create (chn->client);
393 chn->recv = GNUNET_PSYC_receive_create (message_cb, message_cb, cls); 445 chn->recv = GNUNET_PSYC_receive_create (message_cb, message_part_cb, cls);
394 446
395 channel_send_connect_msg (chn); 447 channel_send_connect_msg (chn);
396 return mst; 448 return mst;
@@ -404,10 +456,21 @@ GNUNET_PSYC_master_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
404 * @param keep_active FIXME 456 * @param keep_active FIXME
405 */ 457 */
406void 458void
407GNUNET_PSYC_master_stop (struct GNUNET_PSYC_Master *mst) 459GNUNET_PSYC_master_stop (struct GNUNET_PSYC_Master *mst,
460 int keep_active,
461 GNUNET_ContinuationCallback stop_cb,
462 void *stop_cls)
408{ 463{
409 GNUNET_CLIENT_MANAGER_disconnect (mst->chn.client, GNUNET_YES); 464 struct GNUNET_PSYC_Channel *chn = &mst->chn;
410 GNUNET_free (mst); 465
466 /* FIXME: send msg to service */
467
468 chn->is_disconnecting = GNUNET_YES;
469 chn->disconnect_cb = stop_cb;
470 chn->disconnect_cls = stop_cls;
471
472 GNUNET_CLIENT_MANAGER_disconnect (mst->chn.client, GNUNET_YES,
473 &master_cleanup, mst);
411} 474}
412 475
413 476
@@ -439,7 +502,7 @@ GNUNET_PSYC_join_decision (struct GNUNET_PSYC_JoinHandle *jh,
439 int is_admitted, 502 int is_admitted,
440 uint32_t relay_count, 503 uint32_t relay_count,
441 const struct GNUNET_PeerIdentity *relays, 504 const struct GNUNET_PeerIdentity *relays,
442 const struct GNUNET_PSYC_MessageHeader *join_resp) 505 const struct GNUNET_PSYC_Message *join_resp)
443{ 506{
444 struct GNUNET_PSYC_Channel *chn = &jh->mst->chn; 507 struct GNUNET_PSYC_Channel *chn = &jh->mst->chn;
445 struct GNUNET_PSYC_JoinDecisionMessage *dcsn; 508 struct GNUNET_PSYC_JoinDecisionMessage *dcsn;
@@ -461,6 +524,7 @@ GNUNET_PSYC_join_decision (struct GNUNET_PSYC_JoinHandle *jh,
461 memcpy (&dcsn[1], join_resp, join_resp_size); 524 memcpy (&dcsn[1], join_resp, join_resp_size);
462 525
463 GNUNET_CLIENT_MANAGER_transmit (chn->client, &dcsn->header); 526 GNUNET_CLIENT_MANAGER_transmit (chn->client, &dcsn->header);
527 GNUNET_free (jh);
464 return GNUNET_OK; 528 return GNUNET_OK;
465} 529}
466 530
@@ -576,15 +640,19 @@ GNUNET_PSYC_slave_join (const struct GNUNET_CONFIGURATION_Handle *cfg,
576 uint32_t relay_count, 640 uint32_t relay_count,
577 const struct GNUNET_PeerIdentity *relays, 641 const struct GNUNET_PeerIdentity *relays,
578 GNUNET_PSYC_MessageCallback message_cb, 642 GNUNET_PSYC_MessageCallback message_cb,
643 GNUNET_PSYC_MessagePartCallback message_part_cb,
579 GNUNET_PSYC_SlaveConnectCallback connect_cb, 644 GNUNET_PSYC_SlaveConnectCallback connect_cb,
580 GNUNET_PSYC_JoinDecisionCallback join_decision_cb, 645 GNUNET_PSYC_JoinDecisionCallback join_decision_cb,
581 void *cls, 646 void *cls,
582 const struct GNUNET_MessageHeader *join_msg) 647 const struct GNUNET_PSYC_Message *join_msg)
583{ 648{
584 struct GNUNET_PSYC_Slave *slv = GNUNET_malloc (sizeof (*slv)); 649 struct GNUNET_PSYC_Slave *slv = GNUNET_malloc (sizeof (*slv));
585 struct GNUNET_PSYC_Channel *chn = &slv->chn; 650 struct GNUNET_PSYC_Channel *chn = &slv->chn;
651
652 uint16_t relay_size = relay_count * sizeof (*relays);
653 uint16_t join_msg_size = ntohs (join_msg->header.size);
586 struct SlaveJoinRequest *req 654 struct SlaveJoinRequest *req
587 = GNUNET_malloc (sizeof (*req) + relay_count * sizeof (*relays)); 655 = GNUNET_malloc (sizeof (*req) + relay_size + join_msg_size);
588 req->header.size = htons (sizeof (*req) 656 req->header.size = htons (sizeof (*req)
589 + relay_count * sizeof (*relays)); 657 + relay_count * sizeof (*relays));
590 req->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_SLAVE_JOIN); 658 req->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_SLAVE_JOIN);
@@ -592,7 +660,12 @@ GNUNET_PSYC_slave_join (const struct GNUNET_CONFIGURATION_Handle *cfg,
592 req->slave_key = *slave_key; 660 req->slave_key = *slave_key;
593 req->origin = *origin; 661 req->origin = *origin;
594 req->relay_count = htonl (relay_count); 662 req->relay_count = htonl (relay_count);
595 memcpy (&req[1], relays, relay_count * sizeof (*relays)); 663
664 if (0 < relay_size)
665 memcpy (&req[1], relays, relay_size);
666
667 if (0 < join_msg_size)
668 memcpy ((char *) &req[1] + relay_size, join_msg, join_msg_size);
596 669
597 chn->connect_msg = (struct GNUNET_MessageHeader *) req; 670 chn->connect_msg = (struct GNUNET_MessageHeader *) req;
598 chn->cfg = cfg; 671 chn->cfg = cfg;
@@ -605,7 +678,7 @@ GNUNET_PSYC_slave_join (const struct GNUNET_CONFIGURATION_Handle *cfg,
605 chn->client = GNUNET_CLIENT_MANAGER_connect (cfg, "psyc", slave_handlers); 678 chn->client = GNUNET_CLIENT_MANAGER_connect (cfg, "psyc", slave_handlers);
606 GNUNET_CLIENT_MANAGER_set_user_context_ (chn->client, slv, sizeof (*chn)); 679 GNUNET_CLIENT_MANAGER_set_user_context_ (chn->client, slv, sizeof (*chn));
607 680
608 chn->recv = GNUNET_PSYC_receive_create (message_cb, message_cb, cls); 681 chn->recv = GNUNET_PSYC_receive_create (message_cb, message_part_cb, cls);
609 chn->tmit = GNUNET_PSYC_transmit_create (chn->client); 682 chn->tmit = GNUNET_PSYC_transmit_create (chn->client);
610 683
611 channel_send_connect_msg (chn); 684 channel_send_connect_msg (chn);
@@ -622,10 +695,21 @@ GNUNET_PSYC_slave_join (const struct GNUNET_CONFIGURATION_Handle *cfg,
622 * @param slave Slave handle. 695 * @param slave Slave handle.
623 */ 696 */
624void 697void
625GNUNET_PSYC_slave_part (struct GNUNET_PSYC_Slave *slv) 698GNUNET_PSYC_slave_part (struct GNUNET_PSYC_Slave *slv,
699 int keep_active,
700 GNUNET_ContinuationCallback part_cb,
701 void *part_cls)
626{ 702{
627 GNUNET_CLIENT_MANAGER_disconnect (slv->chn.client, GNUNET_YES); 703 struct GNUNET_PSYC_Channel *chn = &slv->chn;
628 GNUNET_free (slv); 704
705 /* FIXME: send msg to service */
706
707 chn->is_disconnecting = GNUNET_YES;
708 chn->disconnect_cb = part_cb;
709 chn->disconnect_cls = part_cls;
710
711 GNUNET_CLIENT_MANAGER_disconnect (slv->chn.client, GNUNET_YES,
712 &slave_cleanup, slv);
629} 713}
630 714
631 715
@@ -796,6 +880,7 @@ GNUNET_PSYC_channel_story_tell (struct GNUNET_PSYC_Channel *channel,
796 uint64_t start_message_id, 880 uint64_t start_message_id,
797 uint64_t end_message_id, 881 uint64_t end_message_id,
798 GNUNET_PSYC_MessageCallback message_cb, 882 GNUNET_PSYC_MessageCallback message_cb,
883 GNUNET_PSYC_MessagePartCallback message_part_cb,
799 GNUNET_PSYC_FinishCallback finish_cb, 884 GNUNET_PSYC_FinishCallback finish_cb,
800 void *cls) 885 void *cls)
801{ 886{
diff --git a/src/psyc/psyc_util_lib.c b/src/psyc/psyc_util_lib.c
index 8ab0bdad2..6177976de 100644
--- a/src/psyc/psyc_util_lib.c
+++ b/src/psyc/psyc_util_lib.c
@@ -76,7 +76,11 @@ struct GNUNET_PSYC_TransmitHandle
76 * 76 *
77 */ 77 */
78 const char *mod_value; 78 const char *mod_value;
79 size_t mod_value_size; 79
80 /**
81 * Number of bytes remaining to be transmitted from the current modifier value.
82 */
83 uint32_t mod_value_remaining;
80 84
81 /** 85 /**
82 * State of the current message being received from client. 86 * State of the current message being received from client.
@@ -104,14 +108,14 @@ struct GNUNET_PSYC_TransmitHandle
104struct GNUNET_PSYC_ReceiveHandle 108struct GNUNET_PSYC_ReceiveHandle
105{ 109{
106 /** 110 /**
107 * Message part callback. 111 * Message callback.
108 */ 112 */
109 GNUNET_PSYC_MessageCallback message_cb; 113 GNUNET_PSYC_MessageCallback message_cb;
110 114
111 /** 115 /**
112 * Message part callback for historic message. 116 * Message part callback.
113 */ 117 */
114 GNUNET_PSYC_MessageCallback hist_message_cb; 118 GNUNET_PSYC_MessagePartCallback message_part_cb;
115 119
116 /** 120 /**
117 * Closure for the callbacks. 121 * Closure for the callbacks.
@@ -149,6 +153,7 @@ struct GNUNET_PSYC_ReceiveHandle
149 uint32_t mod_value_size; 153 uint32_t mod_value_size;
150}; 154};
151 155
156
152/**** Messages ****/ 157/**** Messages ****/
153 158
154 159
@@ -167,7 +172,7 @@ struct GNUNET_PSYC_ReceiveHandle
167 * @return Message header with size information, 172 * @return Message header with size information,
168 * followed by the message parts. 173 * followed by the message parts.
169 */ 174 */
170struct GNUNET_MessageHeader * 175struct GNUNET_PSYC_Message *
171GNUNET_PSYC_message_create (const char *method_name, 176GNUNET_PSYC_message_create (const char *method_name,
172 const struct GNUNET_ENV_Environment *env, 177 const struct GNUNET_ENV_Environment *env,
173 const void *data, 178 const void *data,
@@ -188,7 +193,7 @@ GNUNET_PSYC_message_create (const char *method_name,
188 } 193 }
189 } 194 }
190 195
191 struct GNUNET_MessageHeader *msg; 196 struct GNUNET_PSYC_Message *msg;
192 uint16_t method_name_size = strlen (method_name) + 1; 197 uint16_t method_name_size = strlen (method_name) + 1;
193 if (method_name_size == 1) 198 if (method_name_size == 1)
194 return NULL; 199 return NULL;
@@ -199,12 +204,13 @@ GNUNET_PSYC_message_create (const char *method_name,
199 + ((0 < data_size) ? sizeof (*pmsg) + data_size : 0)/* data */ 204 + ((0 < data_size) ? sizeof (*pmsg) + data_size : 0)/* data */
200 + sizeof (*pmsg); /* end of message */ 205 + sizeof (*pmsg); /* end of message */
201 msg = GNUNET_malloc (msg_size); 206 msg = GNUNET_malloc (msg_size);
202 msg->size = htons (msg_size); 207 msg->header.size = htons (msg_size);
203 msg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE); 208 msg->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE); /* FIXME */
204 209
205 pmeth = (struct GNUNET_PSYC_MessageMethod *) &msg[1]; 210 pmeth = (struct GNUNET_PSYC_MessageMethod *) &msg[1];
211 pmeth->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD);
206 pmeth->header.size = htons (sizeof (*pmeth) + method_name_size); 212 pmeth->header.size = htons (sizeof (*pmeth) + method_name_size);
207 memcpy (pmeth, method_name, method_name_size); 213 memcpy (&pmeth[1], method_name, method_name_size);
208 214
209 uint16_t p = sizeof (*msg) + sizeof (*pmeth) + method_name_size; 215 uint16_t p = sizeof (*msg) + sizeof (*pmeth) + method_name_size;
210 if (NULL != env) 216 if (NULL != env)
@@ -215,7 +221,7 @@ GNUNET_PSYC_message_create (const char *method_name,
215 uint16_t mod_name_size = strlen (mod->name) + 1; 221 uint16_t mod_name_size = strlen (mod->name) + 1;
216 pmod = (struct GNUNET_PSYC_MessageModifier *) ((char *) msg + p); 222 pmod = (struct GNUNET_PSYC_MessageModifier *) ((char *) msg + p);
217 pmod->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER); 223 pmod->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER);
218 pmod->header.size = sizeof (*pmod) + mod_name_size + 1 + mod->value_size; 224 pmod->header.size = sizeof (*pmod) + mod_name_size + mod->value_size;
219 p += pmod->header.size; 225 p += pmod->header.size;
220 pmod->header.size = htons (pmod->header.size); 226 pmod->header.size = htons (pmod->header.size);
221 227
@@ -241,6 +247,7 @@ GNUNET_PSYC_message_create (const char *method_name,
241 pmsg->size = htons (sizeof (*pmsg)); 247 pmsg->size = htons (sizeof (*pmsg));
242 pmsg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END); 248 pmsg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END);
243 249
250 GNUNET_assert (p + sizeof (*pmsg) == msg_size);
244 return msg; 251 return msg;
245} 252}
246 253
@@ -276,8 +283,8 @@ GNUNET_PSYC_log_message (enum GNUNET_ErrorType kind,
276 uint16_t name_size = ntohs (mod->name_size); 283 uint16_t name_size = ntohs (mod->name_size);
277 char oper = ' ' < mod->oper ? mod->oper : ' '; 284 char oper = ' ' < mod->oper ? mod->oper : ' ';
278 GNUNET_log (kind, "\t%c%.*s\t%.*s\n", oper, name_size, &mod[1], 285 GNUNET_log (kind, "\t%c%.*s\t%.*s\n", oper, name_size, &mod[1],
279 size - sizeof (*mod) - name_size - 1, 286 size - sizeof (*mod) - name_size,
280 ((char *) &mod[1]) + name_size + 1); 287 ((char *) &mod[1]) + name_size);
281 break; 288 break;
282 } 289 }
283 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT: 290 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
@@ -331,7 +338,7 @@ transmit_queue_insert (struct GNUNET_PSYC_TransmitHandle *tmit,
331 uint16_t size = (NULL != msg) ? ntohs (msg->size) : 0; 338 uint16_t size = (NULL != msg) ? ntohs (msg->size) : 0;
332 339
333 LOG (GNUNET_ERROR_TYPE_DEBUG, 340 LOG (GNUNET_ERROR_TYPE_DEBUG,
334 "Queueing message of type %u and size %u (end: %u)).\n", 341 "Queueing message part of type %u and size %u (end: %u)).\n",
335 ntohs (msg->type), size, end); 342 ntohs (msg->type), size, end);
336 343
337 if (NULL != tmit->msg) 344 if (NULL != tmit->msg)
@@ -396,6 +403,9 @@ transmit_data (struct GNUNET_PSYC_TransmitHandle *tmit)
396 msg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA); 403 msg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA);
397 404
398 int notify_ret = tmit->notify_data (tmit->notify_data_cls, &data_size, &msg[1]); 405 int notify_ret = tmit->notify_data (tmit->notify_data_cls, &data_size, &msg[1]);
406 LOG (GNUNET_ERROR_TYPE_DEBUG,
407 "transmit_data (ret: %d, size: %u): %.*s\n",
408 notify_ret, data_size, data_size, &msg[1]);
399 switch (notify_ret) 409 switch (notify_ret)
400 { 410 {
401 case GNUNET_NO: 411 case GNUNET_NO:
@@ -463,9 +473,15 @@ transmit_mod (struct GNUNET_PSYC_TransmitHandle *tmit)
463 msg->size = sizeof (struct GNUNET_PSYC_MessageModifier); 473 msg->size = sizeof (struct GNUNET_PSYC_MessageModifier);
464 notify_ret = tmit->notify_mod (tmit->notify_mod_cls, &data_size, &mod[1], 474 notify_ret = tmit->notify_mod (tmit->notify_mod_cls, &data_size, &mod[1],
465 &mod->oper, &mod->value_size); 475 &mod->oper, &mod->value_size);
466 mod->name_size = strnlen ((char *) &mod[1], data_size); 476
477 mod->name_size = strnlen ((char *) &mod[1], data_size) + 1;
478 LOG (GNUNET_ERROR_TYPE_DEBUG,
479 "transmit_mod (ret: %d, size: %u + %u): %.*s\n",
480 notify_ret, mod->name_size, mod->value_size, data_size, &mod[1]);
467 if (mod->name_size < data_size) 481 if (mod->name_size < data_size)
468 { 482 {
483 tmit->mod_value_remaining
484 = mod->value_size - (data_size - mod->name_size);
469 mod->value_size = htonl (mod->value_size); 485 mod->value_size = htonl (mod->value_size);
470 mod->name_size = htons (mod->name_size); 486 mod->name_size = htons (mod->name_size);
471 } 487 }
@@ -483,6 +499,10 @@ transmit_mod (struct GNUNET_PSYC_TransmitHandle *tmit)
483 msg->size = sizeof (struct GNUNET_MessageHeader); 499 msg->size = sizeof (struct GNUNET_MessageHeader);
484 notify_ret = tmit->notify_mod (tmit->notify_mod_cls, 500 notify_ret = tmit->notify_mod (tmit->notify_mod_cls,
485 &data_size, &msg[1], NULL, NULL); 501 &data_size, &msg[1], NULL, NULL);
502 tmit->mod_value_remaining -= data_size;
503 LOG (GNUNET_ERROR_TYPE_DEBUG,
504 "transmit_mod (ret: %d, size: %u): %.*s\n",
505 notify_ret, data_size, data_size, &msg[1]);
486 break; 506 break;
487 } 507 }
488 default: 508 default:
@@ -497,26 +517,19 @@ transmit_mod (struct GNUNET_PSYC_TransmitHandle *tmit)
497 tmit->paused = GNUNET_YES; 517 tmit->paused = GNUNET_YES;
498 return; 518 return;
499 } 519 }
500 tmit->state = GNUNET_PSYC_MESSAGE_STATE_MOD_CONT; 520 tmit->state
521 = (0 == tmit->mod_value_remaining)
522 ? GNUNET_PSYC_MESSAGE_STATE_MODIFIER
523 : GNUNET_PSYC_MESSAGE_STATE_MOD_CONT;
501 break; 524 break;
502 525
503 case GNUNET_YES: 526 case GNUNET_YES: /* End of modifiers. */
504 if (0 == data_size) 527 GNUNET_assert (0 == tmit->mod_value_remaining);
505 {
506 /* End of modifiers. */
507 tmit->state = GNUNET_PSYC_MESSAGE_STATE_DATA;
508 if (0 == tmit->acks_pending)
509 transmit_data (tmit);
510
511 return;
512 }
513 tmit->state = GNUNET_PSYC_MESSAGE_STATE_MODIFIER;
514 break; 528 break;
515 529
516 default: 530 default:
517 LOG (GNUNET_ERROR_TYPE_ERROR, 531 LOG (GNUNET_ERROR_TYPE_ERROR,
518 "TransmitNotifyModifier callback returned error " 532 "TransmitNotifyModifier callback returned with error.\n");
519 "when requesting a modifier.\n");
520 533
521 tmit->state = GNUNET_PSYC_MESSAGE_STATE_CANCEL; 534 tmit->state = GNUNET_PSYC_MESSAGE_STATE_CANCEL;
522 msg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL); 535 msg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL);
@@ -533,7 +546,16 @@ transmit_mod (struct GNUNET_PSYC_TransmitHandle *tmit)
533 transmit_queue_insert (tmit, msg, GNUNET_NO); 546 transmit_queue_insert (tmit, msg, GNUNET_NO);
534 } 547 }
535 548
536 transmit_mod (tmit); 549 if (GNUNET_YES == notify_ret)
550 {
551 tmit->state = GNUNET_PSYC_MESSAGE_STATE_DATA;
552 if (0 == tmit->acks_pending)
553 transmit_data (tmit);
554 }
555 else
556 {
557 transmit_mod (tmit);
558 }
537} 559}
538 560
539 561
@@ -547,9 +569,10 @@ transmit_notify_env (void *cls, uint16_t *data_size, void *data, uint8_t *oper,
547 size_t value_size = 0; 569 size_t value_size = 0;
548 const char *value = NULL; 570 const char *value = NULL;
549 571
550 if (NULL != oper && NULL != tmit->mod) 572 if (NULL != oper)
551 { /* New modifier */ 573 { /* New modifier */
552 tmit->mod = tmit->mod->next; 574 if (NULL != tmit->mod)
575 tmit->mod = tmit->mod->next;
553 if (NULL == tmit->mod) 576 if (NULL == tmit->mod)
554 { /* No more modifiers, continue with data */ 577 { /* No more modifiers, continue with data */
555 *data_size = 0; 578 *data_size = 0;
@@ -559,30 +582,29 @@ transmit_notify_env (void *cls, uint16_t *data_size, void *data, uint8_t *oper,
559 GNUNET_assert (tmit->mod->value_size < UINT32_MAX); 582 GNUNET_assert (tmit->mod->value_size < UINT32_MAX);
560 *full_value_size = tmit->mod->value_size; 583 *full_value_size = tmit->mod->value_size;
561 *oper = tmit->mod->oper; 584 *oper = tmit->mod->oper;
562 name_size = strlen (tmit->mod->name); 585 name_size = strlen (tmit->mod->name) + 1;
563 586
564 if (name_size + 1 + tmit->mod->value_size <= *data_size) 587 if (name_size + tmit->mod->value_size <= *data_size)
565 { 588 {
566 *data_size = name_size + 1 + tmit->mod->value_size; 589 *data_size = name_size + tmit->mod->value_size;
567 } 590 }
568 else 591 else
569 { 592 {
570 tmit->mod_value_size = tmit->mod->value_size; 593 value_size = *data_size - name_size;
571 value_size = *data_size - name_size - 1;
572 tmit->mod_value_size -= value_size;
573 tmit->mod_value = tmit->mod->value + value_size; 594 tmit->mod_value = tmit->mod->value + value_size;
574 } 595 }
575 596
576 memcpy (data, tmit->mod->name, name_size); 597 memcpy (data, tmit->mod->name, name_size);
577 ((char *)data)[name_size] = '\0'; 598 memcpy ((char *)data + name_size, tmit->mod->value, value_size);
578 memcpy ((char *)data + name_size + 1, tmit->mod->value, value_size); 599 return GNUNET_NO;
579 } 600 }
580 else if (NULL != tmit->mod_value && 0 < tmit->mod_value_size) 601 else
581 { /* Modifier continuation */ 602 { /* Modifier continuation */
603 GNUNET_assert (NULL != tmit->mod_value && 0 < tmit->mod_value_remaining);
582 value = tmit->mod_value; 604 value = tmit->mod_value;
583 if (tmit->mod_value_size <= *data_size) 605 if (tmit->mod_value_remaining <= *data_size)
584 { 606 {
585 value_size = tmit->mod_value_size; 607 value_size = tmit->mod_value_remaining;
586 tmit->mod_value = NULL; 608 tmit->mod_value = NULL;
587 } 609 }
588 else 610 else
@@ -590,7 +612,6 @@ transmit_notify_env (void *cls, uint16_t *data_size, void *data, uint8_t *oper,
590 value_size = *data_size; 612 value_size = *data_size;
591 tmit->mod_value += value_size; 613 tmit->mod_value += value_size;
592 } 614 }
593 tmit->mod_value_size -= value_size;
594 615
595 if (*data_size < value_size) 616 if (*data_size < value_size)
596 { 617 {
@@ -603,9 +624,8 @@ transmit_notify_env (void *cls, uint16_t *data_size, void *data, uint8_t *oper,
603 624
604 *data_size = value_size; 625 *data_size = value_size;
605 memcpy (data, value, value_size); 626 memcpy (data, value, value_size);
627 return (tmit->mod_value = NULL) ? GNUNET_YES : GNUNET_NO;
606 } 628 }
607
608 return 0 == tmit->mod_value_size ? GNUNET_YES : GNUNET_NO;
609} 629}
610 630
611 631
@@ -663,10 +683,16 @@ GNUNET_PSYC_transmit_message (struct GNUNET_PSYC_TransmitHandle *tmit,
663 { 683 {
664 tmit->notify_mod = &transmit_notify_env; 684 tmit->notify_mod = &transmit_notify_env;
665 tmit->notify_mod_cls = tmit; 685 tmit->notify_mod_cls = tmit;
666 tmit->mod 686 if (NULL != env)
667 = (NULL != env) 687 {
668 ? GNUNET_ENV_environment_head (env) 688 struct GNUNET_ENV_Modifier mod = {};
669 : NULL; 689 mod.next = GNUNET_ENV_environment_head (env);
690 tmit->mod = &mod;
691 }
692 else
693 {
694 tmit->mod = NULL;
695 }
670 } 696 }
671 697
672 transmit_mod (tmit); 698 transmit_mod (tmit);
@@ -762,12 +788,12 @@ GNUNET_PSYC_transmit_got_ack (struct GNUNET_PSYC_TransmitHandle *tmit)
762 */ 788 */
763struct GNUNET_PSYC_ReceiveHandle * 789struct GNUNET_PSYC_ReceiveHandle *
764GNUNET_PSYC_receive_create (GNUNET_PSYC_MessageCallback message_cb, 790GNUNET_PSYC_receive_create (GNUNET_PSYC_MessageCallback message_cb,
765 GNUNET_PSYC_MessageCallback hist_message_cb, 791 GNUNET_PSYC_MessagePartCallback message_part_cb,
766 void *cb_cls) 792 void *cb_cls)
767{ 793{
768 struct GNUNET_PSYC_ReceiveHandle *recv = GNUNET_malloc (sizeof (*recv)); 794 struct GNUNET_PSYC_ReceiveHandle *recv = GNUNET_malloc (sizeof (*recv));
769 recv->message_cb = message_cb; 795 recv->message_cb = message_cb;
770 recv->hist_message_cb = hist_message_cb; 796 recv->message_part_cb = message_part_cb;
771 recv->cb_cls = cb_cls; 797 recv->cb_cls = cb_cls;
772 return recv; 798 return recv;
773} 799}
@@ -800,13 +826,11 @@ GNUNET_PSYC_receive_reset (struct GNUNET_PSYC_ReceiveHandle *recv)
800static void 826static void
801recv_error (struct GNUNET_PSYC_ReceiveHandle *recv) 827recv_error (struct GNUNET_PSYC_ReceiveHandle *recv)
802{ 828{
803 GNUNET_PSYC_MessageCallback message_cb 829 if (NULL != recv->message_part_cb)
804 = recv->flags & GNUNET_PSYC_MESSAGE_HISTORIC 830 recv->message_part_cb (recv->cb_cls, recv->message_id, 0, recv->flags, NULL);
805 ? recv->hist_message_cb
806 : recv->message_cb;
807 831
808 if (NULL != message_cb) 832 if (NULL != recv->message_cb)
809 message_cb (recv->cb_cls, recv->message_id, recv->flags, NULL); 833 recv->message_cb (recv->cb_cls, recv->message_id, recv->flags, NULL);
810 834
811 GNUNET_PSYC_receive_reset (recv); 835 GNUNET_PSYC_receive_reset (recv);
812} 836}
@@ -827,6 +851,7 @@ GNUNET_PSYC_receive_message (struct GNUNET_PSYC_ReceiveHandle *recv,
827{ 851{
828 uint16_t size = ntohs (msg->header.size); 852 uint16_t size = ntohs (msg->header.size);
829 uint32_t flags = ntohl (msg->flags); 853 uint32_t flags = ntohl (msg->flags);
854 uint64_t message_id;
830 855
831 GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, 856 GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG,
832 (struct GNUNET_MessageHeader *) msg); 857 (struct GNUNET_MessageHeader *) msg);
@@ -858,6 +883,7 @@ GNUNET_PSYC_receive_message (struct GNUNET_PSYC_ReceiveHandle *recv,
858 recv_error (recv); 883 recv_error (recv);
859 return GNUNET_SYSERR; 884 return GNUNET_SYSERR;
860 } 885 }
886 message_id = recv->message_id;
861 887
862 uint16_t pos = 0, psize = 0, ptype, size_eq, size_min; 888 uint16_t pos = 0, psize = 0, ptype, size_eq, size_min;
863 889
@@ -964,10 +990,10 @@ GNUNET_PSYC_receive_message (struct GNUNET_PSYC_ReceiveHandle *recv,
964 990
965 uint16_t name_size = ntohs (mod->name_size); 991 uint16_t name_size = ntohs (mod->name_size);
966 recv->mod_value_size_expected = ntohl (mod->value_size); 992 recv->mod_value_size_expected = ntohl (mod->value_size);
967 recv->mod_value_size = psize - sizeof (*mod) - name_size - 1; 993 recv->mod_value_size = psize - sizeof (*mod) - name_size;
968 994
969 if (psize < sizeof (*mod) + name_size + 1 995 if (psize < sizeof (*mod) + name_size
970 || '\0' != *((char *) &mod[1] + name_size) 996 || '\0' != *((char *) &mod[1] + name_size - 1)
971 || recv->mod_value_size_expected < recv->mod_value_size) 997 || recv->mod_value_size_expected < recv->mod_value_size)
972 { 998 {
973 LOG (GNUNET_ERROR_TYPE_WARNING, "Dropping malformed modifier.\n"); 999 LOG (GNUNET_ERROR_TYPE_WARNING, "Dropping malformed modifier.\n");
@@ -1018,13 +1044,9 @@ GNUNET_PSYC_receive_message (struct GNUNET_PSYC_ReceiveHandle *recv,
1018 } 1044 }
1019 } 1045 }
1020 1046
1021 GNUNET_PSYC_MessageCallback message_cb 1047 if (NULL != recv->message_part_cb)
1022 = recv->flags & GNUNET_PSYC_MESSAGE_HISTORIC 1048 recv->message_part_cb (recv->cb_cls, recv->message_id, 0, // FIXME: data_offset
1023 ? recv->hist_message_cb 1049 recv->flags, pmsg);
1024 : recv->message_cb;
1025
1026 if (NULL != message_cb)
1027 message_cb (recv->cb_cls, recv->message_id, recv->flags, pmsg);
1028 1050
1029 switch (ptype) 1051 switch (ptype)
1030 { 1052 {
@@ -1034,6 +1056,9 @@ GNUNET_PSYC_receive_message (struct GNUNET_PSYC_ReceiveHandle *recv,
1034 break; 1056 break;
1035 } 1057 }
1036 } 1058 }
1059
1060 if (NULL != recv->message_cb)
1061 recv->message_cb (recv->cb_cls, message_id, flags, msg);
1037 return GNUNET_OK; 1062 return GNUNET_OK;
1038} 1063}
1039 1064
@@ -1063,6 +1088,7 @@ GNUNET_PSYC_receive_check_parts (uint16_t data_size, const char *data,
1063 for (pos = 0; pos < data_size; pos += psize, parts++) 1088 for (pos = 0; pos < data_size; pos += psize, parts++)
1064 { 1089 {
1065 pmsg = (const struct GNUNET_MessageHeader *) (data + pos); 1090 pmsg = (const struct GNUNET_MessageHeader *) (data + pos);
1091 GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, pmsg);
1066 psize = ntohs (pmsg->size); 1092 psize = ntohs (pmsg->size);
1067 ptype = ntohs (pmsg->type); 1093 ptype = ntohs (pmsg->type);
1068 if (0 == parts && NULL != first_ptype) 1094 if (0 == parts && NULL != first_ptype)
@@ -1084,3 +1110,111 @@ GNUNET_PSYC_receive_check_parts (uint16_t data_size, const char *data,
1084 } 1110 }
1085 return parts; 1111 return parts;
1086} 1112}
1113
1114
1115struct ParseMessageClosure
1116{
1117 struct GNUNET_ENV_Environment *env;
1118 const char **method_name;
1119 const void **data;
1120 uint16_t *data_size;
1121 enum GNUNET_PSYC_MessageState msg_state;
1122};
1123
1124
1125static void
1126parse_message_part_cb (void *cls, uint64_t message_id, uint64_t data_offset,
1127 uint32_t flags, const struct GNUNET_MessageHeader *msg)
1128{
1129 struct ParseMessageClosure *pmc = cls;
1130 if (NULL == msg)
1131 {
1132 pmc->msg_state = GNUNET_PSYC_MESSAGE_STATE_ERROR;
1133 return;
1134 }
1135
1136 switch (ntohs (msg->type))
1137 {
1138 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD:
1139 {
1140 struct GNUNET_PSYC_MessageMethod *
1141 pmeth = (struct GNUNET_PSYC_MessageMethod *) msg;
1142 *pmc->method_name = (const char *) &pmeth[1];
1143 pmc->msg_state = GNUNET_PSYC_MESSAGE_STATE_METHOD;
1144 break;
1145 }
1146
1147 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
1148 {
1149 struct GNUNET_PSYC_MessageModifier *
1150 pmod = (struct GNUNET_PSYC_MessageModifier *) msg;
1151
1152 const char *name = (const char *) &pmod[1];
1153 const void *value = name + pmod->name_size;
1154 GNUNET_ENV_environment_add (pmc->env, pmod->oper, name, value,
1155 pmod->value_size);
1156 pmc->msg_state = GNUNET_PSYC_MESSAGE_STATE_MODIFIER;
1157 break;
1158 }
1159
1160 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
1161 *pmc->data = &msg[1];
1162 *pmc->data_size = ntohs (msg->size) - sizeof (*msg);
1163 pmc->msg_state = GNUNET_PSYC_MESSAGE_STATE_DATA;
1164 break;
1165
1166 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
1167 pmc->msg_state = GNUNET_PSYC_MESSAGE_STATE_END;
1168 break;
1169
1170 default:
1171 pmc->msg_state = GNUNET_PSYC_MESSAGE_STATE_ERROR;
1172 }
1173}
1174
1175
1176/**
1177 * Parse PSYC message.
1178 *
1179 * @param msg
1180 * The PSYC message to parse.
1181 * @param[out] method_name
1182 * Pointer to the method name inside @a pmsg.
1183 * @param env
1184 * The environment for the message with a list of modifiers.
1185 * @param[out] data
1186 * Pointer to data inside @a pmsg.
1187 * @param[out] data_size
1188 * Size of @data is written here.
1189 *
1190 * @return #GNUNET_OK on success,
1191 * #GNUNET_SYSERR on parse error.
1192 */
1193int
1194GNUNET_PSYC_message_parse (const struct GNUNET_PSYC_Message *msg,
1195 const char **method_name,
1196 struct GNUNET_ENV_Environment *env,
1197 const void **data,
1198 uint16_t *data_size)
1199{
1200 struct ParseMessageClosure cls;
1201 cls.env = env;
1202 cls.method_name = method_name;
1203 cls.data = data;
1204 cls.data_size = data_size;
1205
1206 uint16_t msg_size = ntohs (msg->header.size);
1207 struct GNUNET_PSYC_MessageHeader *
1208 pmsg = GNUNET_malloc (sizeof (*pmsg) + msg_size - sizeof (*msg));
1209 memcpy (&pmsg[1], &msg[1], msg_size - sizeof (*msg));
1210
1211 struct GNUNET_PSYC_ReceiveHandle *
1212 recv = GNUNET_PSYC_receive_create (NULL, &parse_message_part_cb, &cls);
1213 GNUNET_PSYC_receive_message (recv, pmsg);
1214 GNUNET_PSYC_receive_destroy (recv);
1215 GNUNET_free (pmsg);
1216
1217 return (GNUNET_PSYC_MESSAGE_STATE_END == cls.msg_state)
1218 ? GNUNET_OK
1219 : GNUNET_SYSERR;
1220}
diff --git a/src/psyc/test_psyc.c b/src/psyc/test_psyc.c
index 0077bc9b7..495e3be47 100644
--- a/src/psyc/test_psyc.c
+++ b/src/psyc/test_psyc.c
@@ -62,8 +62,6 @@ static struct GNUNET_CRYPTO_EcdsaPrivateKey *slave_key;
62static struct GNUNET_CRYPTO_EddsaPublicKey channel_pub_key; 62static struct GNUNET_CRYPTO_EddsaPublicKey channel_pub_key;
63static struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key; 63static struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key;
64 64
65struct GNUNET_PSYC_MasterTransmitHandle *mth;
66
67struct TransmitClosure 65struct TransmitClosure
68{ 66{
69 struct GNUNET_PSYC_MasterTransmitHandle *mst_tmit; 67 struct GNUNET_PSYC_MasterTransmitHandle *mst_tmit;
@@ -95,6 +93,28 @@ static void
95master_transmit (); 93master_transmit ();
96 94
97 95
96void master_stopped (void *cls)
97{
98 if (NULL != tmit)
99 {
100 GNUNET_ENV_environment_destroy (tmit->env);
101 GNUNET_free (tmit);
102 tmit = NULL;
103 }
104 GNUNET_SCHEDULER_shutdown ();
105}
106
107void slave_parted (void *cls)
108{
109 if (NULL != mst)
110 {
111 GNUNET_PSYC_master_stop (mst, GNUNET_NO, &master_stopped, NULL);
112 mst = NULL;
113 }
114 else
115 master_stopped (NULL);
116}
117
98/** 118/**
99 * Clean up all resources used. 119 * Clean up all resources used.
100 */ 120 */
@@ -103,21 +123,11 @@ cleanup ()
103{ 123{
104 if (NULL != slv) 124 if (NULL != slv)
105 { 125 {
106 GNUNET_PSYC_slave_part (slv); 126 GNUNET_PSYC_slave_part (slv, GNUNET_NO, &slave_parted, NULL);
107 slv = NULL; 127 slv = NULL;
108 } 128 }
109 if (NULL != mst) 129 else
110 { 130 slave_parted (NULL);
111 GNUNET_PSYC_master_stop (mst);
112 mst = NULL;
113 }
114 if (NULL != tmit)
115 {
116 GNUNET_ENV_environment_destroy (tmit->env);
117 GNUNET_free (tmit);
118 tmit = NULL;
119 }
120 GNUNET_SCHEDULER_shutdown ();
121} 131}
122 132
123 133
@@ -171,7 +181,20 @@ end ()
171 181
172static void 182static void
173master_message_cb (void *cls, uint64_t message_id, uint32_t flags, 183master_message_cb (void *cls, uint64_t message_id, uint32_t flags,
174 const struct GNUNET_MessageHeader *msg) 184 const struct GNUNET_PSYC_MessageHeader *msg)
185{
186 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
187 "Master got PSYC message fragment of size %u "
188 "belonging to message ID %llu with flags %x\n",
189 ntohs (msg->header.size), message_id, flags);
190 // FIXME
191}
192
193
194static void
195master_message_part_cb (void *cls, uint64_t message_id,
196 uint64_t data_offset, uint32_t flags,
197 const struct GNUNET_MessageHeader *msg)
175{ 198{
176 if (NULL == msg) 199 if (NULL == msg)
177 { 200 {
@@ -215,7 +238,20 @@ master_message_cb (void *cls, uint64_t message_id, uint32_t flags,
215 238
216static void 239static void
217slave_message_cb (void *cls, uint64_t message_id, uint32_t flags, 240slave_message_cb (void *cls, uint64_t message_id, uint32_t flags,
218 const struct GNUNET_MessageHeader *msg) 241 const struct GNUNET_PSYC_MessageHeader *msg)
242{
243 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
244 "Slave got PSYC message fragment of size %u "
245 "belonging to message ID %llu with flags %x\n",
246 ntohs (msg->header.size), message_id, flags);
247 // FIXME
248}
249
250
251static void
252slave_message_part_cb (void *cls, uint64_t message_id,
253 uint64_t data_offset, uint32_t flags,
254 const struct GNUNET_MessageHeader *msg)
219{ 255{
220 if (NULL == msg) 256 if (NULL == msg)
221 { 257 {
@@ -371,7 +407,7 @@ tmit_notify_mod (void *cls, uint16_t *data_size, void *data, uint8_t *oper,
371 memcpy (data, value, value_size); 407 memcpy (data, value, value_size);
372 } 408 }
373 409
374 return 0 == tmit->mod_value_size ? GNUNET_YES : GNUNET_NO; 410 return GNUNET_NO;
375} 411}
376 412
377 413
@@ -380,8 +416,10 @@ slave_join ();
380 416
381 417
382static void 418static void
383join_decision_cb (void *cls, int is_admitted, 419join_decision_cb (void *cls,
384 const struct GNUNET_PSYC_MessageHeader *join_msg) 420 const struct GNUNET_PSYC_JoinDecisionMessage *dcsn,
421 int is_admitted,
422 const struct GNUNET_PSYC_Message *join_msg)
385{ 423{
386 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 424 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
387 "Slave got join decision: %d\n", is_admitted); 425 "Slave got join decision: %d\n", is_admitted);
@@ -415,8 +453,10 @@ join_decision_cb (void *cls, int is_admitted,
415 453
416 454
417static void 455static void
418join_request_cb (void *cls, const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, 456join_request_cb (void *cls,
419 const struct GNUNET_PSYC_MessageHeader *msg, 457 const struct GNUNET_PSYC_JoinRequestMessage *req,
458 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
459 const struct GNUNET_PSYC_Message *join_msg,
420 struct GNUNET_PSYC_JoinHandle *jh) 460 struct GNUNET_PSYC_JoinHandle *jh)
421{ 461{
422 struct GNUNET_HashCode slave_key_hash; 462 struct GNUNET_HashCode slave_key_hash;
@@ -450,11 +490,11 @@ slave_join ()
450 "_foo", "bar baz", 7); 490 "_foo", "bar baz", 7);
451 GNUNET_ENV_environment_add (env, GNUNET_ENV_OP_ASSIGN, 491 GNUNET_ENV_environment_add (env, GNUNET_ENV_OP_ASSIGN,
452 "_foo_bar", "foo bar baz", 11); 492 "_foo_bar", "foo bar baz", 11);
453 struct GNUNET_MessageHeader * 493 struct GNUNET_PSYC_Message *
454 join_msg = GNUNET_PSYC_message_create ("_request_join", env, "some data", 9); 494 join_msg = GNUNET_PSYC_message_create ("_request_join", env, "some data", 9);
455 495
456 slv = GNUNET_PSYC_slave_join (cfg, &channel_pub_key, slave_key, &origin, 496 slv = GNUNET_PSYC_slave_join (cfg, &channel_pub_key, slave_key, &origin, 0, NULL,
457 0, NULL, &slave_message_cb, 497 &slave_message_cb, &slave_message_part_cb,
458 &slave_connect_cb, &join_decision_cb, NULL, 498 &slave_connect_cb, &join_decision_cb, NULL,
459 join_msg); 499 join_msg);
460 GNUNET_ENV_environment_destroy (env); 500 GNUNET_ENV_environment_destroy (env);
@@ -551,7 +591,8 @@ run (void *cls,
551 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Starting master.\n"); 591 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Starting master.\n");
552 mst = GNUNET_PSYC_master_start (cfg, channel_key, GNUNET_PSYC_CHANNEL_PRIVATE, 592 mst = GNUNET_PSYC_master_start (cfg, channel_key, GNUNET_PSYC_CHANNEL_PRIVATE,
553 &master_start_cb, &join_request_cb, 593 &master_start_cb, &join_request_cb,
554 &master_message_cb, NULL); 594 &master_message_cb, &master_message_part_cb,
595 NULL);
555} 596}
556 597
557 598
diff --git a/src/social/Makefile.am b/src/social/Makefile.am
index 04184dbc6..02b1bf823 100644
--- a/src/social/Makefile.am
+++ b/src/social/Makefile.am
@@ -24,6 +24,11 @@ libgnunetsocial_la_SOURCES = \
24libgnunetsocial_la_LIBADD = \ 24libgnunetsocial_la_LIBADD = \
25 $(top_builddir)/src/util/libgnunetutil.la \ 25 $(top_builddir)/src/util/libgnunetutil.la \
26 $(top_builddir)/src/env/libgnunetenv.la \ 26 $(top_builddir)/src/env/libgnunetenv.la \
27 $(top_builddir)/src/psyc/libgnunetpsycutil.la \
28 $(top_builddir)/src/core/libgnunetcore.la \
29 $(top_builddir)/src/identity/libgnunetidentity.la \
30 $(top_builddir)/src/gns/libgnunetgns.la \
31 $(top_builddir)/src/namestore/libgnunetnamestore.la \
27 $(GN_LIBINTL) $(XLIB) 32 $(GN_LIBINTL) $(XLIB)
28libgnunetsocial_la_LDFLAGS = \ 33libgnunetsocial_la_LDFLAGS = \
29 $(GN_LIB_LDFLAGS) $(WINFLAGS) \ 34 $(GN_LIB_LDFLAGS) $(WINFLAGS) \
diff --git a/src/social/gnunet-service-social.c b/src/social/gnunet-service-social.c
index ab67bedd6..90d12200d 100644
--- a/src/social/gnunet-service-social.c
+++ b/src/social/gnunet-service-social.c
@@ -32,6 +32,7 @@
32#include "gnunet_protocols.h" 32#include "gnunet_protocols.h"
33#include "gnunet_statistics_service.h" 33#include "gnunet_statistics_service.h"
34#include "gnunet_psyc_service.h" 34#include "gnunet_psyc_service.h"
35#include "gnunet_psyc_util_lib.h"
35#include "gnunet_social_service.h" 36#include "gnunet_social_service.h"
36#include "social.h" 37#include "social.h"
37 38
@@ -71,41 +72,56 @@ static struct GNUNET_CONTAINER_MultiHashMap *place_guests;
71 72
72 73
73/** 74/**
74 * Message in the transmission queue. 75 * Message fragment transmission queue.
75 */ 76 */
76struct TransmitMessage 77struct FragmentTransmitQueue
77{ 78{
78 struct TransmitMessage *prev; 79 struct FragmentTransmitQueue *prev;
79 struct TransmitMessage *next; 80 struct FragmentTransmitQueue *next;
80 81
81 struct GNUNET_SERVER_Client *client; 82 struct GNUNET_SERVER_Client *client;
82 83
83 /** 84 /**
84 * ID assigned to the message. 85 * Pointer to the next message part inside the data after this struct.
85 */ 86 */
86 uint64_t id; 87 struct GNUNET_MessageHeader *next_part;
87 88
88 /** 89 /**
89 * Size of @a buf 90 * Size of message.
90 */ 91 */
91 uint16_t size; 92 uint16_t size;
92 93
93 /** 94 /**
94 * @see enum MessageState 95 * @see enum GNUNET_PSYC_MessageState
95 */ 96 */
96 uint8_t state; 97 uint8_t state;
97 98
98 /* Followed by message */ 99 /* Followed by one or more message parts. */
99}; 100};
100 101
101 102
102/** 103/**
104 * Message transmission queue.
105 */
106struct MessageTransmitQueue
107{
108 struct MessageTransmitQueue *prev;
109 struct MessageTransmitQueue *next;
110
111 struct FragmentTransmitQueue *frags_head;
112 struct FragmentTransmitQueue *frags_tail;
113
114 struct GNUNET_SERVER_Client *client;
115};
116
117/**
103 * List of connected clients. 118 * List of connected clients.
104 */ 119 */
105struct ClientList 120struct ClientListItem
106{ 121{
107 struct ClientList *prev; 122 struct ClientListItem *prev;
108 struct ClientList *next; 123 struct ClientListItem *next;
124
109 struct GNUNET_SERVER_Client *client; 125 struct GNUNET_SERVER_Client *client;
110}; 126};
111 127
@@ -115,11 +131,11 @@ struct ClientList
115 */ 131 */
116struct Place 132struct Place
117{ 133{
118 struct ClientList *clients_head; 134 struct ClientListItem *clients_head;
119 struct ClientList *clients_tail; 135 struct ClientListItem *clients_tail;
120 136
121 struct TransmitMessage *tmit_head; 137 struct MessageTransmitQueue *tmit_msgs_head;
122 struct TransmitMessage *tmit_tail; 138 struct MessageTransmitQueue *tmit_msgs_tail;
123 139
124 /** 140 /**
125 * Public key of the channel. 141 * Public key of the channel.
@@ -132,9 +148,27 @@ struct Place
132 struct GNUNET_HashCode pub_key_hash; 148 struct GNUNET_HashCode pub_key_hash;
133 149
134 /** 150 /**
151 * Last message ID received for the place.
152 * 0 if there is no such message.
153 */
154 uint64_t max_message_id;
155
156 /**
135 * Is this a host (#GNUNET_YES), or guest (#GNUNET_NO)? 157 * Is this a host (#GNUNET_YES), or guest (#GNUNET_NO)?
136 */ 158 */
137 uint8_t is_host; 159 uint8_t is_host;
160
161 /**
162 * Is this place ready to receive messages from client?
163 * #GNUNET_YES or #GNUNET_NO
164 */
165 uint8_t is_ready;
166
167 /**
168 * Is the client disconnected?
169 * #GNUNET_YES or #GNUNET_NO
170 */
171 uint8_t is_disconnected;
138}; 172};
139 173
140 174
@@ -146,7 +180,7 @@ struct Host
146 /** 180 /**
147 * Place struct common for Host and Guest 181 * Place struct common for Host and Guest
148 */ 182 */
149 struct Place pl; 183 struct Place plc;
150 184
151 /** 185 /**
152 * Private key of the channel. 186 * Private key of the channel.
@@ -184,17 +218,17 @@ struct Guest
184 /** 218 /**
185 * Place struct common for Host and Guest. 219 * Place struct common for Host and Guest.
186 */ 220 */
187 struct Place pl; 221 struct Place plc;
188 222
189 /** 223 /**
190 * Private key of the slave. 224 * Private key of the slave.
191 */ 225 */
192 struct GNUNET_CRYPTO_EddsaPrivateKey priv_key; 226 struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key;
193 227
194 /** 228 /**
195 * Public key of the slave. 229 * Public key of the slave.
196 */ 230 */
197 struct GNUNET_CRYPTO_EddsaPublicKey pub_key; 231 struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
198 232
199 /** 233 /**
200 * Hash of @a pub_key. 234 * Hash of @a pub_key.
@@ -230,11 +264,32 @@ struct Guest
230 * Join request to be transmitted to the master on join. 264 * Join request to be transmitted to the master on join.
231 */ 265 */
232 struct GNUNET_MessageHeader *join_req; 266 struct GNUNET_MessageHeader *join_req;
267
268 /**
269 * Join decision received from PSYC.
270 */
271 struct GNUNET_PSYC_JoinDecisionMessage *join_dcsn;
272
273};
274
275
276struct Client
277{
278 /**
279 * Place where the client entered.
280 */
281 struct Place *plc;
282
283 /**
284 * Message queue for the message currently being transmitted
285 * by this client.
286 */
287 struct MessageTransmitQueue *tmit_msg;
233}; 288};
234 289
235 290
236static inline void 291static int
237transmit_message (struct Place *pl); 292psyc_transmit_message (struct Place *plc);
238 293
239 294
240/** 295/**
@@ -265,12 +320,12 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
265static void 320static void
266cleanup_host (struct Host *hst) 321cleanup_host (struct Host *hst)
267{ 322{
268 struct Place *pl = &hst->pl; 323 struct Place *plc = &hst->plc;
269 324
270 if (NULL != hst->master) 325 if (NULL != hst->master)
271 GNUNET_PSYC_master_stop (hst->master); 326 GNUNET_PSYC_master_stop (hst->master, GNUNET_NO, NULL, NULL); // FIXME
272 GNUNET_CONTAINER_multihashmap_destroy (hst->join_reqs); 327 GNUNET_CONTAINER_multihashmap_destroy (hst->join_reqs);
273 GNUNET_CONTAINER_multihashmap_remove (hosts, &pl->pub_key_hash, pl); 328 GNUNET_CONTAINER_multihashmap_remove (hosts, &plc->pub_key_hash, plc);
274} 329}
275 330
276 331
@@ -280,28 +335,28 @@ cleanup_host (struct Host *hst)
280static void 335static void
281cleanup_guest (struct Guest *gst) 336cleanup_guest (struct Guest *gst)
282{ 337{
283 struct Place *pl = &gst->pl; 338 struct Place *plc = &gst->plc;
284 struct GNUNET_CONTAINER_MultiHashMap * 339 struct GNUNET_CONTAINER_MultiHashMap *
285 pl_gst = GNUNET_CONTAINER_multihashmap_get (place_guests, 340 plc_gst = GNUNET_CONTAINER_multihashmap_get (place_guests,
286 &pl->pub_key_hash); 341 &plc->pub_key_hash);
287 GNUNET_assert (NULL != pl_gst); 342 GNUNET_assert (NULL != plc_gst);
288 GNUNET_CONTAINER_multihashmap_remove (pl_gst, &gst->pub_key_hash, gst); 343 GNUNET_CONTAINER_multihashmap_remove (plc_gst, &gst->pub_key_hash, gst);
289 344
290 if (0 == GNUNET_CONTAINER_multihashmap_size (pl_gst)) 345 if (0 == GNUNET_CONTAINER_multihashmap_size (plc_gst))
291 { 346 {
292 GNUNET_CONTAINER_multihashmap_remove (place_guests, &pl->pub_key_hash, 347 GNUNET_CONTAINER_multihashmap_remove (place_guests, &plc->pub_key_hash,
293 pl_gst); 348 plc_gst);
294 GNUNET_CONTAINER_multihashmap_destroy (pl_gst); 349 GNUNET_CONTAINER_multihashmap_destroy (plc_gst);
295 } 350 }
296 GNUNET_CONTAINER_multihashmap_remove (guests, &pl->pub_key_hash, gst); 351 GNUNET_CONTAINER_multihashmap_remove (guests, &plc->pub_key_hash, gst);
297 352
298 if (NULL != gst->join_req) 353 if (NULL != gst->join_req)
299 GNUNET_free (gst->join_req); 354 GNUNET_free (gst->join_req);
300 if (NULL != gst->relays) 355 if (NULL != gst->relays)
301 GNUNET_free (gst->relays); 356 GNUNET_free (gst->relays);
302 if (NULL != gst->slave) 357 if (NULL != gst->slave)
303 GNUNET_PSYC_slave_part (gst->slave); 358 GNUNET_PSYC_slave_part (gst->slave, GNUNET_NO, NULL, NULL); // FIXME
304 GNUNET_CONTAINER_multihashmap_remove (guests, &pl->pub_key_hash, pl); 359 GNUNET_CONTAINER_multihashmap_remove (guests, &plc->pub_key_hash, plc);
305} 360}
306 361
307 362
@@ -309,12 +364,23 @@ cleanup_guest (struct Guest *gst)
309 * Clean up place data structures after a client disconnected. 364 * Clean up place data structures after a client disconnected.
310 */ 365 */
311static void 366static void
312cleanup_place (struct Place *pl) 367cleanup_place (struct Place *plc)
313{ 368{
314 (GNUNET_YES == pl->is_host) 369 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
315 ? cleanup_host ((struct Host *) pl) 370 "%p Cleaning up place %s\n",
316 : cleanup_guest ((struct Guest *) pl); 371 plc, GNUNET_h2s (&plc->pub_key_hash));
317 GNUNET_free (pl); 372
373 (GNUNET_YES == plc->is_host)
374 ? cleanup_host ((struct Host *) plc)
375 : cleanup_guest ((struct Guest *) plc);
376 GNUNET_free (plc);
377}
378
379
380static void
381schedule_cleanup_place (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
382{
383 cleanup_place (cls);
318} 384}
319 385
320 386
@@ -331,76 +397,1073 @@ client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
331 if (NULL == client) 397 if (NULL == client)
332 return; 398 return;
333 399
334 struct Place * 400 struct Client *
335 pl = GNUNET_SERVER_client_get_user_context (client, struct Place); 401 ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
336 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 402 if (NULL == ctx)
337 "%p Client (%s) disconnected from place %s\n",
338 pl, (GNUNET_YES == pl->is_host) ? "host" : "guest",
339 GNUNET_h2s (&pl->pub_key_hash));
340
341 if (NULL == pl)
342 { 403 {
343 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 404 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
344 "%p User context is NULL in client_disconnect()\n", pl); 405 "%p User context is NULL in client_disconnect()\n", ctx);
345 GNUNET_break (0); 406 GNUNET_break (0);
346 return; 407 return;
347 } 408 }
348 409
349 struct ClientList *cl = pl->clients_head; 410 struct Place *plc = ctx->plc;
350 while (NULL != cl) 411 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
412 "%p Client (%s) disconnected from place %s\n",
413 plc, (GNUNET_YES == plc->is_host) ? "host" : "guest",
414 GNUNET_h2s (&plc->pub_key_hash));
415
416 struct ClientListItem *cli = plc->clients_head;
417 while (NULL != cli)
351 { 418 {
352 if (cl->client == client) 419 if (cli->client == client)
353 { 420 {
354 GNUNET_CONTAINER_DLL_remove (pl->clients_head, pl->clients_tail, cl); 421 GNUNET_CONTAINER_DLL_remove (plc->clients_head, plc->clients_tail, cli);
355 GNUNET_free (cl); 422 GNUNET_free (cli);
356 break; 423 break;
357 } 424 }
358 cl = cl->next; 425 cli = cli->next;
359 } 426 }
360 427
361 if (NULL == pl->clients_head) 428 if (NULL == plc->clients_head)
362 { /* Last client disconnected. */ 429 { /* Last client disconnected. */
363 if (NULL != pl->tmit_head) 430 if (GNUNET_YES != plc->is_disconnected)
364 { /* Send pending messages to PSYC before cleanup. */ 431 {
365 //FIXME: transmit_message (pl); 432 plc->is_disconnected = GNUNET_YES;
433 if (NULL != plc->tmit_msgs_head)
434 { /* Send pending messages to PSYC before cleanup. */
435 psyc_transmit_message (plc);
436 }
437 else
438 {
439 cleanup_place (plc);
440 }
366 } 441 }
367 else 442 }
443}
444
445
446/**
447 * Send message to all clients connected to the channel.
448 */
449static void
450client_send_msg (const struct Place *plc,
451 const struct GNUNET_MessageHeader *msg)
452{
453 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
454 "%p Sending message to clients.\n", plc);
455
456 struct ClientListItem *cli = plc->clients_head;
457 while (NULL != cli)
458 {
459 GNUNET_SERVER_notification_context_add (nc, cli->client);
460 GNUNET_SERVER_notification_context_unicast (nc, cli->client, msg, GNUNET_NO);
461 cli = cli->next;
462 }
463}
464
465
466/**
467 * Called after a PSYC master is started.
468 */
469static void
470psyc_master_started (void *cls, uint64_t max_message_id)
471{
472 struct Host *hst = cls;
473 struct Place *plc = &hst->plc;
474 plc->max_message_id = max_message_id;
475 plc->is_ready = GNUNET_YES;
476
477 struct CountersResult res;
478 res.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER_ACK);
479 res.header.size = htons (sizeof (res));
480 res.result_code = htonl (GNUNET_OK);
481 res.max_message_id = GNUNET_htonll (plc->max_message_id);
482
483 client_send_msg (plc, &res.header);
484}
485
486
487/**
488 * Called when a PSYC master receives a join request.
489 */
490static void
491psyc_recv_join_request (void *cls,
492 const struct GNUNET_PSYC_JoinRequestMessage *req,
493 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
494 const struct GNUNET_PSYC_Message *join_msg,
495 struct GNUNET_PSYC_JoinHandle *jh)
496{
497 struct Host *hst = cls;
498 struct GNUNET_HashCode slave_key_hash;
499 GNUNET_CRYPTO_hash (slave_key, sizeof (*slave_key), &slave_key_hash);
500 GNUNET_CONTAINER_multihashmap_put (hst->join_reqs, &slave_key_hash, jh,
501 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
502 client_send_msg (&hst->plc, &req->header);
503}
504
505
506/**
507 * Called after a PSYC slave is connected.
508 */
509static void
510psyc_slave_connected (void *cls, uint64_t max_message_id)
511{
512 struct Guest *gst = cls;
513 struct Place *plc = &gst->plc;
514 plc->max_message_id = max_message_id;
515 plc->is_ready = GNUNET_YES;
516
517 struct CountersResult res;
518 res.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_ACK);
519 res.header.size = htons (sizeof (res));
520 res.result_code = htonl (GNUNET_OK);
521 res.max_message_id = GNUNET_htonll (plc->max_message_id);
522
523 client_send_msg (plc, &res.header);
524}
525
526
527/**
528 * Called when a PSYC slave receives a join decision.
529 */
530static void
531psyc_recv_join_dcsn (void *cls,
532 const struct GNUNET_PSYC_JoinDecisionMessage *dcsn,
533 int is_admitted,
534 const struct GNUNET_PSYC_Message *join_msg)
535{
536 struct Guest *gst = cls;
537 client_send_msg (&gst->plc, &dcsn->header);
538}
539
540
541/**
542 * Called when a PSYC master or slave receives a message.
543 */
544static void
545psyc_recv_message (void *cls,
546 uint64_t message_id,
547 uint32_t flags,
548 const struct GNUNET_PSYC_MessageHeader *msg)
549{
550 struct Place *plc = cls;
551 client_send_msg (plc, &msg->header);
552
553 /* FIXME: further processing */
554}
555
556
557/**
558 * Initialize place data structure.
559 */
560static void
561place_init (struct Place *plc)
562{
563
564}
565
566
567/**
568 * Handle a connecting client entering a place as host.
569 */
570static void
571client_recv_host_enter (void *cls, struct GNUNET_SERVER_Client *client,
572 const struct GNUNET_MessageHeader *msg)
573{
574 const struct HostEnterRequest *req
575 = (const struct HostEnterRequest *) msg;
576
577 struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
578 struct GNUNET_HashCode pub_key_hash;
579
580 GNUNET_CRYPTO_eddsa_key_get_public (&req->place_key, &pub_key);
581 GNUNET_CRYPTO_hash (&pub_key, sizeof (pub_key), &pub_key_hash);
582
583 struct Host *
584 hst = GNUNET_CONTAINER_multihashmap_get (hosts, &pub_key_hash);
585 struct Place *plc;
586
587 if (NULL == hst)
588 {
589 hst = GNUNET_new (struct Host);
590 hst->policy = ntohl (req->policy);
591 hst->priv_key = req->place_key;
592 hst->join_reqs = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
593
594 plc = &hst->plc;
595 plc->is_host = GNUNET_YES;
596 plc->pub_key = pub_key;
597 plc->pub_key_hash = pub_key_hash;
598 place_init (plc);
599
600 GNUNET_CONTAINER_multihashmap_put (hosts, &plc->pub_key_hash, plc,
601 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
602 hst->master = GNUNET_PSYC_master_start (cfg, &hst->priv_key, hst->policy,
603 &psyc_master_started,
604 &psyc_recv_join_request,
605 &psyc_recv_message, NULL, hst);
606 }
607 else
608 {
609 plc = &hst->plc;
610
611 struct CountersResult res;
612 res.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER_ACK);
613 res.header.size = htons (sizeof (res));
614 res.result_code = htonl (GNUNET_OK);
615 res.max_message_id = GNUNET_htonll (plc->max_message_id);
616
617 GNUNET_SERVER_notification_context_add (nc, client);
618 GNUNET_SERVER_notification_context_unicast (nc, client, &res.header,
619 GNUNET_NO);
620 }
621
622 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
623 "%p Client connected as host to place %s.\n",
624 hst, GNUNET_h2s (&plc->pub_key_hash));
625
626 struct ClientListItem *cli = GNUNET_new (struct ClientListItem);
627 cli->client = client;
628 GNUNET_CONTAINER_DLL_insert (plc->clients_head, plc->clients_tail, cli);
629
630 struct Client *ctx = GNUNET_new (struct Client);
631 ctx->plc = plc;
632 GNUNET_SERVER_client_set_user_context (client, ctx);
633 GNUNET_SERVER_receive_done (client, GNUNET_OK);
634}
635
636
637/**
638 * Handle a connecting client entering a place as guest.
639 */
640static void
641client_recv_guest_enter (void *cls, struct GNUNET_SERVER_Client *client,
642 const struct GNUNET_MessageHeader *msg)
643{
644 const struct GuestEnterRequest *req
645 = (const struct GuestEnterRequest *) msg;
646 uint16_t req_size = ntohs (req->header.size);
647
648 struct GNUNET_CRYPTO_EcdsaPublicKey gst_pub_key;
649 struct GNUNET_HashCode pub_key_hash, gst_pub_key_hash;
650
651 GNUNET_CRYPTO_ecdsa_key_get_public (&req->guest_key, &gst_pub_key);
652 GNUNET_CRYPTO_hash (&gst_pub_key, sizeof (gst_pub_key), &gst_pub_key_hash);
653 GNUNET_CRYPTO_hash (&req->place_key, sizeof (req->place_key), &pub_key_hash);
654
655 struct GNUNET_CONTAINER_MultiHashMap *
656 plc_gst = GNUNET_CONTAINER_multihashmap_get (place_guests, &pub_key_hash);
657 struct Guest *gst = NULL;
658 struct Place *plc;
659
660 if (NULL != plc_gst)
661 {
662 gst = GNUNET_CONTAINER_multihashmap_get (plc_gst, &gst_pub_key_hash);
663 }
664 if (NULL == gst || NULL == gst->slave)
665 {
666 gst = GNUNET_new (struct Guest);
667 gst->priv_key = req->guest_key;
668 gst->pub_key = gst_pub_key;
669 gst->pub_key_hash = gst_pub_key_hash;
670 gst->origin = req->origin;
671 gst->relay_count = ntohl (req->relay_count);
672
673 const struct GNUNET_PeerIdentity *
674 relays = (const struct GNUNET_PeerIdentity *) &req[1];
675 uint16_t relay_size = gst->relay_count * sizeof (*relays);
676 struct GNUNET_PSYC_Message *join_msg = NULL;
677 uint16_t join_msg_size = 0;
678
679 if (sizeof (*req) + relay_size + sizeof (struct GNUNET_MessageHeader)
680 <= req_size)
681 {
682 join_msg = (struct GNUNET_PSYC_Message *)
683 (((char *) &req[1]) + relay_size);
684 join_msg_size = ntohs (join_msg->header.size);
685 }
686 if (sizeof (*req) + relay_size + join_msg_size != req_size)
687 {
688 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
689 "%u + %u + %u != %u\n",
690 sizeof (*req), relay_size, join_msg_size, req_size);
691 GNUNET_break (0);
692 GNUNET_SERVER_client_disconnect (client);
693 return;
694 }
695 if (0 < gst->relay_count)
696 {
697 gst->relays = GNUNET_malloc (relay_size);
698 memcpy (gst->relays, &req[1], relay_size);
699 }
700
701 plc = &gst->plc;
702 plc->is_host = GNUNET_NO;
703 plc->pub_key = req->place_key;
704 plc->pub_key_hash = pub_key_hash;
705 place_init (plc);
706
707 if (NULL == plc_gst)
708 {
709 plc_gst = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
710 GNUNET_CONTAINER_multihashmap_put (place_guests, &plc->pub_key_hash, plc_gst,
711 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
712 }
713 GNUNET_CONTAINER_multihashmap_put (plc_gst, &gst->pub_key_hash, plc,
714 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
715 GNUNET_CONTAINER_multihashmap_put (guests, &plc->pub_key_hash, plc,
716 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
717 gst->slave
718 = GNUNET_PSYC_slave_join (cfg, &plc->pub_key, &gst->priv_key,
719 &gst->origin, gst->relay_count, gst->relays,
720 &psyc_recv_message, NULL, &psyc_slave_connected,
721 &psyc_recv_join_dcsn, gst, join_msg);
722 }
723 else
724 {
725 plc = &gst->plc;
726
727 struct CountersResult res;
728 res.header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_ACK);
729 res.header.size = htons (sizeof (res));
730 res.result_code = htonl (GNUNET_OK);
731 res.max_message_id = GNUNET_htonll (plc->max_message_id);
732
733 GNUNET_SERVER_notification_context_add (nc, client);
734 GNUNET_SERVER_notification_context_unicast (nc, client, &res.header,
735 GNUNET_NO);
736 if (NULL != gst->join_dcsn)
368 { 737 {
369 cleanup_place (pl); 738 GNUNET_SERVER_notification_context_add (nc, client);
739 GNUNET_SERVER_notification_context_unicast (nc, client,
740 &gst->join_dcsn->header,
741 GNUNET_NO);
370 } 742 }
371 } 743 }
744
745 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
746 "%p Client connected as guest to place %s.\n",
747 gst, GNUNET_h2s (&plc->pub_key_hash));
748
749 struct ClientListItem *cli = GNUNET_new (struct ClientListItem);
750 cli->client = client;
751 GNUNET_CONTAINER_DLL_insert (plc->clients_head, plc->clients_tail, cli);
752
753 struct Client *ctx = GNUNET_new (struct Client);
754 ctx->plc = plc;
755 GNUNET_SERVER_client_set_user_context (client, ctx);
756 GNUNET_SERVER_receive_done (client, GNUNET_OK);
372} 757}
373 758
374 759
760struct JoinDecisionClosure
761{
762 int32_t is_admitted;
763 struct GNUNET_PSYC_Message *msg;
764};
765
766
767/**
768 * Iterator callback for responding to join requests.
769 */
770static int
771psyc_send_join_decision (void *cls, const struct GNUNET_HashCode *pub_key_hash,
772 void *value)
773{
774 struct JoinDecisionClosure *jcls = cls;
775 struct GNUNET_PSYC_JoinHandle *jh = value;
776 // FIXME: add relays
777 GNUNET_PSYC_join_decision (jh, jcls->is_admitted, 0, NULL, jcls->msg);
778 return GNUNET_YES;
779}
780
781
782/**
783 * Handle an entry decision from a host client.
784 */
375static void 785static void
376client_home_enter (void *cls, struct GNUNET_SERVER_Client *client, 786client_recv_join_decision (void *cls, struct GNUNET_SERVER_Client *client,
377 const struct GNUNET_MessageHeader *msg) 787 const struct GNUNET_MessageHeader *msg)
378{ 788{
789 struct Client *
790 ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
791 GNUNET_assert (NULL != ctx);
792 struct Place *plc = ctx->plc;
793 GNUNET_assert (GNUNET_YES == plc->is_host);
794 struct Host *hst = (struct Host *) plc;
795
796 struct GNUNET_PSYC_JoinDecisionMessage *
797 dcsn = (struct GNUNET_PSYC_JoinDecisionMessage *) msg;
798 struct JoinDecisionClosure jcls;
799 jcls.is_admitted = ntohl (dcsn->is_admitted);
800 jcls.msg
801 = (sizeof (*dcsn) + sizeof (*jcls.msg) <= ntohs (msg->size))
802 ? (struct GNUNET_PSYC_Message *) &dcsn[1]
803 : NULL;
804
805 struct GNUNET_HashCode slave_key_hash;
806 GNUNET_CRYPTO_hash (&dcsn->slave_key, sizeof (dcsn->slave_key),
807 &slave_key_hash);
379 808
809 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
810 "%p Got join decision (%d) from client for place %s..\n",
811 hst, jcls.is_admitted, GNUNET_h2s (&plc->pub_key_hash));
812 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
813 "%p ..and slave %s.\n",
814 hst, GNUNET_h2s (&slave_key_hash));
815
816 GNUNET_CONTAINER_multihashmap_get_multiple (hst->join_reqs, &slave_key_hash,
817 &psyc_send_join_decision, &jcls);
818 GNUNET_CONTAINER_multihashmap_remove_all (hst->join_reqs, &slave_key_hash);
819 GNUNET_SERVER_receive_done (client, GNUNET_OK);
380} 820}
381 821
382 822
823/**
824 * Send acknowledgement to a client.
825 *
826 * Sent after a message fragment has been passed on to multicast.
827 *
828 * @param plc The place struct for the client.
829 */
383static void 830static void
384client_place_enter (void *cls, struct GNUNET_SERVER_Client *client, 831send_message_ack (struct Place *plc, struct GNUNET_SERVER_Client *client)
385 const struct GNUNET_MessageHeader *msg) 832{
833 struct GNUNET_MessageHeader res;
834 res.size = htons (sizeof (res));
835 res.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK);
836
837 GNUNET_SERVER_notification_context_add (nc, client);
838 GNUNET_SERVER_notification_context_unicast (nc, client, &res, GNUNET_NO);
839}
840
841
842/**
843 * Proceed to the next message part in the transmission queue.
844 *
845 * @param plc
846 * Place where the transmission is going on.
847 * @param tmit_msg
848 * Currently transmitted message.
849 * @param tmit_frag
850 * Currently transmitted message fragment.
851 *
852 * @return @a tmit_frag, or NULL if reached the end of fragment.
853 */
854static struct FragmentTransmitQueue *
855psyc_transmit_queue_next_part (struct Place *plc,
856 struct MessageTransmitQueue *tmit_msg,
857 struct FragmentTransmitQueue *tmit_frag)
858{
859 uint16_t psize = ntohs (tmit_frag->next_part->size);
860 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
861 "%p psyc_transmit_queue_next_part: %x + %u - %x = %u < %u\n",
862 plc, tmit_frag->next_part, psize, &tmit_frag[1],
863 (char *) tmit_frag->next_part + psize - ((char *) &tmit_frag[1]),
864 tmit_frag->size);
865 if ((char *) tmit_frag->next_part + psize - ((char *) &tmit_frag[1])
866 < tmit_frag->size)
867 {
868 tmit_frag->next_part
869 = (struct GNUNET_MessageHeader *) ((char *) tmit_frag->next_part + psize);
870 }
871 else /* Reached end of current fragment. */
872 {
873 if (NULL != tmit_frag->client)
874 send_message_ack (plc, tmit_frag->client);
875 GNUNET_CONTAINER_DLL_remove (tmit_msg->frags_head, tmit_msg->frags_tail, tmit_frag);
876 GNUNET_free (tmit_frag);
877 tmit_frag = NULL;
878 }
879 return tmit_frag;
880}
881
882
883/**
884 * Proceed to next message in transmission queue.
885 *
886 * @param plc
887 * Place where the transmission is going on.
888 * @param tmit_msg
889 * Currently transmitted message.
890 *
891 * @return The next message in queue, or NULL if queue is empty.
892 */
893static struct MessageTransmitQueue *
894psyc_transmit_queue_next_msg (struct Place *plc,
895 struct MessageTransmitQueue *tmit_msg)
896{
897 GNUNET_CONTAINER_DLL_remove (plc->tmit_msgs_head, plc->tmit_msgs_tail, tmit_msg);
898 GNUNET_free (tmit_msg);
899 return plc->tmit_msgs_head;
900}
901
902
903/**
904 * Callback for data transmission to PSYC.
905 */
906static int
907psyc_transmit_notify_data (void *cls, uint16_t *data_size, void *data)
386{ 908{
909 struct Place *plc = cls;
910 struct MessageTransmitQueue *tmit_msg = plc->tmit_msgs_head;
911 GNUNET_assert (NULL != tmit_msg);
912 struct FragmentTransmitQueue *tmit_frag = tmit_msg->frags_head;
913 if (NULL == tmit_frag)
914 { /* Rest of the message have not arrived yet, pause transmission */
915 *data_size = 0;
916 return GNUNET_NO;
917 }
918 struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part;
919 if (NULL == pmsg)
920 {
921 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
922 "%p psyc_transmit_notify_data: nothing to send.\n", plc);
923 *data_size = 0;
924 return GNUNET_NO;
925 }
387 926
927 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
928 "%p psyc_transmit_notify_data()\n", plc);
929 GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, pmsg);
930
931 uint16_t ptype = ntohs (pmsg->type);
932 uint16_t pdata_size = ntohs (pmsg->size) - sizeof (*pmsg);
933 int ret;
934
935 switch (ptype)
936 {
937 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
938 if (*data_size < pdata_size)
939 {
940 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
941 "%p psyc_transmit_notify_data: buffer size too small for data.\n", plc);
942 *data_size = 0;
943 return GNUNET_NO;
944 }
945 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
946 "%p psyc_transmit_notify_data: sending %u bytes.\n",
947 plc, pdata_size);
948
949 *data_size = pdata_size;
950 memcpy (data, &pmsg[1], *data_size);
951 ret = GNUNET_NO;
952 break;
953
954 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
955 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
956 *data_size = 0;
957 ret = GNUNET_YES;
958 break;
959
960 default:
961 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
962 "%p psyc_transmit_notify_data: unexpected message part of type %u.\n",
963 plc, ptype);
964 ret = GNUNET_SYSERR;
965 }
966
967 if (GNUNET_SYSERR == ret)
968 {
969 *data_size = 0;
970 tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg);
971 plc->is_disconnected = GNUNET_YES;
972 GNUNET_SERVER_client_disconnect (tmit_frag->client);
973 GNUNET_SCHEDULER_add_now (&schedule_cleanup_place, plc);
974 return ret;
975 }
976 else
977 {
978 psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag);
979
980 if (NULL == tmit_msg->frags_head
981 && GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= ptype)
982 { /* Reached end of current message. */
983 tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg);
984 }
985 }
986
987 if (ret != GNUNET_NO)
988 {
989 if (NULL != tmit_msg)
990 {
991 psyc_transmit_message (plc);
992 }
993 else if (GNUNET_YES == plc->is_disconnected)
994 {
995 /* FIXME: handle partial message (when still in_transmit) */
996 cleanup_place (plc);
997 }
998 }
999 return ret;
388} 1000}
389 1001
390 1002
1003/**
1004 * Callback for modifier transmission to PSYC.
1005 */
1006static int
1007psyc_transmit_notify_mod (void *cls, uint16_t *data_size, void *data,
1008 uint8_t *oper, uint32_t *full_value_size)
1009{
1010 struct Place *plc = cls;
1011 struct MessageTransmitQueue *tmit_msg = plc->tmit_msgs_head;
1012 GNUNET_assert (NULL != tmit_msg);
1013 struct FragmentTransmitQueue *tmit_frag = tmit_msg->frags_head;
1014 if (NULL == tmit_frag)
1015 { /* Rest of the message have not arrived yet, pause transmission */
1016 *data_size = 0;
1017 return GNUNET_NO;
1018 }
1019 struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part;
1020 if (NULL == pmsg)
1021 {
1022 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1023 "%p psyc_transmit_notify_mod: nothing to send.\n", plc);
1024 *data_size = 0;
1025 return GNUNET_NO;
1026 }
1027
1028 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1029 "%p psyc_transmit_notify_mod()\n", plc);
1030 GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, pmsg);
1031
1032 uint16_t ptype = ntohs (pmsg->type);
1033 int ret;
1034
1035 switch (ptype)
1036 {
1037 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
1038 {
1039 if (NULL == oper)
1040 {
1041 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1042 "%p psyc_transmit_notify_mod: oper is NULL.\n", plc);
1043 ret = GNUNET_SYSERR;
1044 break;
1045 }
1046 struct GNUNET_PSYC_MessageModifier *
1047 pmod = (struct GNUNET_PSYC_MessageModifier *) tmit_frag->next_part;
1048 uint16_t mod_size = ntohs (pmod->header.size) - sizeof (*pmod);
1049
1050 if (*data_size < mod_size)
1051 {
1052 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1053 "%p psyc_transmit_notify_mod: buffer size too small for data.\n", plc);
1054 *data_size = 0;
1055 return GNUNET_NO;
1056 }
1057
1058 *full_value_size = ntohl (pmod->value_size);
1059 *oper = pmod->oper;
1060 *data_size = mod_size;
1061 memcpy (data, &pmod[1], mod_size);
1062 ret = GNUNET_NO;
1063#if REMOVE // FIXME
1064 ret = (mod_size - strnlen ((char *) &pmod[1], mod_size) - 1
1065 == *full_value_size)
1066 ? GNUNET_YES
1067 : GNUNET_NO;
1068#endif
1069 break;
1070 }
1071
1072 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
1073 {
1074 if (NULL != oper)
1075 {
1076 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1077 "%p psyc_transmit_notify_mod: oper is not NULL.\n", plc);
1078 ret = GNUNET_SYSERR;
1079 break;
1080 }
1081 uint16_t mod_size = ntohs (pmsg->size) - sizeof (*pmsg);
1082 if (*data_size < mod_size)
1083 {
1084 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1085 "%p psyc_transmit_notify_mod: buffer size too small for data.\n", plc);
1086 *data_size = 0;
1087 return GNUNET_NO;
1088 }
1089 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1090 "%p psyc_transmit_notify_mod: sending %u bytes.\n", plc, mod_size);
1091
1092 *data_size = mod_size;
1093 memcpy (data, &pmsg[1], *data_size);
1094 ret = GNUNET_NO;
1095 break;
1096 }
1097
1098 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
1099 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
1100 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
1101 *data_size = 0;
1102 ret = GNUNET_YES;
1103 break;
1104
1105 default:
1106 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1107 "%p psyc_transmit_notify_mod: unexpected message part of type %u.\n",
1108 plc, ptype);
1109 ret = GNUNET_SYSERR;
1110 }
1111
1112 if (GNUNET_SYSERR == ret)
1113 {
1114 *data_size = 0;
1115 ret = GNUNET_SYSERR;
1116 tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg);
1117 plc->is_disconnected = GNUNET_YES;
1118 GNUNET_SERVER_client_disconnect (tmit_frag->client);
1119 GNUNET_SCHEDULER_add_now (&schedule_cleanup_place, plc);
1120 }
1121 else
1122 {
1123 psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag);
1124
1125 if (NULL == tmit_msg->frags_head
1126 && GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= ptype)
1127 { /* Reached end of current message. */
1128 tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg);
1129 }
1130 }
1131 return ret;
1132}
1133
1134/**
1135 * Callback for data transmission from a host to PSYC.
1136 */
1137static int
1138host_transmit_notify_data (void *cls, uint16_t *data_size, void *data)
1139{
1140 int ret = psyc_transmit_notify_data (cls, data_size, data);
1141
1142 if (GNUNET_NO != ret)
1143 {
1144 struct Host *hst = cls;
1145 hst->tmit_handle = NULL;
1146 }
1147 return ret;
1148}
1149
1150
1151/**
1152 * Callback for the transmit functions of multicast.
1153 */
1154static int
1155guest_transmit_notify_data (void *cls, uint16_t *data_size, void *data)
1156{
1157 int ret = psyc_transmit_notify_data (cls, data_size, data);
1158
1159 if (GNUNET_NO != ret)
1160 {
1161 struct Guest *gst = cls;
1162 gst->tmit_handle = NULL;
1163 }
1164 return ret;
1165}
1166
1167
1168/**
1169 * Callback for modifier transmission from a host to PSYC.
1170 */
1171static int
1172host_transmit_notify_mod (void *cls, uint16_t *data_size, void *data,
1173 uint8_t *oper, uint32_t *full_value_size)
1174{
1175 int ret = psyc_transmit_notify_mod (cls, data_size, data,
1176 oper, full_value_size);
1177 if (GNUNET_SYSERR == ret)
1178 {
1179 struct Host *hst = cls;
1180 hst->tmit_handle = NULL;
1181 }
1182 return ret;
1183}
1184
1185
1186/**
1187 * Callback for modifier transmission from a guest to PSYC.
1188 */
1189static int
1190guest_transmit_notify_mod (void *cls, uint16_t *data_size, void *data,
1191 uint8_t *oper, uint32_t *full_value_size)
1192{
1193 int ret = psyc_transmit_notify_mod (cls, data_size, data,
1194 oper, full_value_size);
1195 if (GNUNET_SYSERR == ret)
1196 {
1197 struct Guest *gst = cls;
1198 gst->tmit_handle = NULL;
1199 }
1200 return ret;
1201}
1202
1203
1204/**
1205 * Get method part of next message from transmission queue.
1206 *
1207 * @param tmit_msg
1208 * Next item in message transmission queue.
1209 * @param[out] pmeth
1210 * The message method is returned here.
1211 *
1212 * @return #GNUNET_OK on success
1213 * #GNUNET_NO if there are no more messages in queue.
1214 * #GNUNET_SYSERR if the next message is malformed.
1215 */
1216static int
1217psyc_transmit_queue_next_method (struct Place *plc,
1218 struct GNUNET_PSYC_MessageMethod **pmeth)
1219{
1220 struct MessageTransmitQueue *tmit_msg = plc->tmit_msgs_head;
1221 if (NULL == tmit_msg)
1222 return GNUNET_NO;
1223
1224 struct FragmentTransmitQueue *tmit_frag = tmit_msg->frags_head;
1225 if (NULL == tmit_frag)
1226 {
1227 GNUNET_break (0);
1228 return GNUNET_NO;
1229 }
1230
1231 struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part;
1232 if (NULL == pmsg
1233 || GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD != ntohs (pmsg->type))
1234 {
1235 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1236 "%p psyc_transmit_queue_next_method: unexpected message part of type %u.\n",
1237 plc, ntohs (pmsg->type));
1238 GNUNET_break (0);
1239 return GNUNET_SYSERR;
1240 }
1241
1242 uint16_t psize = ntohs (pmsg->size);
1243 *pmeth = (struct GNUNET_PSYC_MessageMethod *) pmsg;
1244
1245 if (psize < sizeof (**pmeth) + 1 || '\0' != *((char *) *pmeth + psize - 1))
1246 {
1247 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1248 "%p psyc_transmit_queue_next_method: invalid method name.\n",
1249 plc, ntohs (pmsg->type));
1250 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1251 "%u <= %u || NUL != %u\n",
1252 sizeof (**pmeth), psize, *((char *) *pmeth + psize - 1));
1253 GNUNET_break (0);
1254 return GNUNET_SYSERR;
1255 }
1256 psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag);
1257 return GNUNET_OK;
1258}
1259
1260
1261/**
1262 * Transmit the next message in queue from the host to the PSYC channel.
1263 */
1264static int
1265psyc_master_transmit_message (struct Host *hst)
1266{
1267
1268 if (NULL == hst->tmit_handle)
1269 {
1270 struct GNUNET_PSYC_MessageMethod *pmeth = NULL;
1271 int ret = psyc_transmit_queue_next_method (&hst->plc, &pmeth);
1272 if (GNUNET_OK != ret)
1273 return ret;
1274
1275 hst->tmit_handle
1276 = GNUNET_PSYC_master_transmit (hst->master, (const char *) &pmeth[1],
1277 &host_transmit_notify_mod,
1278 &host_transmit_notify_data, hst,
1279 pmeth->flags);
1280 }
1281 else
1282 {
1283 GNUNET_PSYC_master_transmit_resume (hst->tmit_handle);
1284 }
1285 return GNUNET_OK;
1286}
1287
1288
1289/**
1290 * Transmit the next message in queue from a guest to the PSYC channel.
1291 */
1292static int
1293psyc_slave_transmit_message (struct Guest *gst)
1294{
1295 if (NULL == gst->tmit_handle)
1296 {
1297 struct GNUNET_PSYC_MessageMethod *pmeth = NULL;
1298 int ret = psyc_transmit_queue_next_method (&gst->plc, &pmeth);
1299 if (GNUNET_OK != ret)
1300 return ret;
1301
1302 gst->tmit_handle
1303 = GNUNET_PSYC_slave_transmit (gst->slave, (const char *) &pmeth[1],
1304 &guest_transmit_notify_mod,
1305 &guest_transmit_notify_data, gst,
1306 pmeth->flags);
1307 }
1308 else
1309 {
1310 GNUNET_PSYC_slave_transmit_resume (gst->tmit_handle);
1311 }
1312 return GNUNET_OK;
1313}
1314
1315
1316/**
1317 * Transmit a message to PSYC.
1318 */
1319static int
1320psyc_transmit_message (struct Place *plc)
1321{
1322 return
1323 (plc->is_host)
1324 ? psyc_master_transmit_message ((struct Host *) plc)
1325 : psyc_slave_transmit_message ((struct Guest *) plc);
1326}
1327
1328
1329/**
1330 * Queue message parts for sending to PSYC.
1331 *
1332 * @param plc Place to send to.
1333 * @param client Client the message originates from.
1334 * @param data_size Size of @a data.
1335 * @param data Concatenated message parts.
1336 * @param first_ptype First message part type in @a data.
1337 * @param last_ptype Last message part type in @a data.
1338 */
1339static struct MessageTransmitQueue *
1340psyc_transmit_queue_message (struct Place *plc,
1341 struct GNUNET_SERVER_Client *client,
1342 size_t data_size,
1343 const void *data,
1344 uint16_t first_ptype, uint16_t last_ptype,
1345 struct MessageTransmitQueue *tmit_msg)
1346{
1347 if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == first_ptype)
1348 {
1349 tmit_msg = GNUNET_malloc (sizeof (*tmit_msg));
1350 GNUNET_CONTAINER_DLL_insert_tail (plc->tmit_msgs_head, plc->tmit_msgs_tail, tmit_msg);
1351 }
1352 else if (NULL == tmit_msg)
1353 {
1354 return NULL;
1355 }
1356
1357 struct FragmentTransmitQueue *
1358 tmit_frag = GNUNET_malloc (sizeof (*tmit_frag) + data_size);
1359 memcpy (&tmit_frag[1], data, data_size);
1360 tmit_frag->next_part = (struct GNUNET_MessageHeader *) &tmit_frag[1];
1361 tmit_frag->client = client;
1362 tmit_frag->size = data_size;
1363
1364 GNUNET_CONTAINER_DLL_insert_tail (tmit_msg->frags_head, tmit_msg->frags_tail, tmit_frag);
1365 tmit_msg->client = client;
1366 return tmit_msg;
1367}
1368
1369
1370/**
1371 * Cancel transmission of current message to PSYC.
1372 *
1373 * @param plc Place to send to.
1374 * @param client Client the message originates from.
1375 */
391static void 1376static void
392client_join_decision (void *cls, struct GNUNET_SERVER_Client *client, 1377psyc_transmit_cancel (struct Place *plc, struct GNUNET_SERVER_Client *client)
393 const struct GNUNET_MessageHeader *msg)
394{ 1378{
1379 uint16_t type = GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL;
1380
1381 struct GNUNET_MessageHeader msg;
1382 msg.size = htons (sizeof (msg));
1383 msg.type = htons (type);
395 1384
1385 psyc_transmit_queue_message (plc, client, sizeof (msg), &msg, type, type, NULL);
1386 psyc_transmit_message (plc);
1387
1388 /* FIXME: cleanup */
396} 1389}
397 1390
398 1391
1392/**
1393 * Handle an incoming message from a client, to be transmitted to the place.
1394 */
399static void 1395static void
400client_psyc_message (void *cls, struct GNUNET_SERVER_Client *client, 1396client_recv_psyc_message (void *cls, struct GNUNET_SERVER_Client *client,
401 const struct GNUNET_MessageHeader *msg) 1397 const struct GNUNET_MessageHeader *msg)
402{ 1398{
1399 struct Client *
1400 ctx = GNUNET_SERVER_client_get_user_context (client, struct Client);
1401 GNUNET_assert (NULL != ctx);
1402 struct Place *plc = ctx->plc;
1403 int ret = GNUNET_SYSERR;
403 1404
1405 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1406 "%p Received message from client.\n", plc);
1407 GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, msg);
1408
1409 if (GNUNET_YES != plc->is_ready)
1410 {
1411 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1412 "%p Place is not ready yet, disconnecting client.\n", plc);
1413 GNUNET_break (0);
1414 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1415 return;
1416 }
1417
1418 uint16_t size = ntohs (msg->size);
1419 uint16_t psize = size - sizeof (*msg);
1420 if (psize < sizeof (struct GNUNET_MessageHeader)
1421 || GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD < psize)
1422 {
1423 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1424 "%p Received message with invalid payload size (%u) from client.\n",
1425 plc, psize);
1426 GNUNET_break (0);
1427 psyc_transmit_cancel (plc, client);
1428 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1429 return;
1430 }
1431
1432 uint16_t first_ptype = 0, last_ptype = 0;
1433 if (GNUNET_SYSERR
1434 == GNUNET_PSYC_receive_check_parts (psize, (const char *) &msg[1],
1435 &first_ptype, &last_ptype))
1436 {
1437 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1438 "%p Received invalid message part from client.\n", plc);
1439 GNUNET_break (0);
1440 psyc_transmit_cancel (plc, client);
1441 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1442 return;
1443 }
1444 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1445 "%p Received message with first part type %u and last part type %u.\n",
1446 plc, first_ptype, last_ptype);
1447
1448 ctx->tmit_msg
1449 = psyc_transmit_queue_message (plc, client, psize, &msg[1],
1450 first_ptype, last_ptype, ctx->tmit_msg);
1451 if (NULL != ctx->tmit_msg)
1452 {
1453 if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= last_ptype)
1454 ctx->tmit_msg = NULL;
1455 ret = psyc_transmit_message (plc);
1456 }
1457
1458 if (GNUNET_OK != ret)
1459 {
1460 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1461 "%p Received invalid message part from client.\n", plc);
1462 GNUNET_break (0);
1463 psyc_transmit_cancel (plc, client);
1464 ret = GNUNET_SYSERR;
1465 }
1466 GNUNET_SERVER_receive_done (client, ret);
404} 1467}
405 1468
406 1469
@@ -416,16 +1479,16 @@ run (void *cls, struct GNUNET_SERVER_Handle *server,
416 const struct GNUNET_CONFIGURATION_Handle *c) 1479 const struct GNUNET_CONFIGURATION_Handle *c)
417{ 1480{
418 static const struct GNUNET_SERVER_MessageHandler handlers[] = { 1481 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
419 { &client_home_enter, NULL, 1482 { &client_recv_host_enter, NULL,
420 GNUNET_MESSAGE_TYPE_SOCIAL_HOME_ENTER, 0 }, 1483 GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER, 0 },
421 1484
422 { &client_place_enter, NULL, 1485 { &client_recv_guest_enter, NULL,
423 GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_ENTER, 0 }, 1486 GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER, 0 },
424 1487
425 { &client_join_decision, NULL, 1488 { &client_recv_join_decision, NULL,
426 GNUNET_MESSAGE_TYPE_SOCIAL_JOIN_DECISION, 0 }, 1489 GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION, 0 },
427 1490
428 { &client_psyc_message, NULL, 1491 { &client_recv_psyc_message, NULL,
429 GNUNET_MESSAGE_TYPE_PSYC_MESSAGE, 0 } 1492 GNUNET_MESSAGE_TYPE_PSYC_MESSAGE, 0 }
430 }; 1493 };
431 1494
diff --git a/src/social/social.h b/src/social/social.h
index 7f854eed8..00edaefd1 100644
--- a/src/social/social.h
+++ b/src/social/social.h
@@ -19,7 +19,7 @@
19 */ 19 */
20 20
21/** 21/**
22 * @file psyc/psyc.h 22 * @file social/social.h
23 * @brief Common type definitions for the Social service and API. 23 * @brief Common type definitions for the Social service and API.
24 * @author Gabor X Toth 24 * @author Gabor X Toth
25 */ 25 */
@@ -30,16 +30,99 @@
30#include "platform.h" 30#include "platform.h"
31#include "gnunet_social_service.h" 31#include "gnunet_social_service.h"
32 32
33enum MessageState
34{
35 MSG_STATE_START = 0,
36 MSG_STATE_HEADER = 1,
37 MSG_STATE_METHOD = 2,
38 MSG_STATE_MODIFIER = 3,
39 MSG_STATE_MOD_CONT = 4,
40 MSG_STATE_DATA = 5,
41 MSG_STATE_END = 6,
42 MSG_STATE_CANCEL = 7,
43 MSG_STATE_ERROR = 8,
44};
45
33 46
34GNUNET_NETWORK_STRUCT_BEGIN 47GNUNET_NETWORK_STRUCT_BEGIN
35 48
36/**** library -> service ****/ 49/**** library -> service ****/
37 50
38 51
52struct HostEnterRequest
53{
54 /**
55 * Type: GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER
56 */
57 struct GNUNET_MessageHeader header;
58
59 uint32_t policy GNUNET_PACKED;
60
61 struct GNUNET_CRYPTO_EcdsaPrivateKey host_key;
62
63 struct GNUNET_CRYPTO_EddsaPrivateKey place_key;
64};
65
66
67struct GuestEnterRequest
68{
69 /**
70 * Type: GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_ADDR
71 */
72 struct GNUNET_MessageHeader header;
73
74 uint32_t relay_count GNUNET_PACKED;
75
76 struct GNUNET_CRYPTO_EcdsaPrivateKey guest_key;
77
78 struct GNUNET_CRYPTO_EddsaPublicKey place_key;
79
80 struct GNUNET_PeerIdentity origin;
81
82 /* Followed by struct GNUNET_PeerIdentity relays[relay_count] */
83
84 /* Followed by struct GNUNET_MessageHeader join_msg */
85};
86
39 87
40/**** service -> library ****/ 88/**** service -> library ****/
41 89
42 90
91struct CountersResult
92{
93 /**
94 * Type: GNUNET_MESSAGE_TYPE_PSYC_RESULT_COUNTERS
95 */
96 struct GNUNET_MessageHeader header;
97
98 /**
99 * Status code for the operation.
100 */
101 int32_t result_code GNUNET_PACKED;
102
103 /**
104 * Last message ID sent to the channel.
105 */
106 uint64_t max_message_id;
107};
108
109
110#if REMOVE
111struct NymEnterRequest
112{
113 /**
114 * Type: GNUNET_MESSAGE_TYPE_SOCIAL_NYM_ENTER
115 */
116 struct GNUNET_MessageHeader header;
117 /**
118 * Public key of the joining slave.
119 */
120 struct GNUNET_CRYPTO_EcdsaPublicKey nym_key;
121
122 /* Followed by struct GNUNET_MessageHeader join_request */
123};
124#endif
125
43 126
44GNUNET_NETWORK_STRUCT_END 127GNUNET_NETWORK_STRUCT_END
45 128
diff --git a/src/social/social_api.c b/src/social/social_api.c
index ee13c7d61..d19f83e89 100644
--- a/src/social/social_api.c
+++ b/src/social/social_api.c
@@ -1,4 +1,4 @@
1/* 1 /*
2 * This file is part of GNUnet 2 * This file is part of GNUnet
3 * (C) 2013 Christian Grothoff (and other contributing authors) 3 * (C) 2013 Christian Grothoff (and other contributing authors)
4 * 4 *
@@ -25,30 +25,93 @@
25 */ 25 */
26 26
27#include <inttypes.h> 27#include <inttypes.h>
28#include <string.h>
28 29
29#include "platform.h" 30#include "platform.h"
30#include "gnunet_util_lib.h" 31#include "gnunet_util_lib.h"
31#include "gnunet_env_lib.h" 32#include "gnunet_env_lib.h"
33#include "gnunet_core_service.h"
34#include "gnunet_identity_service.h"
35#include "gnunet_namestore_service.h"
36#include "gnunet_gns_service.h"
32#include "gnunet_psyc_service.h" 37#include "gnunet_psyc_service.h"
38#include "gnunet_psyc_util_lib.h"
33#include "gnunet_social_service.h" 39#include "gnunet_social_service.h"
34#include "social.h" 40#include "social.h"
35 41
42#define LOG(kind,...) GNUNET_log_from (kind, "social-api",__VA_ARGS__)
36 43
37/**
38 * Handle for a pseudonym of another user in the network.
39 */
40struct GNUNET_SOCIAL_Nym
41{
42
43};
44 44
45static struct GNUNET_CORE_Handle *core;
46static struct GNUNET_GNS_Handle *gns;
47static struct GNUNET_NAMESTORE_Handle *namestore;
48static struct GNUNET_PeerIdentity this_peer;
45 49
46/** 50/**
47 * Handle for a place where social interactions happen. 51 * Handle for a place where social interactions happen.
48 */ 52 */
49struct GNUNET_SOCIAL_Place 53struct GNUNET_SOCIAL_Place
50{ 54{
51 55 /**
56 * Configuration to use.
57 */
58 const struct GNUNET_CONFIGURATION_Handle *cfg;
59
60 /**
61 * Client connection to the service.
62 */
63 struct GNUNET_CLIENT_MANAGER_Connection *client;
64
65 /**
66 * Transmission handle;
67 */
68 struct GNUNET_PSYC_TransmitHandle *tmit;
69
70 /**
71 * Receipt handle;
72 */
73 struct GNUNET_PSYC_ReceiveHandle *recv;
74
75 /**
76 * Message to send on reconnect.
77 */
78 struct GNUNET_MessageHeader *connect_msg;
79
80 /**
81 * Slicer for processing incoming methods.
82 */
83 struct GNUNET_SOCIAL_Slicer *slicer;
84
85 /**
86 * Function called after disconnected from the service.
87 */
88 GNUNET_ContinuationCallback disconnect_cb;
89
90 /**
91 * Closure for @a disconnect_cb.
92 */
93 void *disconnect_cls;
94
95 /**
96 * Public key of the place.
97 */
98 struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
99
100 /**
101 * Private key of the ego.
102 */
103 struct GNUNET_CRYPTO_EcdsaPrivateKey ego_key;
104
105 /**
106 * Does this place belong to a host (#GNUNET_YES) or guest (#GNUNET_NO)?
107 */
108 uint8_t is_host;
109
110 /**
111 * Is this place in the process of disconnecting from the service?
112 * #GNUNET_YES or #GNUNET_NO
113 */
114 uint8_t is_disconnecting;
52}; 115};
53 116
54 117
@@ -57,7 +120,20 @@ struct GNUNET_SOCIAL_Place
57 */ 120 */
58struct GNUNET_SOCIAL_Host 121struct GNUNET_SOCIAL_Host
59{ 122{
123 struct GNUNET_SOCIAL_Place plc;
60 124
125 struct GNUNET_CRYPTO_EddsaPrivateKey place_key;
126
127 GNUNET_SOCIAL_HostEnterCallback enter_cb;
128
129 GNUNET_SOCIAL_AnswerDoorCallback answer_door_cb;
130
131 GNUNET_SOCIAL_FarewellCallback farewell_cb;
132
133 /**
134 * Closure for callbacks.
135 */
136 void *cb_cls;
61}; 137};
62 138
63 139
@@ -66,16 +142,91 @@ struct GNUNET_SOCIAL_Host
66 */ 142 */
67struct GNUNET_SOCIAL_Guest 143struct GNUNET_SOCIAL_Guest
68{ 144{
145 struct GNUNET_SOCIAL_Place plc;
69 146
147 GNUNET_SOCIAL_GuestEnterCallback enter_cb;
148
149 GNUNET_SOCIAL_EntryDecisionCallback entry_dcsn_cb;
150
151 /**
152 * Closure for callbacks.
153 */
154 void *cb_cls;
70}; 155};
71 156
72 157
73/** 158/**
74 * Handle to an implementation of try-and-slice. 159 * Handle for a pseudonym of another user in the network.
160 */
161struct GNUNET_SOCIAL_Nym
162{
163 struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
164 struct GNUNET_HashCode pub_key_hash;
165};
166
167
168/**
169 * Hash map of all nyms.
170 * pub_key_hash -> struct GNUNET_SOCIAL_Nym *
171 */
172struct GNUNET_CONTAINER_MultiHashMap *nyms;
173
174
175/**
176 * Handle for a try-and-slice instance.
75 */ 177 */
76struct GNUNET_SOCIAL_Slicer 178struct GNUNET_SOCIAL_Slicer
77{ 179{
180 /**
181 * Message handlers: method_name -> SlicerCallbacks
182 */
183 struct GNUNET_CONTAINER_MultiHashMap *handlers;
184
185
186 /**
187 * Currently being processed message part.
188 */
189 const struct GNUNET_MessageHeader *msg;
190
191 /**
192 * ID of currently being received message.
193 */
194 uint64_t message_id;
195
196 /**
197 * Method name of currently being received message.
198 */
199 char *method_name;
200
201 /**
202 * Public key of the nym the current message originates from.
203 */
204 struct GNUNET_CRYPTO_EcdsaPublicKey nym_key;
205
206 /**
207 * Size of @a method_name (including terminating \0).
208 */
209 uint16_t method_name_size;
210};
211
78 212
213/**
214 * Callbacks for a slicer method handler.
215 */
216struct SlicerCallbacks
217{
218 GNUNET_SOCIAL_MethodCallback method_cb;
219 GNUNET_SOCIAL_ModifierCallback modifier_cb;
220 GNUNET_SOCIAL_DataCallback data_cb;
221 GNUNET_SOCIAL_EndOfMessageCallback eom_cb;
222 void *cls;
223};
224
225
226struct SlicerRemoveClosure
227{
228 struct GNUNET_SOCIAL_Slicer *slicer;
229 struct SlicerCallbacks rm_cbs;
79}; 230};
80 231
81 232
@@ -118,6 +269,181 @@ struct GNUNET_SOCIAL_HistoryLesson
118}; 269};
119 270
120 271
272static struct GNUNET_SOCIAL_Nym *
273nym_get_or_create (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub_key)
274{
275 struct GNUNET_SOCIAL_Nym *nym = NULL;
276 struct GNUNET_HashCode pub_key_hash;
277
278 if (NULL == pub_key)
279 return NULL;
280
281 GNUNET_CRYPTO_hash (pub_key, sizeof (*pub_key), &pub_key_hash);
282
283 if (NULL == nyms)
284 nyms = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
285 else
286 nym = GNUNET_CONTAINER_multihashmap_get (nyms, &pub_key_hash);
287
288 if (NULL == nym)
289 {
290 nym = GNUNET_new (struct GNUNET_SOCIAL_Nym);
291 nym->pub_key = *pub_key;
292 nym->pub_key_hash = pub_key_hash;
293 GNUNET_CONTAINER_multihashmap_put (nyms, &nym->pub_key_hash, nym,
294 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
295 }
296 return nym;
297}
298
299
300static void
301nym_destroy (struct GNUNET_SOCIAL_Nym *nym)
302{
303 GNUNET_CONTAINER_multihashmap_remove (nyms, &nym->pub_key_hash, nym);
304 GNUNET_free (nym);
305}
306
307
308/**
309 * Call a handler for an incoming message part.
310 *
311 * @param cls
312 * @param key
313 * @param value
314 *
315 * @return
316 */
317int
318slicer_handler_notify (void *cls, const struct GNUNET_HashCode *key,
319 void *value)
320{
321 struct GNUNET_SOCIAL_Slicer *slicer = cls;
322 const struct GNUNET_MessageHeader *msg = slicer->msg;
323 struct SlicerCallbacks *cbs = value;
324 uint16_t ptype = ntohs (msg->type);
325
326 switch (ptype)
327 {
328 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD:
329 {
330 if (NULL == cbs->method_cb)
331 break;
332 struct GNUNET_PSYC_MessageMethod *
333 meth = (struct GNUNET_PSYC_MessageMethod *) msg;
334 cbs->method_cb (cbs->cls, meth, slicer->message_id,
335 ntohl (meth->flags),
336 nym_get_or_create (&slicer->nym_key),
337 slicer->method_name);
338 break;
339 }
340
341 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
342 {
343 if (NULL == cbs->modifier_cb)
344 break;
345 struct GNUNET_PSYC_MessageModifier *
346 mod = (struct GNUNET_PSYC_MessageModifier *) msg;
347 cbs->modifier_cb (cbs->cls, mod, slicer->message_id,
348 mod->oper, (const char *) &mod[1],
349 (const void *) &mod[1] + ntohs (mod->name_size),
350 ntohs (mod->value_size));
351 break;
352 }
353
354 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
355 {
356 if (NULL == cbs->modifier_cb)
357 break;
358 /* FIXME: concatenate until done */
359 break;
360 }
361
362 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
363 {
364 if (NULL == cbs->data_cb)
365 break;
366 uint64_t data_offset = 0; // FIXME
367 cbs->data_cb (cbs->cls, msg, slicer->message_id,
368 data_offset, &msg[1], ntohs (msg->size) - sizeof (*msg));
369 break;
370 }
371
372 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
373 if (NULL == cbs->eom_cb)
374 break;
375 cbs->eom_cb (cbs->cls, msg, slicer->message_id, GNUNET_NO);
376 break;
377
378 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
379 if (NULL == cbs->eom_cb)
380 break;
381 cbs->eom_cb (cbs->cls, msg, slicer->message_id, GNUNET_YES);
382 break;
383 }
384 return GNUNET_YES;
385}
386
387
388/**
389 * Process an incoming message part and call matching handlers.
390 *
391 * @param cls
392 * Closure.
393 * @param message_id
394 * ID of the message.
395 * @param flags
396 * Flags for the message.
397 * @see enum GNUNET_PSYC_MessageFlags
398 * @param msg
399 * The message part. as it arrived from the network.
400 */
401static void
402slicer_message (void *cls, uint64_t message_id, uint64_t fragment_offset,
403 uint32_t flags, const struct GNUNET_MessageHeader *msg)
404{
405 struct GNUNET_SOCIAL_Slicer *slicer = cls;
406 uint16_t ptype = ntohs (msg->type);
407 if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == ptype)
408 {
409 struct GNUNET_PSYC_MessageMethod *
410 meth = (struct GNUNET_PSYC_MessageMethod *) msg;
411 slicer->method_name_size = ntohs (meth->header.size) - sizeof (*meth);
412 slicer->method_name = GNUNET_malloc (slicer->method_name_size);
413 memcpy (slicer->method_name, &meth[1], slicer->method_name_size);
414 slicer->message_id = message_id;
415 }
416 else
417 {
418 GNUNET_assert (message_id == slicer->message_id);
419 }
420
421 LOG (GNUNET_ERROR_TYPE_WARNING,
422 "Slicer received message of type %u and size %u, "
423 "with ID %" PRIu64 " and method %s\n",
424 ptype, ntohs (msg->size), message_id, slicer->method_name);
425
426 slicer->msg = msg;
427 char *name = GNUNET_malloc (slicer->method_name_size);
428 memcpy (name, slicer->method_name, slicer->method_name_size);
429 do
430 {
431 struct GNUNET_HashCode key;
432 uint16_t name_len = strlen (name);
433 GNUNET_CRYPTO_hash (name, name_len, &key);
434 GNUNET_CONTAINER_multihashmap_get_multiple (slicer->handlers, &key,
435 &slicer_handler_notify, slicer);
436 char *p = strrchr (name, '_');
437 if (NULL == p)
438 break;
439 *p = '\0';
440 } while (1);
441 GNUNET_free (name);
442 slicer->msg = NULL;
443
444 if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= ptype)
445 GNUNET_free (slicer->method_name);
446}
121 447
122 448
123/** 449/**
@@ -128,7 +454,9 @@ struct GNUNET_SOCIAL_HistoryLesson
128struct GNUNET_SOCIAL_Slicer * 454struct GNUNET_SOCIAL_Slicer *
129GNUNET_SOCIAL_slicer_create (void) 455GNUNET_SOCIAL_slicer_create (void)
130{ 456{
131 return NULL; 457 struct GNUNET_SOCIAL_Slicer *slicer = GNUNET_malloc (sizeof (*slicer));
458 slicer->handlers = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
459 return slicer;
132} 460}
133 461
134 462
@@ -148,36 +476,338 @@ void
148GNUNET_SOCIAL_slicer_add (struct GNUNET_SOCIAL_Slicer *slicer, 476GNUNET_SOCIAL_slicer_add (struct GNUNET_SOCIAL_Slicer *slicer,
149 const char *method_name, 477 const char *method_name,
150 GNUNET_SOCIAL_MethodCallback method_cb, 478 GNUNET_SOCIAL_MethodCallback method_cb,
479 GNUNET_SOCIAL_ModifierCallback modifier_cb,
480 GNUNET_SOCIAL_DataCallback data_cb,
481 GNUNET_SOCIAL_EndOfMessageCallback eom_cb,
151 void *cls) 482 void *cls)
152{ 483{
484 struct GNUNET_HashCode key;
485 GNUNET_CRYPTO_hash (method_name, strlen (method_name), &key);
486
487 struct SlicerCallbacks *cbs = GNUNET_malloc (sizeof (*cbs));
488 cbs->method_cb = method_cb;
489 cbs->modifier_cb = modifier_cb;
490 cbs->data_cb = data_cb;
491 cbs->eom_cb = eom_cb;
492 cbs->cls = cls;
493
494 GNUNET_CONTAINER_multihashmap_put (slicer->handlers, &key, cbs,
495 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
496}
153 497
498
499int
500slicer_remove_handler (void *cls, const struct GNUNET_HashCode *key, void *value)
501{
502 struct SlicerRemoveClosure *rm_cls = cls;
503 struct GNUNET_SOCIAL_Slicer *slicer = rm_cls->slicer;
504 struct SlicerCallbacks *rm_cbs = &rm_cls->rm_cbs;
505 struct SlicerCallbacks *cbs = value;
506
507 if (cbs->method_cb == rm_cbs->method_cb
508 && cbs->modifier_cb == rm_cbs->modifier_cb
509 && cbs->data_cb == rm_cbs->data_cb
510 && cbs->eom_cb == rm_cbs->eom_cb)
511 {
512 GNUNET_CONTAINER_multihashmap_remove (slicer->handlers, key, cbs);
513 GNUNET_free (cbs);
514 return GNUNET_NO;
515 }
516 return GNUNET_YES;
154} 517}
155 518
156 519
157/** 520/**
158 * Remove a registered method from the try-and-slice instance. 521 * Remove a registered method from the try-and-slice instance.
159 * 522 *
523 * Removes the first matching handler registered with @a method and the given callbacks.
524 *
160 * @param slicer The try-and-slice instance. 525 * @param slicer The try-and-slice instance.
161 * @param method_name Name of the method to remove. 526 * @param method_name Name of the method to remove.
162 * @param method Method handler. 527 * @param method Method handler.
528 *
529 * @return #GNUNET_OK if a method handler was removed,
530 * #GNUNET_NO if no handler matched the given method name and callbacks.
163 */ 531 */
164void 532int
165GNUNET_SOCIAL_slicer_remove (struct GNUNET_SOCIAL_Slicer *slicer, 533GNUNET_SOCIAL_slicer_remove (struct GNUNET_SOCIAL_Slicer *slicer,
166 const char *method_name, 534 const char *method_name,
167 GNUNET_SOCIAL_MethodCallback method_cb) 535 GNUNET_SOCIAL_MethodCallback method_cb,
536 GNUNET_SOCIAL_ModifierCallback modifier_cb,
537 GNUNET_SOCIAL_DataCallback data_cb,
538 GNUNET_SOCIAL_EndOfMessageCallback eom_cb)
168{ 539{
540 struct GNUNET_HashCode key;
541 GNUNET_CRYPTO_hash (method_name, strlen (method_name), &key);
542
543 struct SlicerRemoveClosure rm_cls;
544 rm_cls.slicer = slicer;
545 struct SlicerCallbacks *rm_cbs = &rm_cls.rm_cbs;
546 rm_cbs->method_cb = method_cb;
547 rm_cbs->modifier_cb = modifier_cb;
548 rm_cbs->data_cb = data_cb;
549 rm_cbs->eom_cb = eom_cb;
550
551 return
552 (GNUNET_SYSERR
553 == GNUNET_CONTAINER_multihashmap_get_multiple (slicer->handlers, &key,
554 &slicer_remove_handler,
555 &rm_cls))
556 ? GNUNET_NO
557 : GNUNET_OK;
558}
559
169 560
561int
562slicer_free_handler (void *cls, const struct GNUNET_HashCode *key, void *value)
563{
564 struct SlicerCallbacks *cbs = value;
565 GNUNET_free (cbs);
566 return GNUNET_YES;
170} 567}
171 568
569
172/** 570/**
173 * Destroy a given try-and-slice instance. 571 * Destroy a given try-and-slice instance.
174 * 572 *
175 * @param slicer slicer to destroy 573 * @param slicer
574 * Slicer to destroy
176 */ 575 */
177void 576void
178GNUNET_SOCIAL_slicer_destroy (struct GNUNET_SOCIAL_Slicer *slicer) 577GNUNET_SOCIAL_slicer_destroy (struct GNUNET_SOCIAL_Slicer *slicer)
179{ 578{
579 GNUNET_CONTAINER_multihashmap_iterate (slicer->handlers, &slicer_free_handler,
580 NULL);
581 GNUNET_CONTAINER_multihashmap_destroy (slicer->handlers);
582 GNUNET_free (slicer);
583}
584
585
586static void
587place_send_connect_msg (struct GNUNET_SOCIAL_Place *plc)
588{
589 uint16_t cmsg_size = ntohs (plc->connect_msg->size);
590 struct GNUNET_MessageHeader * cmsg = GNUNET_malloc (cmsg_size);
591 memcpy (cmsg, plc->connect_msg, cmsg_size);
592 GNUNET_CLIENT_MANAGER_transmit_now (plc->client, cmsg);
593}
594
595
596static void
597place_recv_message_ack (void *cls,
598 struct GNUNET_CLIENT_MANAGER_Connection *client,
599 const struct GNUNET_MessageHeader *msg)
600{
601 struct GNUNET_SOCIAL_Place *
602 plc = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*plc));
603 GNUNET_PSYC_transmit_got_ack (plc->tmit);
604}
605
606
607static void
608place_recv_message (void *cls,
609 struct GNUNET_CLIENT_MANAGER_Connection *client,
610 const struct GNUNET_MessageHeader *msg)
611{
612 struct GNUNET_SOCIAL_Place *
613 plc = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*plc));
614 GNUNET_PSYC_receive_message (plc->recv,
615 (const struct GNUNET_PSYC_MessageHeader *) msg);
616}
617
618
619static void
620place_recv_disconnect (void *cls,
621 struct GNUNET_CLIENT_MANAGER_Connection *client,
622 const struct GNUNET_MessageHeader *msg)
623{
624 struct GNUNET_SOCIAL_Place *
625 plc = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*plc));
626
627 GNUNET_CLIENT_MANAGER_reconnect (client);
628 place_send_connect_msg (plc);
629}
630
631
632static void
633host_recv_enter_ack (void *cls,
634 struct GNUNET_CLIENT_MANAGER_Connection *client,
635 const struct GNUNET_MessageHeader *msg)
636{
637 struct GNUNET_SOCIAL_Host *
638 hst = GNUNET_CLIENT_MANAGER_get_user_context_ (client,
639 sizeof (struct GNUNET_SOCIAL_Place));
640
641 struct GNUNET_PSYC_CountersResultMessage *
642 cres = (struct GNUNET_PSYC_CountersResultMessage *) msg;
643 if (NULL != hst->enter_cb)
644 hst->enter_cb (hst->cb_cls, GNUNET_ntohll (cres->max_message_id));
645}
646
647
648static void
649host_recv_enter_request (void *cls,
650 struct GNUNET_CLIENT_MANAGER_Connection *client,
651 const struct GNUNET_MessageHeader *msg)
652{
653 struct GNUNET_SOCIAL_Host *
654 hst = GNUNET_CLIENT_MANAGER_get_user_context_ (client,
655 sizeof (struct GNUNET_SOCIAL_Place));
656 if (NULL == hst->answer_door_cb)
657 return;
658
659 const char *method_name = NULL;
660 struct GNUNET_ENV_Environment *env = NULL;
661 const void *data = NULL;
662 uint16_t data_size = 0;
663
664 const struct GNUNET_PSYC_JoinRequestMessage *
665 req = (const struct GNUNET_PSYC_JoinRequestMessage *) msg;
666 const struct GNUNET_PSYC_Message *entry_msg = NULL;
667 if (sizeof (*req) + sizeof (*entry_msg) <= ntohs (req->header.size))
668 {
669 entry_msg = (struct GNUNET_PSYC_Message *) &req[1];
670 LOG (GNUNET_ERROR_TYPE_DEBUG,
671 "Received entry_msg of type %u and size %u.\n",
672 ntohs (entry_msg->header.type), ntohs (entry_msg->header.size));
673
674 env = GNUNET_ENV_environment_create ();
675 if (GNUNET_OK != GNUNET_PSYC_message_parse (entry_msg, &method_name, env,
676 &data, &data_size))
677 {
678 LOG (GNUNET_ERROR_TYPE_WARNING,
679 "Ignoring invalid entry request from nym %s.\n",
680 GNUNET_CRYPTO_ecdsa_public_key_to_string (&req->slave_key));
681 GNUNET_break_op (0);
682 GNUNET_ENV_environment_destroy (env);
683 return;
684 }
685 }
686
687 struct GNUNET_SOCIAL_Nym *nym = nym_get_or_create (&req->slave_key);
688 hst->answer_door_cb (hst->cb_cls, nym, method_name, env,
689 data_size, data);
690
691 if (NULL != env)
692 GNUNET_ENV_environment_destroy (env);
693}
694
695
696static void
697guest_recv_enter_ack (void *cls,
698 struct GNUNET_CLIENT_MANAGER_Connection *client,
699 const struct GNUNET_MessageHeader *msg)
700{
701 struct GNUNET_SOCIAL_Guest *
702 gst = GNUNET_CLIENT_MANAGER_get_user_context_ (client,
703 sizeof (struct GNUNET_SOCIAL_Place));
704
705 struct GNUNET_PSYC_CountersResultMessage *
706 cres = (struct GNUNET_PSYC_CountersResultMessage *) msg;
707 if (NULL != gst->enter_cb)
708 gst->enter_cb (gst->cb_cls, ntohl (cres->result_code),
709 GNUNET_ntohll (cres->max_message_id));
710}
711
712
713static void
714guest_recv_join_decision (void *cls,
715 struct GNUNET_CLIENT_MANAGER_Connection *client,
716 const struct GNUNET_MessageHeader *msg)
717{
718 struct GNUNET_SOCIAL_Guest *
719 gst = GNUNET_CLIENT_MANAGER_get_user_context_ (client,
720 sizeof (struct GNUNET_SOCIAL_Place));
721 const struct GNUNET_PSYC_JoinDecisionMessage *
722 dcsn = (const struct GNUNET_PSYC_JoinDecisionMessage *) msg;
723
724 struct GNUNET_PSYC_Message *pmsg = NULL;
725 if (ntohs (dcsn->header.size) <= sizeof (*dcsn) + sizeof (*pmsg))
726 pmsg = (struct GNUNET_PSYC_Message *) &dcsn[1];
727
728 if (NULL != gst->entry_dcsn_cb)
729 gst->entry_dcsn_cb (gst->cb_cls, ntohl (dcsn->is_admitted), pmsg);
730}
731
732
733static struct GNUNET_CLIENT_MANAGER_MessageHandler host_handlers[] =
734{
735 { &host_recv_enter_ack, NULL,
736 GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER_ACK,
737 sizeof (struct CountersResult), GNUNET_NO },
738
739 { &host_recv_enter_request, NULL,
740 GNUNET_MESSAGE_TYPE_PSYC_JOIN_REQUEST,
741 sizeof (struct GNUNET_PSYC_JoinRequestMessage), GNUNET_YES },
742
743 { &place_recv_message, NULL,
744 GNUNET_MESSAGE_TYPE_PSYC_MESSAGE,
745 sizeof (struct GNUNET_PSYC_MessageHeader), GNUNET_YES },
746
747 { &place_recv_message_ack, NULL,
748 GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK,
749 sizeof (struct GNUNET_MessageHeader), GNUNET_NO },
750
751 { &place_recv_disconnect, NULL, 0, 0, GNUNET_NO },
752
753 { NULL, NULL, 0, 0, GNUNET_NO }
754};
755
756
757static struct GNUNET_CLIENT_MANAGER_MessageHandler guest_handlers[] =
758{
759 { &guest_recv_enter_ack, NULL,
760 GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_ACK,
761 sizeof (struct CountersResult), GNUNET_NO },
762
763 { &host_recv_enter_request, NULL,
764 GNUNET_MESSAGE_TYPE_PSYC_JOIN_REQUEST,
765 sizeof (struct GNUNET_PSYC_JoinRequestMessage), GNUNET_YES },
766
767 { &place_recv_message, NULL,
768 GNUNET_MESSAGE_TYPE_PSYC_MESSAGE,
769 sizeof (struct GNUNET_PSYC_MessageHeader), GNUNET_YES },
770
771 { &place_recv_message_ack, NULL,
772 GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK,
773 sizeof (struct GNUNET_MessageHeader), GNUNET_NO },
774
775 { &guest_recv_join_decision, NULL,
776 GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION,
777 sizeof (struct GNUNET_PSYC_JoinDecisionMessage), GNUNET_YES },
778
779 { &place_recv_disconnect, NULL, 0, 0, GNUNET_NO },
780
781 { NULL, NULL, 0, 0, GNUNET_NO }
782};
783
784
785static void
786place_cleanup (struct GNUNET_SOCIAL_Place *plc)
787{
788 GNUNET_PSYC_transmit_destroy (plc->tmit);
789 GNUNET_PSYC_receive_destroy (plc->recv);
790 GNUNET_free (plc->connect_msg);
791 if (NULL != plc->disconnect_cb)
792 plc->disconnect_cb (plc->disconnect_cls);
793}
794
795
796static void
797host_cleanup (void *cls)
798{
799 struct GNUNET_SOCIAL_Host *hst = cls;
800 place_cleanup (&hst->plc);
801 GNUNET_free (hst);
802}
803
180 804
805static void
806guest_cleanup (void *cls)
807{
808 struct GNUNET_SOCIAL_Guest *gst = cls;
809 place_cleanup (&gst->plc);
810 GNUNET_free (gst);
181} 811}
182 812
183 813
@@ -187,46 +817,179 @@ GNUNET_SOCIAL_slicer_destroy (struct GNUNET_SOCIAL_Slicer *slicer)
187 * A place is created upon first entering, and it is active until permanently 817 * A place is created upon first entering, and it is active until permanently
188 * left using GNUNET_SOCIAL_host_leave(). 818 * left using GNUNET_SOCIAL_host_leave().
189 * 819 *
190 * @param cfg Configuration to contact the social service. 820 * @param cfg
191 * @param place_keyfile File with the private-public key pair of the place, 821 * Configuration to contact the social service.
192 * created if the file does not exist; pass NULL for ephemeral places. 822 * @param ego
193 * @param policy Policy specifying entry and history restrictions of the place. 823 * Identity of the host.
194 * @param ego Identity of the host. 824 * @param place_key
195 * @param slicer Slicer to handle incoming messages. 825 * Private-public key pair of the place.
196 * @param listener_cb Function to handle new nyms that want to enter. 826 * NULL for ephemeral places.
197 * @param farewell_cb Function to handle departing nyms. 827 * @param policy
198 * @param cls Closure for @a listener_cb and @a farewell_cb. 828 * Policy specifying entry and history restrictions for the place.
829 * @param slicer
830 * Slicer to handle incoming messages.
831 * @param answer_door_cb
832 * Function to handle new nyms that want to enter.
833 * @param farewell_cb
834 * Function to handle departing nyms.
835 * @param cls
836 * Closure for the callbacks.
199 * 837 *
200 * @return Handle for the host. 838 * @return Handle for the host.
201 */ 839 */
202struct GNUNET_SOCIAL_Host * 840struct GNUNET_SOCIAL_Host *
203GNUNET_SOCIAL_host_enter (const struct GNUNET_CONFIGURATION_Handle *cfg, 841GNUNET_SOCIAL_host_enter (const struct GNUNET_CONFIGURATION_Handle *cfg,
204 const char *place_keyfile, 842 const struct GNUNET_IDENTITY_Ego *ego,
843 const struct GNUNET_CRYPTO_EddsaPrivateKey *place_key,
205 enum GNUNET_PSYC_Policy policy, 844 enum GNUNET_PSYC_Policy policy,
206 struct GNUNET_IDENTITY_Ego *ego,
207 struct GNUNET_SOCIAL_Slicer *slicer, 845 struct GNUNET_SOCIAL_Slicer *slicer,
208 GNUNET_SOCIAL_AnswerDoorCallback listener_cb, 846 GNUNET_SOCIAL_HostEnterCallback enter_cb,
847 GNUNET_SOCIAL_AnswerDoorCallback answer_door_cb,
209 GNUNET_SOCIAL_FarewellCallback farewell_cb, 848 GNUNET_SOCIAL_FarewellCallback farewell_cb,
210 void *cls) 849 void *cls)
211{ 850{
212 return NULL; 851 struct GNUNET_SOCIAL_Host *hst = GNUNET_malloc (sizeof (*hst));
852 struct GNUNET_SOCIAL_Place *plc = &hst->plc;
853 struct HostEnterRequest *req = GNUNET_malloc (sizeof (*req));
854
855 if (NULL != place_key)
856 {
857 hst->place_key = *place_key;
858 }
859 else
860 {
861 struct GNUNET_CRYPTO_EddsaPrivateKey *
862 ephemeral_key = GNUNET_CRYPTO_eddsa_key_create ();
863 hst->place_key = *ephemeral_key;
864 GNUNET_CRYPTO_eddsa_key_get_public (&hst->place_key, &plc->pub_key);
865 GNUNET_CRYPTO_eddsa_key_clear (ephemeral_key);
866 GNUNET_free (ephemeral_key);
867 }
868 plc->ego_key = *GNUNET_IDENTITY_ego_get_private_key (ego);
869
870 req->header.size = htons (sizeof (*req));
871 req->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER);
872 req->policy = policy;
873 req->place_key = hst->place_key;
874 req->host_key = plc->ego_key;
875
876 plc->connect_msg = (struct GNUNET_MessageHeader *) req;
877 plc->cfg = cfg;
878 plc->is_host = GNUNET_YES;
879 plc->slicer = slicer;
880
881 hst->plc.ego_key = *GNUNET_IDENTITY_ego_get_private_key (ego);
882 hst->enter_cb = enter_cb;
883 hst->answer_door_cb = answer_door_cb;
884 hst->cb_cls = cls;
885
886 plc->client = GNUNET_CLIENT_MANAGER_connect (cfg, "social", host_handlers);
887 GNUNET_CLIENT_MANAGER_set_user_context_ (plc->client, hst, sizeof (*plc));
888
889 plc->tmit = GNUNET_PSYC_transmit_create (plc->client);
890 plc->recv = GNUNET_PSYC_receive_create (NULL, &slicer_message, plc->slicer);
891
892 place_send_connect_msg (plc);
893 return hst;
213} 894}
214 895
215 896
216/** 897/**
217 * Admit @a nym to the place. 898 * Enter a place as host.
218 * 899 *
219 * The @a nym reference will remain valid until either the @a host or @a nym 900 * A place is created upon first entering, and it is active until permanently
220 * leaves the place. 901 * left using GNUNET_SOCIAL_host_leave().
221 * 902 *
222 * @param host Host of the place. 903 * @param cfg
223 * @param nym Handle for the entity that wants to enter. 904 * Configuration to contact the social service.
905 * @param ego
906 * Identity of the host.
907 * @param gns_name
908 * GNS name in the zone of the @a ego that contains the
909 * public key of the place in a PLACE record.
910 * @param policy
911 * Policy specifying entry and history restrictions for the place.
912 * @param slicer
913 * Slicer to handle incoming messages.
914 * @param answer_door_cb
915 * Function to handle new nyms that want to enter.
916 * @param farewell_cb
917 * Function to handle departing nyms.
918 * @param cls
919 * Closure for the callbacks.
920 *
921 * @return Handle for the host.
224 */ 922 */
225void 923struct GNUNET_SOCIAL_Host *
226GNUNET_SOCIAL_host_admit (struct GNUNET_SOCIAL_Host *host, 924GNUNET_SOCIAL_host_enter_by_name (const struct GNUNET_CONFIGURATION_Handle *cfg,
227 struct GNUNET_SOCIAL_Nym *nym) 925 struct GNUNET_IDENTITY_Ego *ego,
926 const char *gns_name,
927 enum GNUNET_PSYC_Policy policy,
928 struct GNUNET_SOCIAL_Slicer *slicer,
929 GNUNET_SOCIAL_HostEnterCallback enter_cb,
930 GNUNET_SOCIAL_AnswerDoorCallback answer_door_cb,
931 GNUNET_SOCIAL_FarewellCallback farewell_cb,
932 void *cls)
228{ 933{
934 struct GNUNET_CRYPTO_EddsaPrivateKey place_key = {};
229 935
936 /* FIXME:
937 * 1. get public key by looking up PLACE entry under gns_name
938 * in the zone of the ego.
939 * 2. get private key from $GNUNET_DATA_HOME/social/places/PUB_KEY_HASH
940 */
941
942 return GNUNET_SOCIAL_host_enter (cfg, ego, &place_key, policy, slicer,
943 enter_cb, answer_door_cb, farewell_cb, cls);
944}
945
946
947/**
948 * Decision whether to admit @a nym into the place or refuse entry.
949 *
950 * @param hst
951 * Host of the place.
952 * @param nym
953 * Handle for the entity that wanted to enter.
954 * @param is_admitted
955 * #GNUNET_YES if @a nym is admitted,
956 * #GNUNET_NO if @a nym is refused entry,
957 * #GNUNET_SYSERR if we cannot answer the request.
958 * @param method_name
959 * Method name for the rejection message.
960 * @param env
961 * Environment containing variables for the message, or NULL.
962 * @param data
963 * Data for the rejection message to send back.
964 * @param data_size
965 * Number of bytes in @a data for method.
966 * @return #GNUNET_OK on success,
967 * #GNUNET_SYSERR if the message is too large.
968 */
969int
970GNUNET_SOCIAL_host_entry_decision (struct GNUNET_SOCIAL_Host *hst,
971 struct GNUNET_SOCIAL_Nym *nym,
972 int is_admitted,
973 const struct GNUNET_PSYC_Message *entry_resp)
974{
975 struct GNUNET_PSYC_JoinDecisionMessage *dcsn;
976 uint16_t entry_resp_size
977 = (NULL != entry_resp) ? ntohs (entry_resp->header.size) : 0;
978
979 if (GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD < sizeof (*dcsn) + entry_resp_size)
980 return GNUNET_SYSERR;
981
982 dcsn = GNUNET_malloc (sizeof (*dcsn) + entry_resp_size);
983 dcsn->header.size = htons (sizeof (*dcsn) + entry_resp_size);
984 dcsn->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION);
985 dcsn->is_admitted = htonl (is_admitted);
986 dcsn->slave_key = nym->pub_key;
987
988 if (0 < entry_resp_size)
989 memcpy (&dcsn[1], entry_resp, entry_resp_size);
990
991 GNUNET_CLIENT_MANAGER_transmit (hst->plc.client, &dcsn->header);
992 return GNUNET_OK;
230} 993}
231 994
232 995
@@ -249,63 +1012,60 @@ GNUNET_SOCIAL_host_eject (struct GNUNET_SOCIAL_Host *host,
249 1012
250 1013
251/** 1014/**
252 * Refuse @a nym entry into the place. 1015 * Get the public key of a @a nym.
253 * 1016 *
254 * @param host Host of the place. 1017 * Suitable, for example, to be used with GNUNET_NAMESTORE_zone_to_name().
255 * @param nym Handle for the entity that wanted to enter. 1018 *
256 * @param method_name Method name for the rejection message. 1019 * @param nym Pseudonym to map to a cryptographic identifier.
257 * @param env Environment containing variables for the message, or NULL. 1020 * @param[out] nym_key Set to the public key of the nym.
258 * @param data Data for the rejection message to send back.
259 * @param data_size Number of bytes in @a data for method.
260 */ 1021 */
261void 1022struct GNUNET_CRYPTO_EcdsaPublicKey *
262GNUNET_SOCIAL_host_refuse_entry (struct GNUNET_SOCIAL_Host *host, 1023GNUNET_SOCIAL_nym_get_key (struct GNUNET_SOCIAL_Nym *nym)
263 struct GNUNET_SOCIAL_Nym *nym,
264 const char *method_name,
265 const struct GNUNET_ENV_Environment *env,
266 const void *data,
267 size_t data_size)
268{ 1024{
269 1025 return &nym->pub_key;
270} 1026}
271 1027
272 1028
273/** 1029/**
274 * Get the public key of a @a nym. 1030 * Obtain the private-public key pair of the hosted place.
275 * 1031 *
276 * Suitable, for example, to be used with GNUNET_NAMESTORE_zone_to_name(). 1032 * The public part is suitable for storing in GNS within a PLACE record,
1033 * along with peer IDs to join at.
277 * 1034 *
278 * @param nym Pseudonym to map to a cryptographic identifier. 1035 * @param host
279 * @param[out] nym_key Set to the public key of the nym. 1036 * Host of the place.
1037 *
1038 * @return Private-public key pair of the hosted place.
280 */ 1039 */
281void 1040const struct GNUNET_CRYPTO_EddsaPrivateKey *
282GNUNET_SOCIAL_nym_get_key (struct GNUNET_SOCIAL_Nym *nym, 1041GNUNET_SOCIAL_host_get_place_key (struct GNUNET_SOCIAL_Host *hst)
283 struct GNUNET_CRYPTO_EddsaPublicKey *nym_key) 1042{
1043 return &hst->place_key;
1044}
1045
1046
1047static void
1048namestore_result_host_advertise (void *cls, int32_t success, const char *emsg)
284{ 1049{
285 1050
286} 1051}
287 1052
288 1053
289/** 1054/**
290 * Obtain the private-public key pair of the host. 1055 * Connected to core service.
291 *
292 * @param host Host to get the key of.
293 * @param[out] host_key Set to the private-public key pair of the host. The
294 * public part is suitable for storing in GNS within a "PLACE"
295 * record, along with peer IDs to join at.
296 */ 1056 */
297void 1057static void
298GNUNET_SOCIAL_host_get_key (struct GNUNET_SOCIAL_Host *host, 1058core_connected_cb (void *cls, const struct GNUNET_PeerIdentity *my_identity)
299 struct GNUNET_CRYPTO_EddsaPrivateKey *host_key)
300{ 1059{
301 1060 this_peer = *my_identity;
1061 // FIXME
302} 1062}
303 1063
304 1064
305/** 1065/**
306 * Advertise the place in the GNS zone of the @e ego of the @a host. 1066 * Advertise the place in the GNS zone of the @e ego of the @a host.
307 * 1067 *
308 * @param host Host of the place. 1068 * @param hst Host of the place.
309 * @param name The name for the PLACE record to put in the zone. 1069 * @param name The name for the PLACE record to put in the zone.
310 * @param peer_count Number of elements in the @a peers array. 1070 * @param peer_count Number of elements in the @a peers array.
311 * @param peers List of peers in the PLACE record that can be used to send join 1071 * @param peers List of peers in the PLACE record that can be used to send join
@@ -314,14 +1074,37 @@ GNUNET_SOCIAL_host_get_key (struct GNUNET_SOCIAL_Host *host,
314 * @param password Password used to encrypt the record. 1074 * @param password Password used to encrypt the record.
315 */ 1075 */
316void 1076void
317GNUNET_SOCIAL_host_advertise (struct GNUNET_SOCIAL_Host *host, 1077GNUNET_SOCIAL_host_advertise (struct GNUNET_SOCIAL_Host *hst,
318 const char *name, 1078 const char *name,
319 size_t peer_count, 1079 size_t peer_count,
320 const struct GNUNET_PeerIdentity *peers, 1080 const struct GNUNET_PeerIdentity *peers,
321 struct GNUNET_TIME_Relative expiration_time, 1081 struct GNUNET_TIME_Relative expiration_time,
322 const char *password) 1082 const char *password)
323{ 1083{
324 1084 struct GNUNET_SOCIAL_Place *plc = &hst->plc;
1085 if (NULL == namestore)
1086 namestore = GNUNET_NAMESTORE_connect (plc->cfg);
1087 if (NULL == core)
1088 core = GNUNET_CORE_connect (plc->cfg, NULL, core_connected_cb, NULL, NULL,
1089 NULL, GNUNET_NO, NULL, GNUNET_NO, NULL);
1090
1091 struct GNUNET_GNSRECORD_Data rd = { 0 };
1092 rd.record_type = GNUNET_GNSRECORD_TYPE_PLACE;
1093 rd.flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1094 rd.expiration_time
1095 = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_WEEKS, 1).rel_value_us;
1096
1097 struct GNUNET_GNSRECORD_PlaceData *rec = GNUNET_malloc (sizeof (*rec));
1098 rec->place_key = plc->pub_key;
1099 rec->origin = this_peer;
1100 rec->relay_count = htons (0); // FIXME
1101
1102 rd.data_size = sizeof (*rec);
1103 rd.data = rec;
1104
1105 GNUNET_NAMESTORE_records_store (namestore, &hst->plc.ego_key,
1106 name, 1, &rd, namestore_result_host_advertise,
1107 hst);
325} 1108}
326 1109
327 1110
@@ -342,26 +1125,43 @@ GNUNET_SOCIAL_host_advertise (struct GNUNET_SOCIAL_Host *host,
342 * @return NULL on error (announcement already in progress?). 1125 * @return NULL on error (announcement already in progress?).
343 */ 1126 */
344struct GNUNET_SOCIAL_Announcement * 1127struct GNUNET_SOCIAL_Announcement *
345GNUNET_SOCIAL_host_announce (struct GNUNET_SOCIAL_Host *host, 1128GNUNET_SOCIAL_host_announce (struct GNUNET_SOCIAL_Host *hst,
346 const char *method_name, 1129 const char *method_name,
347 const struct GNUNET_ENV_Environment *env, 1130 const struct GNUNET_ENV_Environment *env,
348 GNUNET_CONNECTION_TransmitReadyNotify notify, 1131 GNUNET_PSYC_TransmitNotifyData notify_data,
349 void *notify_cls, 1132 void *notify_data_cls,
350 enum GNUNET_SOCIAL_AnnounceFlags flags) 1133 enum GNUNET_SOCIAL_AnnounceFlags flags)
351{ 1134{
352 return NULL; 1135 if (GNUNET_OK ==
1136 GNUNET_PSYC_transmit_message (hst->plc.tmit, method_name, env,
1137 NULL, notify_data, notify_data_cls, flags));
1138 return (struct GNUNET_SOCIAL_Announcement *) hst->plc.tmit;
1139}
1140
1141
1142/**
1143 * Resume transmitting announcement.
1144 *
1145 * @param a
1146 * The announcement to resume.
1147 */
1148void
1149GNUNET_SOCIAL_host_announce_resume (struct GNUNET_SOCIAL_Announcement *a)
1150{
1151 GNUNET_PSYC_transmit_resume ((struct GNUNET_PSYC_TransmitHandle *) a);
353} 1152}
354 1153
355 1154
356/** 1155/**
357 * Cancel announcement. 1156 * Cancel announcement.
358 * 1157 *
359 * @param a The announcement to cancel. 1158 * @param a
1159 * The announcement to cancel.
360 */ 1160 */
361void 1161void
362GNUNET_SOCIAL_host_announce_cancel (struct GNUNET_SOCIAL_Announcement *a) 1162GNUNET_SOCIAL_host_announce_cancel (struct GNUNET_SOCIAL_Announcement *a)
363{ 1163{
364 1164 GNUNET_PSYC_transmit_cancel ((struct GNUNET_PSYC_TransmitHandle *) a);
365} 1165}
366 1166
367 1167
@@ -375,9 +1175,9 @@ GNUNET_SOCIAL_host_announce_cancel (struct GNUNET_SOCIAL_Announcement *a)
375 * @return Handle for the hosted place, valid as long as @a host is valid. 1175 * @return Handle for the hosted place, valid as long as @a host is valid.
376 */ 1176 */
377struct GNUNET_SOCIAL_Place * 1177struct GNUNET_SOCIAL_Place *
378GNUNET_SOCIAL_host_get_place (struct GNUNET_SOCIAL_Host *host) 1178GNUNET_SOCIAL_host_get_place (struct GNUNET_SOCIAL_Host *hst)
379{ 1179{
380 return NULL; 1180 return &hst->plc;
381} 1181}
382 1182
383 1183
@@ -390,22 +1190,65 @@ GNUNET_SOCIAL_host_get_place (struct GNUNET_SOCIAL_Host *host)
390 * @param keep_active Keep the place active after last host disconnected. 1190 * @param keep_active Keep the place active after last host disconnected.
391 */ 1191 */
392void 1192void
393GNUNET_SOCIAL_host_leave (struct GNUNET_SOCIAL_Host *host, int keep_active) 1193GNUNET_SOCIAL_host_leave (struct GNUNET_SOCIAL_Host *hst,
1194 int keep_active,
1195 GNUNET_ContinuationCallback leave_cb,
1196 void *leave_cls)
394{ 1197{
1198 struct GNUNET_SOCIAL_Place *plc = &hst->plc;
1199
1200 /* FIXME: send msg to service */
1201
1202 plc->is_disconnecting = GNUNET_YES;
1203 plc->disconnect_cb = leave_cb;
1204 plc->disconnect_cls = leave_cls;
395 1205
1206 GNUNET_CLIENT_MANAGER_disconnect (plc->client, GNUNET_YES,
1207 &host_cleanup, hst);
396} 1208}
397 1209
398 1210
1211static struct GuestEnterRequest *
1212guest_enter_request_create (const struct GNUNET_CRYPTO_EcdsaPrivateKey *guest_key,
1213 const struct GNUNET_CRYPTO_EddsaPublicKey *place_key,
1214 const struct GNUNET_PeerIdentity *origin,
1215 size_t relay_count,
1216 const struct GNUNET_PeerIdentity *relays,
1217 const struct GNUNET_PSYC_Message *join_msg)
1218{
1219 uint16_t join_msg_size = ntohs (join_msg->header.size);
1220 uint16_t relay_size = relay_count * sizeof (*relays);
1221
1222 struct GuestEnterRequest *
1223 req = GNUNET_malloc (sizeof (*req) + relay_size + join_msg_size);
1224
1225 req->header.size = htons (sizeof (*req) + relay_size + join_msg_size);
1226 req->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER);
1227 req->place_key = *place_key;
1228 req->guest_key = *guest_key;
1229 req->origin = *origin;
1230 req->relay_count = relay_count;
1231
1232 uint16_t p = sizeof (*req);
1233 if (0 < relay_size)
1234 {
1235 memcpy ((char *) req + p, relays, relay_size);
1236 p += relay_size;
1237 }
1238
1239 memcpy ((char *) req + p, join_msg, join_msg_size);
1240 return req;
1241}
1242
399/** 1243/**
400 * Request entry to a place as a guest. 1244 * Request entry to a place as a guest.
401 * 1245 *
402 * @param cfg Configuration to contact the social service. 1246 * @param cfg Configuration to contact the social service.
403 * @param ego Identity of the guest. 1247 * @param ego Identity of the guest.
404 * @param address GNS name of the place to enter. Either in the form of 1248 * @param crypto_address Public key of the place to enter.
405 * 'room.friend.gnu', or 'NYMPUBKEY.zkey'. This latter case refers to 1249 * @param origin Peer identity of the origin of the underlying multicast group.
406 * the 'PLACE' record of the empty label ("+") in the GNS zone with the 1250 * @param relay_count Number of elements in the @a relays array.
407 * nym's public key 'NYMPUBKEY', and can be used to request entry to a 1251 * @param relays Relays for the underlying multicast group.
408 * pseudonym's place directly.
409 * @param method_name Method name for the message. 1252 * @param method_name Method name for the message.
410 * @param env Environment containing variables for the message, or NULL. 1253 * @param env Environment containing variables for the message, or NULL.
411 * @param data Payload for the message to give to the enter callback. 1254 * @param data Payload for the message to give to the enter callback.
@@ -416,26 +1259,132 @@ GNUNET_SOCIAL_host_leave (struct GNUNET_SOCIAL_Host *host, int keep_active)
416 */ 1259 */
417struct GNUNET_SOCIAL_Guest * 1260struct GNUNET_SOCIAL_Guest *
418GNUNET_SOCIAL_guest_enter (const struct GNUNET_CONFIGURATION_Handle *cfg, 1261GNUNET_SOCIAL_guest_enter (const struct GNUNET_CONFIGURATION_Handle *cfg,
419 struct GNUNET_IDENTITY_Ego *ego, 1262 const struct GNUNET_IDENTITY_Ego *ego,
420 char *address, 1263 const struct GNUNET_CRYPTO_EddsaPublicKey *place_key,
421 const char *method_name, 1264 const struct GNUNET_PeerIdentity *origin,
422 const struct GNUNET_ENV_Environment *env, 1265 uint32_t relay_count,
423 const void *data, 1266 const struct GNUNET_PeerIdentity *relays,
424 size_t data_size, 1267 const struct GNUNET_PSYC_Message *entry_msg,
425 struct GNUNET_SOCIAL_Slicer *slicer) 1268 struct GNUNET_SOCIAL_Slicer *slicer,
1269 GNUNET_SOCIAL_GuestEnterCallback local_enter_cb,
1270 GNUNET_SOCIAL_EntryDecisionCallback entry_dcsn_cb,
1271 void *cls)
426{ 1272{
427 return NULL; 1273 struct GNUNET_SOCIAL_Guest *gst = GNUNET_malloc (sizeof (*gst));
1274 struct GNUNET_SOCIAL_Place *plc = &gst->plc;
1275
1276 struct GuestEnterRequest *
1277 req = guest_enter_request_create (&plc->ego_key, place_key, origin,
1278 relay_count, relays, entry_msg);
1279 plc->connect_msg = &req->header;
1280 plc->ego_key = *GNUNET_IDENTITY_ego_get_private_key (ego);
1281 plc->pub_key = *place_key;
1282 plc->cfg = cfg;
1283 plc->is_host = GNUNET_YES;
1284 plc->slicer = slicer;
1285
1286 gst->enter_cb = local_enter_cb;
1287 gst->entry_dcsn_cb = entry_dcsn_cb;
1288 gst->cb_cls = cls;
1289
1290 plc->client = GNUNET_CLIENT_MANAGER_connect (cfg, "social", guest_handlers);
1291 GNUNET_CLIENT_MANAGER_set_user_context_ (plc->client, gst, sizeof (*plc));
1292
1293 plc->tmit = GNUNET_PSYC_transmit_create (plc->client);
1294 plc->recv = GNUNET_PSYC_receive_create (NULL, &slicer_message, plc->slicer);
1295
1296 place_send_connect_msg (plc);
1297 return gst;
1298}
1299
1300
1301/**
1302 * Result of a GNS name lookup for entering a place.
1303 *
1304 * @see GNUNET_SOCIAL_guest_enter_by_name
1305 */
1306static void
1307gns_result_guest_enter (void *cls, uint32_t rd_count,
1308 const struct GNUNET_GNSRECORD_Data *rd)
1309{
1310 struct GNUNET_SOCIAL_Guest *gst = cls;
1311 struct GNUNET_SOCIAL_Place *plc = &gst->plc;
1312
1313 const struct GNUNET_GNSRECORD_PlaceData *
1314 rec = (const struct GNUNET_GNSRECORD_PlaceData *) rd->data;
1315
1316 if (0 == rd_count)
1317 {
1318 if (NULL != gst->enter_cb)
1319 gst->enter_cb (gst->cb_cls, GNUNET_SYSERR, 0);
1320 return;
1321 }
1322
1323
1324 if (rd->data_size < sizeof (*rec))
1325 {
1326 GNUNET_break_op (0);
1327 if (NULL != gst->enter_cb)
1328 gst->enter_cb (gst->cb_cls, GNUNET_SYSERR, 0);
1329 return;
1330 }
1331
1332 struct GuestEnterRequest *
1333 req = (struct GuestEnterRequest *) plc->connect_msg;
1334 uint16_t req_size = ntohs (req->header.size);
1335
1336 struct GNUNET_PeerIdentity *relays = NULL;
1337 uint16_t relay_count = ntohs (rec->relay_count);
1338
1339 if (0 < relay_count)
1340 {
1341 uint16_t relay_size = relay_count * sizeof (struct GNUNET_PeerIdentity);
1342 struct GuestEnterRequest *
1343 req2 = GNUNET_malloc (req_size + relay_size);
1344
1345 req2->header.size = htons (req_size + relay_size);
1346 req2->header.type = req->header.type;
1347 req2->guest_key = req->guest_key;
1348
1349 uint16_t p = sizeof (*req);
1350 if (0 < relay_size)
1351 {
1352 memcpy ((char *) req2 + p, relays, relay_size);
1353 p += relay_size;
1354 }
1355
1356 memcpy ((char *) req + p, &req[1], req_size - sizeof (*req));
1357
1358 plc->connect_msg = &req2->header;
1359 GNUNET_free (req);
1360 req = req2;
1361 }
1362
1363 req->place_key = rec->place_key;
1364 req->origin = rec->origin;
1365 req->relay_count = rec->relay_count;
1366 memcpy (&req[1], &rec[1],
1367 ntohl (rec->relay_count) * sizeof (struct GNUNET_PeerIdentity));
1368
1369 plc->connect_msg = &req->header;
1370 plc->pub_key = req->place_key;
1371
1372 plc->tmit = GNUNET_PSYC_transmit_create (plc->client);
1373 plc->recv = GNUNET_PSYC_receive_create (NULL, &slicer_message, plc);
1374
1375 place_send_connect_msg (plc);
428} 1376}
429 1377
430/** 1378/**
431 * Request entry to a place as a guest. 1379 * Request entry to a place as a guest.
432 * 1380 *
433 * @param cfg Configuration to contact the social service. 1381 * @param cfg Configuration to contact the social service.
434 * @param ego Identity of the guest. 1382 * @param ego Identity of the guest.
435 * @param crypto_address Public key of the place to enter. 1383 * @param address GNS name of the place to enter. Either in the form of
436 * @param origin Peer identity of the origin of the underlying multicast group. 1384 * 'room.friend.gnu', or 'NYMPUBKEY.zkey'. This latter case refers to
437 * @param relay_count Number of elements in the @a relays array. 1385 * the 'PLACE' record of the empty label ("+") in the GNS zone with the
438 * @param relays Relays for the underlying multicast group. 1386 * nym's public key 'NYMPUBKEY', and can be used to request entry to a
1387 * pseudonym's place directly.
439 * @param method_name Method name for the message. 1388 * @param method_name Method name for the message.
440 * @param env Environment containing variables for the message, or NULL. 1389 * @param env Environment containing variables for the message, or NULL.
441 * @param data Payload for the message to give to the enter callback. 1390 * @param data Payload for the message to give to the enter callback.
@@ -445,41 +1394,75 @@ GNUNET_SOCIAL_guest_enter (const struct GNUNET_CONFIGURATION_Handle *cfg,
445 * @return NULL on errors, otherwise handle for the guest. 1394 * @return NULL on errors, otherwise handle for the guest.
446 */ 1395 */
447struct GNUNET_SOCIAL_Guest * 1396struct GNUNET_SOCIAL_Guest *
448GNUNET_SOCIAL_guest_enter2 (const struct GNUNET_CONFIGURATION_Handle *cfg, 1397GNUNET_SOCIAL_guest_enter_by_name (const struct GNUNET_CONFIGURATION_Handle *cfg,
449 struct GNUNET_IDENTITY_Ego *ego, 1398 struct GNUNET_IDENTITY_Ego *ego,
450 struct GNUNET_CRYPTO_EddsaPublicKey *crypto_address, 1399 char *gns_name,
451 struct GNUNET_PeerIdentity *origin, 1400 const struct GNUNET_PSYC_Message *join_msg,
452 size_t relay_count, 1401 struct GNUNET_SOCIAL_Slicer *slicer,
453 struct GNUNET_PeerIdentity *relays, 1402 GNUNET_SOCIAL_GuestEnterCallback local_enter_cb,
454 const char *method_name, 1403 GNUNET_SOCIAL_EntryDecisionCallback entry_decision_cb,
455 const struct GNUNET_ENV_Environment *env, 1404 void *cls)
456 const void *data,
457 size_t data_size,
458 struct GNUNET_SOCIAL_Slicer *slicer)
459{ 1405{
460 return NULL; 1406 struct GNUNET_SOCIAL_Guest *gst = GNUNET_malloc (sizeof (*gst));
1407 struct GNUNET_SOCIAL_Place *plc = &gst->plc;
1408
1409 gst->enter_cb = local_enter_cb;
1410 gst->cb_cls = cls;
1411
1412 plc->ego_key = *GNUNET_IDENTITY_ego_get_private_key (ego);
1413 plc->cfg = cfg;
1414 plc->is_host = GNUNET_NO;
1415 plc->slicer = slicer;
1416
1417 struct GuestEnterRequest *
1418 req = guest_enter_request_create (&plc->ego_key, NULL, NULL, 0, NULL,
1419 join_msg);
1420 plc->connect_msg = &req->header;
1421
1422 /* FIXME: get the public key of the origin and relays
1423 * by looking up the PLACE record of gns_name.
1424 */
1425 if (NULL == gns)
1426 gns = GNUNET_GNS_connect (cfg);
1427
1428 plc->client = GNUNET_CLIENT_MANAGER_connect (cfg, "social", guest_handlers);
1429 GNUNET_CLIENT_MANAGER_set_user_context_ (plc->client, gst, sizeof (*plc));
1430
1431 struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key;
1432 GNUNET_IDENTITY_ego_get_public_key (ego, &ego_pub_key);
1433 GNUNET_GNS_lookup (gns, gns_name, &ego_pub_key,
1434 GNUNET_GNSRECORD_TYPE_PLACE, GNUNET_GNS_LO_DEFAULT,
1435 NULL, gns_result_guest_enter, gst);
1436
1437 return gst;
461} 1438}
462 1439
463 1440
464/** 1441/**
465 * Talk to the host of the place. 1442 * Talk to the host of the place.
466 * 1443 *
467 * @param place Place where we want to talk to the host. 1444 * @param place
468 * @param method_name Method to invoke on the host. 1445 * Place where we want to talk to the host.
469 * @param env Environment containing variables for the message, or NULL. 1446 * @param method_name
470 * @param notify Function to use to get the payload for the method. 1447 * Method to invoke on the host.
471 * @param notify_cls Closure for @a notify. 1448 * @param env
472 * @param flags Flags for the message being sent. 1449 * Environment containing variables for the message, or NULL.
1450 * @param notify_data
1451 * Function to use to get the payload for the method.
1452 * @param notify_data_cls
1453 * Closure for @a notify_data.
1454 * @param flags
1455 * Flags for the message being sent.
473 * 1456 *
474 * @return NULL if we are already trying to talk to the host, 1457 * @return NULL if we are already trying to talk to the host,
475 * otherwise handle to cancel the request. 1458 * otherwise handle to cancel the request.
476 */ 1459 */
477struct GNUNET_SOCIAL_TalkRequest * 1460struct GNUNET_SOCIAL_TalkRequest *
478GNUNET_SOCIAL_guest_talk (struct GNUNET_SOCIAL_Place *place, 1461GNUNET_SOCIAL_guest_talk (struct GNUNET_SOCIAL_Guest *guest,
479 const char *method_name, 1462 const char *method_name,
480 const struct GNUNET_ENV_Environment *env, 1463 const struct GNUNET_ENV_Environment *env,
481 GNUNET_CONNECTION_TransmitReadyNotify notify, 1464 GNUNET_PSYC_TransmitNotifyData notify_data,
482 void *notify_cls, 1465 void *notify_data_cls,
483 enum GNUNET_SOCIAL_TalkFlags flags) 1466 enum GNUNET_SOCIAL_TalkFlags flags)
484{ 1467{
485 return NULL; 1468 return NULL;
@@ -487,14 +1470,28 @@ GNUNET_SOCIAL_guest_talk (struct GNUNET_SOCIAL_Place *place,
487 1470
488 1471
489/** 1472/**
1473 * Resume talking to the host of the place.
1474 *
1475 * @param tr
1476 * Talk request to resume.
1477 */
1478void
1479GNUNET_SOCIAL_guest_talk_resume (struct GNUNET_SOCIAL_TalkRequest *tr)
1480{
1481 GNUNET_PSYC_transmit_resume ((struct GNUNET_PSYC_TransmitHandle *) tr);
1482}
1483
1484
1485/**
490 * Cancel talking to the host of the place. 1486 * Cancel talking to the host of the place.
491 * 1487 *
492 * @param tr Talk request to cancel. 1488 * @param tr
1489 * Talk request to cancel.
493 */ 1490 */
494void 1491void
495GNUNET_SOCIAL_guest_talk_cancel (struct GNUNET_SOCIAL_TalkRequest *tr) 1492GNUNET_SOCIAL_guest_talk_cancel (struct GNUNET_SOCIAL_TalkRequest *tr)
496{ 1493{
497 1494 GNUNET_PSYC_transmit_cancel ((struct GNUNET_PSYC_TransmitHandle *) tr);
498} 1495}
499 1496
500 1497
@@ -507,9 +1504,21 @@ GNUNET_SOCIAL_guest_talk_cancel (struct GNUNET_SOCIAL_TalkRequest *tr)
507 * @param keep_active Keep place active after last application disconnected. 1504 * @param keep_active Keep place active after last application disconnected.
508 */ 1505 */
509void 1506void
510GNUNET_SOCIAL_guest_leave (struct GNUNET_SOCIAL_Place *place, int keep_active) 1507GNUNET_SOCIAL_guest_leave (struct GNUNET_SOCIAL_Guest *gst,
1508 int keep_active,
1509 GNUNET_ContinuationCallback leave_cb,
1510 void *leave_cls)
511{ 1511{
1512 struct GNUNET_SOCIAL_Place *plc = &gst->plc;
1513
1514 /* FIXME: send msg to service */
1515
1516 plc->is_disconnecting = GNUNET_YES;
1517 plc->disconnect_cb = leave_cb;
1518 plc->disconnect_cls = leave_cls;
512 1519
1520 GNUNET_CLIENT_MANAGER_disconnect (plc->client, GNUNET_YES,
1521 &guest_cleanup, gst);
513} 1522}
514 1523
515 1524
@@ -523,9 +1532,9 @@ GNUNET_SOCIAL_guest_leave (struct GNUNET_SOCIAL_Place *place, int keep_active)
523 * @return Handle for the place, valid as long as @a guest is valid. 1532 * @return Handle for the place, valid as long as @a guest is valid.
524 */ 1533 */
525struct GNUNET_SOCIAL_Place * 1534struct GNUNET_SOCIAL_Place *
526GNUNET_SOCIAL_guest_get_place (struct GNUNET_SOCIAL_Host *guest) 1535GNUNET_SOCIAL_guest_get_place (struct GNUNET_SOCIAL_Guest *gst)
527{ 1536{
528 return NULL; 1537 return &gst->plc;
529} 1538}
530 1539
531 1540
@@ -671,6 +1680,4 @@ GNUNET_SOCIAL_place_look_at (struct GNUNET_SOCIAL_Place *place,
671} 1680}
672 1681
673 1682
674
675
676/* end of social_api.c */ 1683/* end of social_api.c */
diff --git a/src/social/test_social.c b/src/social/test_social.c
index 053e347d1..340c4482a 100644
--- a/src/social/test_social.c
+++ b/src/social/test_social.c
@@ -17,7 +17,6 @@
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA. 18 * Boston, MA 02111-1307, USA.
19 */ 19 */
20
21/** 20/**
22 * @file social/test_social.c 21 * @file social/test_social.c
23 * @brief Tests for the Social API. 22 * @brief Tests for the Social API.
@@ -32,32 +31,132 @@
32#include "gnunet_util_lib.h" 31#include "gnunet_util_lib.h"
33#include "gnunet_testing_lib.h" 32#include "gnunet_testing_lib.h"
34#include "gnunet_env_lib.h" 33#include "gnunet_env_lib.h"
34#include "gnunet_psyc_util_lib.h"
35#include "gnunet_social_service.h" 35#include "gnunet_social_service.h"
36#include "gnunet_core_service.h"
37#include "gnunet_identity_service.h"
36 38
37#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) 39#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
38 40
39#define DEBUG_SERVICE 0 41#define DEBUG_SERVICE 0
42#define DATA2ARG(data) data, sizeof (data)
40 43
41/** 44/**
42 * Return value from 'main'. 45 * Return value from 'main'.
43 */ 46 */
44static int res; 47int res;
45
46static const struct GNUNET_CONFIGURATION_Handle *cfg;
47 48
48/** 49/**
49 * Handle for task for timeout termination. 50 * Handle for task for timeout termination.
50 */ 51 */
51static GNUNET_SCHEDULER_TaskIdentifier end_badly_task; 52GNUNET_SCHEDULER_TaskIdentifier end_badly_task;
53
54const struct GNUNET_CONFIGURATION_Handle *cfg;
55
56struct GNUNET_CORE_Handle *core;
57struct GNUNET_PeerIdentity this_peer;
58
59struct GNUNET_IDENTITY_Handle *id;
60
61const struct GNUNET_IDENTITY_Ego *host_ego;
62const struct GNUNET_IDENTITY_Ego *guest_ego;
63
64const char *host_name = "Host One";
65const char *guest_name = "Guest One";
66
67struct GNUNET_CRYPTO_EddsaPrivateKey *place_key;
68struct GNUNET_CRYPTO_EcdsaPrivateKey *guest_key;
69
70struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key;
71struct GNUNET_CRYPTO_EcdsaPublicKey guest_pub_key;
72
73struct GNUNET_SOCIAL_Slicer *host_slicer;
74struct GNUNET_SOCIAL_Slicer *guest_slicer;
75
76struct GNUNET_SOCIAL_Host *hst;
77struct GNUNET_SOCIAL_Guest *gst;
78
79struct GuestEnterMessage
80{
81 struct GNUNET_PSYC_Message *msg;
82 const char *method_name;
83 struct GNUNET_ENV_Environment *env;
84 void *data;
85 uint16_t data_size;
86} guest_enter_msg;
87
88struct TransmitClosure
89{
90 struct GNUNET_SOCIAL_Announcement *host_ann;
91 struct GNUNET_SOCIAL_TalkRequest *guest_talk;
92 struct GNUNET_ENV_Environment *env;
93 char *data[16];
94 uint8_t data_delay[16];
95 uint8_t data_count;
96 uint8_t paused;
97 uint8_t n;
98} tmit;
99
100uint8_t join_req_count;
101struct GNUNET_PSYC_Message *join_resp;
102
103enum
104{
105 TEST_NONE = 0,
106 TEST_HOST_ANSWER_DOOR_REFUSE = 1,
107 TEST_GUEST_RECV_ENTRY_DCSN_REFUSE = 2,
108 TEST_HOST_ANSWER_DOOR_ADMIT = 3,
109 TEST_GUEST_RECV_ENTRY_DCSN_ADMIT = 4,
110 TEST_HOST_ANNOUNCE = 5,
111 TEST_HOST_ANNOUNCE_END = 6,
112 TEST_GUEST_TALK = 7,
113 TEST_GUEST_TALK_END = 8,
114 TEST_GUEST_LEAVE = 9,
115 TEST_HOST_LEAVE = 10,
116} test;
117
118
119void
120guest_enter ();
121
122
123void
124guest_talk ();
125
126
127void
128host_announce2 ();
52 129
53 130
54/** 131/**
55 * Clean up all resources used. 132 * Clean up all resources used.
56 */ 133 */
57static void 134void
58cleanup () 135cleanup ()
59{ 136{
137 if (NULL != core)
138 {
139 GNUNET_CORE_disconnect (core);
140 core = NULL;
141 }
60 142
143 if (NULL != id)
144 {
145 GNUNET_IDENTITY_disconnect (id);
146 id = NULL;
147 }
148
149 if (NULL != gst)
150 {
151 GNUNET_SOCIAL_guest_leave (gst, GNUNET_NO, NULL, NULL);
152 gst = NULL;
153 }
154 if (NULL != hst)
155 {
156 GNUNET_SOCIAL_host_leave (hst, GNUNET_NO, NULL, NULL);
157 hst = NULL;
158 }
159 GNUNET_SCHEDULER_shutdown ();
61} 160}
62 161
63 162
@@ -67,7 +166,7 @@ cleanup ()
67 * @param cls NULL 166 * @param cls NULL
68 * @param tc scheduler context 167 * @param tc scheduler context
69 */ 168 */
70static void 169void
71end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 170end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
72{ 171{
73 res = 1; 172 res = 1;
@@ -82,7 +181,7 @@ end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
82 * @param cls NULL 181 * @param cls NULL
83 * @param tc scheduler context 182 * @param tc scheduler context
84 */ 183 */
85static void 184void
86end_normally (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 185end_normally (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
87{ 186{
88 res = 0; 187 res = 0;
@@ -94,7 +193,7 @@ end_normally (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
94/** 193/**
95 * Finish the test case (successfully). 194 * Finish the test case (successfully).
96 */ 195 */
97static void 196void
98end () 197end ()
99{ 198{
100 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending tests.\n"); 199 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending tests.\n");
@@ -109,6 +208,564 @@ end ()
109} 208}
110 209
111 210
211static void
212transmit_resume (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
213{
214 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmission resumed.\n");
215 struct TransmitClosure *tmit = cls;
216 if (NULL != tmit->host_ann)
217 GNUNET_SOCIAL_host_announce_resume (tmit->host_ann);
218 else
219 GNUNET_SOCIAL_guest_talk_resume (tmit->guest_talk);
220}
221
222
223int
224notify_data (void *cls, uint16_t *data_size, void *data)
225{
226 struct TransmitClosure *tmit = cls;
227 if (NULL != tmit->env)
228 {
229 GNUNET_ENV_environment_destroy (tmit->env);
230 tmit->env = NULL;
231 }
232 if (0 == tmit->data_count)
233 {
234 *data_size = 0;
235 return GNUNET_YES;
236 }
237
238 uint16_t size = strlen (tmit->data[tmit->n]) + 1;
239 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
240 "Transmit notify data: %u bytes available, "
241 "processing fragment %u/%u (size %u).\n",
242 *data_size, tmit->n + 1, tmit->data_count, size);
243 if (*data_size < size)
244 {
245 *data_size = 0;
246 GNUNET_assert (0);
247 return GNUNET_SYSERR;
248 }
249
250 if (GNUNET_YES != tmit->paused && 0 < tmit->data_delay[tmit->n])
251 {
252 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmission paused.\n");
253 tmit->paused = GNUNET_YES;
254 GNUNET_SCHEDULER_add_delayed (
255 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
256 tmit->data_delay[tmit->n]),
257 &transmit_resume, tmit);
258 *data_size = 0;
259 return GNUNET_NO;
260 }
261 tmit->paused = GNUNET_NO;
262
263 *data_size = size;
264 memcpy (data, tmit->data[tmit->n], size);
265
266 return ++tmit->n < tmit->data_count ? GNUNET_NO : GNUNET_YES;
267}
268
269
270void host_left ()
271{
272 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
273 "The host has left the place.\n");
274 GNUNET_SOCIAL_slicer_destroy (host_slicer);
275 host_slicer = NULL;
276 hst = NULL;
277
278 end ();
279}
280
281
282void
283schedule_host_leave (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
284{
285 test = TEST_HOST_LEAVE;
286 GNUNET_SOCIAL_host_leave (hst, GNUNET_NO, &host_left, NULL);
287}
288
289
290void
291host_farewell (void *cls,
292 struct GNUNET_SOCIAL_Nym *nym,
293 struct GNUNET_ENV_Environment *env,
294 size_t variable_count,
295 struct GNUNET_ENV_Modifier *variables)
296{
297 struct GNUNET_CRYPTO_EcdsaPublicKey *
298 nym_key = GNUNET_SOCIAL_nym_get_key (nym);
299 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
300 "Nym %s has left the place.\n",
301 GNUNET_CRYPTO_ecdsa_public_key_to_string (nym_key));
302 GNUNET_assert (0 == memcmp (&guest_pub_key, nym_key, sizeof (*nym_key)));
303
304 GNUNET_SCHEDULER_add_now (&schedule_host_leave, NULL);
305}
306
307
308void
309guest_left (void *cls)
310{
311 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
312 "The guest has left the place.\n");
313 GNUNET_SOCIAL_slicer_destroy (guest_slicer);
314 guest_slicer = NULL;
315 gst = NULL;
316
317 GNUNET_SCHEDULER_add_now (&schedule_host_leave, NULL);
318}
319
320
321void
322schedule_guest_leave (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
323{
324 test = TEST_GUEST_LEAVE;
325 /* FIXME test keep_active */
326 GNUNET_SOCIAL_guest_leave (gst, GNUNET_NO, &guest_left, NULL);
327}
328
329
330
331void
332guest_recv_method (void *cls,
333 const struct GNUNET_PSYC_MessageMethod *meth,
334 uint64_t message_id,
335 uint32_t flags,
336 const struct GNUNET_SOCIAL_Nym *nym,
337 const char *method_name)
338{
339 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
340 "Test #%u: Guest received method for message ID %" PRIu64 ":\n"
341 "%s\n",
342 test, message_id, method_name);
343 /* FIXME: check message */
344}
345
346
347void
348guest_recv_modifier (void *cls,
349 const struct GNUNET_PSYC_MessageModifier *mod,
350 uint64_t message_id,
351 enum GNUNET_ENV_Operator oper,
352 const char *name,
353 const void *value,
354 uint16_t value_size)
355{
356 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
357 "Test #%u: Guest received modifier for message ID %" PRIu64 ":\n"
358 "%c%s: %.*s\n",
359 test, message_id, oper, name, value_size, value);
360}
361
362
363void
364guest_recv_data (void *cls,
365 const struct GNUNET_MessageHeader *msg,
366 uint64_t message_id,
367 uint64_t data_offset,
368 const void *data,
369 uint16_t data_size)
370{
371 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
372 "Test #%u: Guest received data for message ID %" PRIu64 ":\n"
373 "%.*s\n",
374 test, message_id, data_size, data);
375}
376
377
378void
379guest_recv_eom (void *cls,
380 const struct GNUNET_MessageHeader *msg,
381 uint64_t message_id,
382 uint8_t cancelled)
383{
384 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
385 "Test #%u: Guest received end of message ID %" PRIu64
386 ", cancelled: %u\n",
387 test, message_id, cancelled);
388
389 switch (test)
390 {
391 case TEST_HOST_ANNOUNCE:
392 test = TEST_HOST_ANNOUNCE_END;
393 break;
394
395 case TEST_HOST_ANNOUNCE_END:
396 guest_talk ();
397 break;
398
399 case TEST_GUEST_TALK:
400 test = TEST_GUEST_TALK_END;
401 break;
402
403 case TEST_GUEST_TALK_END:
404 GNUNET_SCHEDULER_add_now (&schedule_guest_leave, NULL);
405 break;
406
407 default:
408 GNUNET_assert (0);
409 }
410}
411
412
413void
414host_recv_method (void *cls,
415 const struct GNUNET_PSYC_MessageMethod *meth,
416 uint64_t message_id,
417 uint32_t flags,
418 const struct GNUNET_SOCIAL_Nym *nym,
419 const char *method_name)
420{
421 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
422 "Test #%u: Host received method for message ID %" PRIu64 ":\n"
423 "%s\n",
424 test, message_id, method_name);
425 /* FIXME: check message */
426}
427
428
429void
430host_recv_modifier (void *cls,
431 const struct GNUNET_PSYC_MessageModifier *mod,
432 uint64_t message_id,
433 enum GNUNET_ENV_Operator oper,
434 const char *name,
435 const void *value,
436 uint16_t value_size)
437{
438 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
439 "Test #%u: Host received modifier for message ID %" PRIu64 ":\n"
440 "%c%s: %.*s\n",
441 test, message_id, oper, name, value_size, value);
442}
443
444
445void
446host_recv_data (void *cls,
447 const struct GNUNET_MessageHeader *msg,
448 uint64_t message_id,
449 uint64_t data_offset,
450 const void *data,
451 uint16_t data_size)
452{
453 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
454 "Test #%u: Host received data for message ID %" PRIu64 ":\n"
455 "%.*s\n",
456 test, message_id, data_size, data);
457}
458
459
460void
461host_recv_eom (void *cls,
462 const struct GNUNET_MessageHeader *msg,
463 uint64_t message_id,
464 uint8_t cancelled)
465{
466 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
467 "Test #%u: Host received end of message ID %" PRIu64
468 ", cancelled: %u\n",
469 test, message_id, cancelled);
470
471 switch (test)
472 {
473 case TEST_HOST_ANNOUNCE:
474 test = TEST_HOST_ANNOUNCE_END;
475 //host_announce2 ();
476 break;
477
478 case TEST_HOST_ANNOUNCE_END:
479 guest_talk ();
480 break;
481
482 case TEST_GUEST_TALK:
483 test = TEST_GUEST_TALK_END;
484 break;
485
486 case TEST_GUEST_TALK_END:
487 GNUNET_SCHEDULER_add_now (&schedule_guest_leave, NULL);
488 break;
489
490 default:
491 GNUNET_assert (0);
492 }
493}
494
495
496void
497guest_talk ()
498{
499 test = TEST_GUEST_TALK;
500
501 tmit = (struct TransmitClosure) {};
502 tmit.env = GNUNET_ENV_environment_create ();
503 GNUNET_ENV_environment_add (tmit.env, GNUNET_ENV_OP_ASSIGN,
504 "_bar_foo", DATA2ARG ("one two three"));
505 GNUNET_ENV_environment_add (tmit.env, GNUNET_ENV_OP_ASSIGN,
506 "_bar_baz", DATA2ARG ("four five"));
507 tmit.data[0] = "zzz xxx yyy";
508 tmit.data[1] = "zyx wvu tsr qpo";
509 tmit.data[2] = "testing ten nine eight";
510 tmit.data_count = 3;
511
512 tmit.host_ann
513 = GNUNET_SOCIAL_host_announce (hst, "_message_guest", tmit.env,
514 &notify_data, &tmit,
515 GNUNET_SOCIAL_TALK_NONE);
516}
517
518void
519host_announce ()
520{
521 test = TEST_HOST_ANNOUNCE;
522
523 tmit = (struct TransmitClosure) {};
524 tmit.env = GNUNET_ENV_environment_create ();
525 GNUNET_ENV_environment_add (tmit.env, GNUNET_ENV_OP_ASSIGN,
526 "_foo", DATA2ARG ("bar baz"));
527 GNUNET_ENV_environment_add (tmit.env, GNUNET_ENV_OP_ASSIGN,
528 "_foo_bar", DATA2ARG ("foo bar"));
529 GNUNET_ENV_environment_add (tmit.env, GNUNET_ENV_OP_ASSIGN,
530 "_foo_bar_baz", DATA2ARG ("foo bar baz"));
531 tmit.data[0] = "aaa bbb ccc";
532 tmit.data[1] = "abc def ghi jkl";
533 tmit.data[2] = "testing one two three";
534 tmit.data[3] = "four five";
535 tmit.data_count = 4;
536
537 tmit.host_ann
538 = GNUNET_SOCIAL_host_announce (hst, "_message_host", tmit.env,
539 &notify_data, &tmit,
540 GNUNET_SOCIAL_ANNOUNCE_NONE);
541}
542
543void
544host_announce2 ()
545{
546 test = TEST_HOST_ANNOUNCE;
547
548 tmit = (struct TransmitClosure) {};
549 tmit.env = GNUNET_ENV_environment_create ();
550 GNUNET_ENV_environment_add (tmit.env, GNUNET_ENV_OP_ASSIGN,
551 "_foo2", DATA2ARG ("BAR BAZ"));
552 GNUNET_ENV_environment_add (tmit.env, GNUNET_ENV_OP_ASSIGN,
553 "_foo2_bar", DATA2ARG ("FOO BAR"));
554 GNUNET_ENV_environment_add (tmit.env, GNUNET_ENV_OP_ASSIGN,
555 "_foo2_bar", DATA2ARG ("FOO BAR BAZ"));
556 tmit.data[0] = "AAA BBB CCC";
557 tmit.data[1] = "ABC DEF GHI JKL";
558 tmit.data[2] = "TESTING ONE TWO THREE";
559 tmit.data_count = 3;
560
561 tmit.host_ann
562 = GNUNET_SOCIAL_host_announce (hst, "_message_host_two", tmit.env,
563 &notify_data, &tmit,
564 GNUNET_SOCIAL_ANNOUNCE_NONE);
565}
566
567
568void
569guest_recv_entry_decision (void *cls,
570 int is_admitted,
571 const struct GNUNET_PSYC_Message *entry_resp)
572{
573 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
574 "Guest received entry decision (try %u): %d.\n",
575 join_req_count, is_admitted);
576
577 if (NULL != entry_resp)
578 {
579 struct GNUNET_ENV_Environment *env = GNUNET_ENV_environment_create ();
580 const char *method_name = NULL;
581 const void *data = NULL;
582 uint16_t data_size = 0;
583 GNUNET_PSYC_message_parse (entry_resp, &method_name, env, &data, &data_size);
584
585 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
586 "%s\n%.*s\n",
587 method_name, data_size, data);
588 /* FIXME: check response message */
589 }
590
591 switch (test)
592 {
593 case TEST_GUEST_RECV_ENTRY_DCSN_REFUSE:
594 GNUNET_assert (GNUNET_NO == is_admitted);
595 guest_enter ();
596 break;
597
598 case TEST_GUEST_RECV_ENTRY_DCSN_ADMIT:
599 GNUNET_assert (GNUNET_YES == is_admitted);
600 host_announce ();
601 break;
602
603 default:
604 GNUNET_assert (0);
605 }
606}
607
608
609void
610host_answer_door (void *cls,
611 struct GNUNET_SOCIAL_Nym *nym,
612 const char *method_name,
613 struct GNUNET_ENV_Environment *env,
614 size_t data_size,
615 const void *data)
616{
617 join_req_count++;
618
619 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
620 "Host received entry request from guest (try %u).\n",
621 join_req_count);
622 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
623 "%s\n%.*s\n",
624 method_name, data_size, data);
625
626 switch (test)
627 {
628 case TEST_HOST_ANSWER_DOOR_REFUSE:
629 test = TEST_GUEST_RECV_ENTRY_DCSN_REFUSE;
630 join_resp = GNUNET_PSYC_message_create ("_refuse_nym", env,
631 DATA2ARG ("Go away!"));
632 GNUNET_SOCIAL_host_entry_decision (hst, nym, GNUNET_NO, join_resp);
633 break;
634
635 case TEST_HOST_ANSWER_DOOR_ADMIT:
636 test = TEST_GUEST_RECV_ENTRY_DCSN_ADMIT;
637 join_resp = GNUNET_PSYC_message_create ("_admit_nym", env,
638 DATA2ARG ("Welcome, nym!"));
639 GNUNET_SOCIAL_host_entry_decision (hst, nym, GNUNET_YES, join_resp);
640 break;
641
642 default:
643 GNUNET_assert (0);
644 }
645}
646
647
648void
649guest_recv_local_enter (void *cls, int result, uint64_t max_message_id)
650{
651 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Guest entered to local place.\n");
652
653}
654
655
656void
657guest_enter ()
658{
659 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Entering to place as guest.\n");
660
661 struct GuestEnterMessage *emsg = &guest_enter_msg;
662
663 emsg->method_name = "_request_enter";
664 emsg->env = GNUNET_ENV_environment_create ();
665 GNUNET_ENV_environment_add (emsg->env, GNUNET_ENV_OP_ASSIGN,
666 "_abc", "abc def", 7);
667 GNUNET_ENV_environment_add (emsg->env, GNUNET_ENV_OP_ASSIGN,
668 "_abc_def", "abc def ghi", 11);
669 emsg->data = "let me in";
670 emsg->data_size = strlen (emsg->data) + 1;
671 emsg->msg = GNUNET_PSYC_message_create (emsg->method_name, emsg->env,
672 emsg->data, emsg->data_size);
673
674 gst = GNUNET_SOCIAL_guest_enter (cfg, guest_ego, &place_pub_key,
675 &this_peer, 0, NULL, emsg->msg,
676 guest_slicer, &guest_recv_local_enter,
677 &guest_recv_entry_decision, NULL);
678}
679
680
681void id_guest_ego_cb (void *cls, const struct GNUNET_IDENTITY_Ego *ego)
682{
683 GNUNET_assert (NULL != ego);
684 guest_ego = ego;
685
686 guest_slicer = GNUNET_SOCIAL_slicer_create ();
687 GNUNET_SOCIAL_slicer_add (guest_slicer, "",
688 &guest_recv_method, &guest_recv_modifier,
689 &guest_recv_data, &guest_recv_eom, NULL);
690 test = TEST_HOST_ANSWER_DOOR_ADMIT;
691 //host_announce ();
692 guest_enter ();
693}
694
695
696void id_guest_created (void *cls, const char *emsg)
697{
698 if (NULL != emsg)
699 {
700 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
701 "Could not create guest identity: %s\n", emsg);
702#if 0 == DEBUG_SERVICE
703 GNUNET_assert (0);
704#endif
705 }
706
707 GNUNET_IDENTITY_ego_lookup (cfg, guest_name, &id_guest_ego_cb, NULL);
708}
709
710
711void host_entered (void *cls, uint64_t max_message_id)
712{
713 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Host entered to place.\n");
714
715 GNUNET_IDENTITY_create (id, guest_name, &id_guest_created, NULL);
716}
717
718
719void id_host_ego_cb (void *cls, const struct GNUNET_IDENTITY_Ego *ego)
720{
721 GNUNET_assert (NULL != ego);
722 host_ego = ego;
723
724 host_slicer = GNUNET_SOCIAL_slicer_create ();
725 GNUNET_SOCIAL_slicer_add (host_slicer, "",
726 &host_recv_method, &host_recv_modifier,
727 &host_recv_data, &host_recv_eom, NULL);
728
729 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Entering to place as host.\n");
730 hst = GNUNET_SOCIAL_host_enter (cfg, host_ego, place_key,
731 GNUNET_PSYC_CHANNEL_PRIVATE, host_slicer,
732 &host_entered, &host_answer_door,
733 &host_farewell, NULL);
734}
735
736
737void id_host_created (void *cls, const char *emsg)
738{
739 if (NULL != emsg)
740 {
741 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
742 "Could not create host identity: %s\n", emsg);
743#if 0 == DEBUG_SERVICE
744 GNUNET_assert (0);
745#endif
746 }
747
748 GNUNET_IDENTITY_ego_lookup (cfg, host_name, &id_host_ego_cb, NULL);
749}
750
751
752void identity_ego_cb (void *cls, struct GNUNET_IDENTITY_Ego *ego,
753 void **ctx, const char *name)
754{
755
756}
757
758
759void
760core_connected (void *cls, const struct GNUNET_PeerIdentity *my_identity)
761{
762 this_peer = *my_identity;
763
764 id = GNUNET_IDENTITY_connect (cfg, &identity_ego_cb, NULL);
765 GNUNET_IDENTITY_create (id, host_name, &id_host_created, NULL);
766}
767
768
112/** 769/**
113 * Main function of the test, run from scheduler. 770 * Main function of the test, run from scheduler.
114 * 771 *
@@ -116,7 +773,7 @@ end ()
116 * @param cfg configuration we use (also to connect to Social service) 773 * @param cfg configuration we use (also to connect to Social service)
117 * @param peer handle to access more of the peer (not used) 774 * @param peer handle to access more of the peer (not used)
118 */ 775 */
119static void 776void
120#if DEBUG_SERVICE 777#if DEBUG_SERVICE
121run (void *cls, char *const *args, const char *cfgfile, 778run (void *cls, char *const *args, const char *cfgfile,
122 const struct GNUNET_CONFIGURATION_Handle *c) 779 const struct GNUNET_CONFIGURATION_Handle *c)
@@ -129,9 +786,14 @@ run (void *cls,
129 cfg = c; 786 cfg = c;
130 end_badly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); 787 end_badly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
131 788
132 /* FIXME: add tests */ 789 place_key = GNUNET_CRYPTO_eddsa_key_create ();
790 guest_key = GNUNET_CRYPTO_ecdsa_key_create ();
133 791
134 end (); 792 GNUNET_CRYPTO_eddsa_key_get_public (place_key, &place_pub_key);
793 GNUNET_CRYPTO_ecdsa_key_get_public (guest_key, &guest_pub_key);
794
795 core = GNUNET_CORE_connect (cfg, NULL, &core_connected, NULL, NULL,
796 NULL, GNUNET_NO, NULL, GNUNET_NO, NULL);
135} 797}
136 798
137 799
diff --git a/src/util/client_manager.c b/src/util/client_manager.c
index c415ce845..6ab2c7c6d 100644
--- a/src/util/client_manager.c
+++ b/src/util/client_manager.c
@@ -30,7 +30,7 @@
30#include "platform.h" 30#include "platform.h"
31#include "gnunet_util_lib.h" 31#include "gnunet_util_lib.h"
32 32
33#define LOG(kind,...) GNUNET_log_from (kind, "util",__VA_ARGS__) 33#define LOG(kind,...) GNUNET_log_from (kind, "util-client-mgr", __VA_ARGS__)
34 34
35 35
36/** 36/**
@@ -94,6 +94,16 @@ struct GNUNET_CLIENT_MANAGER_Connection
94 const struct GNUNET_CLIENT_MANAGER_MessageHandler *handlers; 94 const struct GNUNET_CLIENT_MANAGER_MessageHandler *handlers;
95 95
96 /** 96 /**
97 * Disconnect callback.
98 */
99 void (*disconnect_cb)(void *);
100
101 /**
102 * Disconnect closure.
103 */
104 void *disconnect_cls;
105
106 /**
97 * User context value. 107 * User context value.
98 * @see GNUNET_CLIENT_MANAGER_set_user_context() 108 * @see GNUNET_CLIENT_MANAGER_set_user_context()
99 * @see GNUNET_CLIENT_MANAGER_get_user_context() 109 * @see GNUNET_CLIENT_MANAGER_get_user_context()
@@ -125,7 +135,7 @@ struct GNUNET_CLIENT_MANAGER_Connection
125 * #GNUNET_YES if GNUNET_CLIENT_MANAGER_disconnect() was called 135 * #GNUNET_YES if GNUNET_CLIENT_MANAGER_disconnect() was called
126 * and we're transmitting the last messages from the queue. 136 * and we're transmitting the last messages from the queue.
127 */ 137 */
128 uint8_t disconnecting; 138 uint8_t is_disconnecting;
129}; 139};
130 140
131 141
@@ -185,6 +195,15 @@ static void
185transmit_next (struct GNUNET_CLIENT_MANAGER_Connection *mgr); 195transmit_next (struct GNUNET_CLIENT_MANAGER_Connection *mgr);
186 196
187 197
198static void
199schedule_disconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
200{
201 struct GNUNET_CLIENT_MANAGER_Connection *mgr = cls;
202 GNUNET_CLIENT_MANAGER_disconnect (mgr, GNUNET_NO,
203 mgr->disconnect_cb, mgr->disconnect_cls);
204}
205
206
188/** 207/**
189 * Transmit next message to service. 208 * Transmit next message to service.
190 * 209 *
@@ -221,7 +240,14 @@ send_next_message (void *cls, size_t buf_size, void *buf)
221 GNUNET_free (mqi); 240 GNUNET_free (mqi);
222 241
223 if (NULL != mgr->tmit_head) 242 if (NULL != mgr->tmit_head)
243 {
224 transmit_next (mgr); 244 transmit_next (mgr);
245 }
246 else if (GNUNET_YES == mgr->is_disconnecting)
247 {
248 GNUNET_SCHEDULER_add_now (&schedule_disconnect, mgr);
249 return size;
250 }
225 251
226 if (GNUNET_NO == mgr->in_receive) 252 if (GNUNET_NO == mgr->in_receive)
227 { 253 {
@@ -247,8 +273,9 @@ transmit_next (struct GNUNET_CLIENT_MANAGER_Connection *mgr)
247 273
248 if (NULL == mgr->tmit_head) 274 if (NULL == mgr->tmit_head)
249 { 275 {
250 if (GNUNET_YES == mgr->disconnecting) 276 if (GNUNET_YES == mgr->is_disconnecting)
251 GNUNET_CLIENT_MANAGER_disconnect (mgr, GNUNET_NO); 277 GNUNET_CLIENT_MANAGER_disconnect (mgr, GNUNET_NO,
278 mgr->disconnect_cb, mgr->disconnect_cls);
252 return; 279 return;
253 } 280 }
254 281
@@ -269,7 +296,7 @@ transmit_next (struct GNUNET_CLIENT_MANAGER_Connection *mgr)
269 * @param tc Scheduler context. 296 * @param tc Scheduler context.
270 */ 297 */
271static void 298static void
272reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 299schedule_reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
273{ 300{
274 struct GNUNET_CLIENT_MANAGER_Connection *mgr = cls; 301 struct GNUNET_CLIENT_MANAGER_Connection *mgr = cls;
275 mgr->reconnect_task = GNUNET_SCHEDULER_NO_TASK; 302 mgr->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
@@ -305,7 +332,7 @@ GNUNET_CLIENT_MANAGER_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
305 mgr->service_name = service_name; 332 mgr->service_name = service_name;
306 mgr->handlers = handlers; 333 mgr->handlers = handlers;
307 mgr->reconnect_delay = GNUNET_TIME_UNIT_ZERO; 334 mgr->reconnect_delay = GNUNET_TIME_UNIT_ZERO;
308 mgr->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, mgr); 335 mgr->reconnect_task = GNUNET_SCHEDULER_add_now (&schedule_reconnect, mgr);
309 return mgr; 336 return mgr;
310} 337}
311 338
@@ -315,17 +342,25 @@ GNUNET_CLIENT_MANAGER_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
315 * 342 *
316 * @param mgr Client manager connection. 343 * @param mgr Client manager connection.
317 * @param transmit_queue Transmit pending messages in queue before disconnecting. 344 * @param transmit_queue Transmit pending messages in queue before disconnecting.
345 * @param disconnect_cb Function called after disconnected from the service.
346 * @param disconnect_cls Closure for @a disconnect_cb.
318 */ 347 */
319void 348void
320GNUNET_CLIENT_MANAGER_disconnect (struct GNUNET_CLIENT_MANAGER_Connection *mgr, 349GNUNET_CLIENT_MANAGER_disconnect (struct GNUNET_CLIENT_MANAGER_Connection *mgr,
321 int transmit_queue) 350 int transmit_queue,
351 GNUNET_ContinuationCallback disconnect_cb,
352 void *disconnect_cls)
322{ 353{
354 LOG (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting (%d)\n", transmit_queue);
355 mgr->disconnect_cb = disconnect_cb;
356 mgr->disconnect_cls = disconnect_cls;
323 if (NULL != mgr->tmit_head) 357 if (NULL != mgr->tmit_head)
324 { 358 {
325 if (GNUNET_YES == transmit_queue) 359 if (GNUNET_YES == transmit_queue)
326 { 360 {
327 mgr->disconnecting = GNUNET_YES; 361 mgr->is_disconnecting = GNUNET_YES;
328 transmit_next (mgr); 362 transmit_next (mgr);
363 return;
329 } 364 }
330 else 365 else
331 { 366 {
@@ -350,7 +385,10 @@ GNUNET_CLIENT_MANAGER_disconnect (struct GNUNET_CLIENT_MANAGER_Connection *mgr,
350 GNUNET_CLIENT_disconnect (mgr->client); 385 GNUNET_CLIENT_disconnect (mgr->client);
351 mgr->client = NULL; 386 mgr->client = NULL;
352 } 387 }
388 if (NULL != mgr->disconnect_cb)
389 mgr->disconnect_cb (mgr->disconnect_cls);
353 GNUNET_free (mgr); 390 GNUNET_free (mgr);
391 LOG (GNUNET_ERROR_TYPE_DEBUG, "Disconnected.\n");
354} 392}
355 393
356 394
@@ -380,7 +418,7 @@ GNUNET_CLIENT_MANAGER_reconnect (struct GNUNET_CLIENT_MANAGER_Connection *mgr)
380 "Scheduling task to reconnect to service in %s.\n", 418 "Scheduling task to reconnect to service in %s.\n",
381 GNUNET_STRINGS_relative_time_to_string (mgr->reconnect_delay, GNUNET_YES)); 419 GNUNET_STRINGS_relative_time_to_string (mgr->reconnect_delay, GNUNET_YES));
382 mgr->reconnect_task = 420 mgr->reconnect_task =
383 GNUNET_SCHEDULER_add_delayed (mgr->reconnect_delay, &reconnect, mgr); 421 GNUNET_SCHEDULER_add_delayed (mgr->reconnect_delay, &schedule_reconnect, mgr);
384 mgr->reconnect_delay = GNUNET_TIME_STD_BACKOFF (mgr->reconnect_delay); 422 mgr->reconnect_delay = GNUNET_TIME_STD_BACKOFF (mgr->reconnect_delay);
385} 423}
386 424