diff options
author | Christian Grothoff <christian@grothoff.org> | 2013-05-29 08:19:14 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2013-05-29 08:19:14 +0000 |
commit | 1bdbb8bc0cec3650843daf5eb559ed46e9a69fd7 (patch) | |
tree | 95f01ee9c62b026c4c161a62d309f25b05acc5cc /src/chat | |
parent | 022002438e4047d235a688cfd9da7b63ab990103 (diff) | |
download | gnunet-1bdbb8bc0cec3650843daf5eb559ed46e9a69fd7.tar.gz gnunet-1bdbb8bc0cec3650843daf5eb559ed46e9a69fd7.zip |
-removing chat from build
Diffstat (limited to 'src/chat')
-rw-r--r-- | src/chat/Makefile.am | 137 | ||||
-rw-r--r-- | src/chat/chat.c | 822 | ||||
-rw-r--r-- | src/chat/chat.conf.in | 21 | ||||
-rw-r--r-- | src/chat/chat.h | 485 | ||||
-rw-r--r-- | src/chat/gnunet-chat.c | 750 | ||||
-rw-r--r-- | src/chat/gnunet-service-chat.c | 1713 | ||||
-rw-r--r-- | src/chat/test_chat.c | 556 | ||||
-rw-r--r-- | src/chat/test_chat_data.conf | 55 | ||||
-rw-r--r-- | src/chat/test_chat_peer1.conf | 92 | ||||
-rw-r--r-- | src/chat/test_chat_peer2.conf | 94 | ||||
-rw-r--r-- | src/chat/test_chat_peer3.conf | 93 | ||||
-rw-r--r-- | src/chat/test_chat_private.c | 640 |
12 files changed, 0 insertions, 5458 deletions
diff --git a/src/chat/Makefile.am b/src/chat/Makefile.am deleted file mode 100644 index a518bfd12..000000000 --- a/src/chat/Makefile.am +++ /dev/null | |||
@@ -1,137 +0,0 @@ | |||
1 | INCLUDES = -I$(top_srcdir)/src/include | ||
2 | |||
3 | pkgcfgdir= $(pkgdatadir)/config.d/ | ||
4 | |||
5 | libexecdir= $(pkglibdir)/libexec/ | ||
6 | |||
7 | pkgcfg_DATA = \ | ||
8 | chat.conf | ||
9 | |||
10 | if MINGW | ||
11 | WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols | ||
12 | endif | ||
13 | |||
14 | if USE_COVERAGE | ||
15 | AM_CFLAGS = -fprofile-arcs -ftest-coverage | ||
16 | endif | ||
17 | |||
18 | lib_LTLIBRARIES = libgnunetchat.la | ||
19 | |||
20 | libgnunetchat_la_SOURCES = \ | ||
21 | chat.c chat.h | ||
22 | |||
23 | libgnunetchat_la_LIBADD = \ | ||
24 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
25 | $(top_builddir)/src/fs/libgnunetfs.la | ||
26 | |||
27 | libgnunetchat_la_DEPENDENCIES = \ | ||
28 | $(top_builddir)/src/fs/libgnunetfs.la | ||
29 | |||
30 | libgnunetchat_la_LDFLAGS = \ | ||
31 | $(GN_LIB_LDFLAGS) $(WINFLAGS) \ | ||
32 | -version-info 0:0:0 | ||
33 | |||
34 | libexec_PROGRAMS = \ | ||
35 | gnunet-service-chat | ||
36 | |||
37 | bin_PROGRAMS = \ | ||
38 | gnunet-chat | ||
39 | |||
40 | gnunet_service_chat_SOURCES = \ | ||
41 | gnunet-service-chat.c | ||
42 | gnunet_service_chat_LDADD = \ | ||
43 | $(top_builddir)/src/core/libgnunetcore.la \ | ||
44 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
45 | $(GN_LIBINTL) | ||
46 | |||
47 | gnunet_chat_SOURCES = \ | ||
48 | gnunet-chat.c | ||
49 | gnunet_chat_LDADD = \ | ||
50 | $(top_builddir)/src/chat/libgnunetchat.la \ | ||
51 | $(top_builddir)/src/fs/libgnunetfs.la \ | ||
52 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
53 | $(GN_LIBINTL) | ||
54 | gnunet_chat_DEPENDENCIES = \ | ||
55 | libgnunetchat.la | ||
56 | |||
57 | check_PROGRAMS = \ | ||
58 | test_chat \ | ||
59 | test_chat_acknowledgement \ | ||
60 | test_chat_anonymous \ | ||
61 | test_chat_authentication \ | ||
62 | test_chat_p2p \ | ||
63 | test_chat_acknowledgement_p2p \ | ||
64 | test_chat_anonymous_p2p \ | ||
65 | test_chat_authentication_p2p \ | ||
66 | test_chat_private \ | ||
67 | test_chat_private_p2p | ||
68 | |||
69 | if ENABLE_TEST_RUN | ||
70 | TESTS = $(check_PROGRAMS) | ||
71 | endif | ||
72 | |||
73 | test_chat_SOURCES = \ | ||
74 | test_chat.c | ||
75 | test_chat_LDADD = \ | ||
76 | $(top_builddir)/src/chat/libgnunetchat.la \ | ||
77 | $(top_builddir)/src/util/libgnunetutil.la | ||
78 | |||
79 | test_chat_acknowledgement_SOURCES = \ | ||
80 | test_chat.c | ||
81 | test_chat_acknowledgement_LDADD = \ | ||
82 | $(top_builddir)/src/chat/libgnunetchat.la \ | ||
83 | $(top_builddir)/src/util/libgnunetutil.la | ||
84 | |||
85 | test_chat_anonymous_SOURCES = \ | ||
86 | test_chat.c | ||
87 | test_chat_anonymous_LDADD = \ | ||
88 | $(top_builddir)/src/chat/libgnunetchat.la \ | ||
89 | $(top_builddir)/src/util/libgnunetutil.la | ||
90 | |||
91 | test_chat_authentication_SOURCES = \ | ||
92 | test_chat.c | ||
93 | test_chat_authentication_LDADD = \ | ||
94 | $(top_builddir)/src/chat/libgnunetchat.la \ | ||
95 | $(top_builddir)/src/util/libgnunetutil.la | ||
96 | |||
97 | test_chat_p2p_SOURCES = \ | ||
98 | test_chat.c | ||
99 | test_chat_p2p_LDADD = \ | ||
100 | $(top_builddir)/src/chat/libgnunetchat.la \ | ||
101 | $(top_builddir)/src/util/libgnunetutil.la | ||
102 | |||
103 | test_chat_acknowledgement_p2p_SOURCES = \ | ||
104 | test_chat.c | ||
105 | test_chat_acknowledgement_p2p_LDADD = \ | ||
106 | $(top_builddir)/src/chat/libgnunetchat.la \ | ||
107 | $(top_builddir)/src/util/libgnunetutil.la | ||
108 | |||
109 | test_chat_anonymous_p2p_SOURCES = \ | ||
110 | test_chat.c | ||
111 | test_chat_anonymous_p2p_LDADD = \ | ||
112 | $(top_builddir)/src/chat/libgnunetchat.la \ | ||
113 | $(top_builddir)/src/util/libgnunetutil.la | ||
114 | |||
115 | test_chat_authentication_p2p_SOURCES = \ | ||
116 | test_chat.c | ||
117 | test_chat_authentication_p2p_LDADD = \ | ||
118 | $(top_builddir)/src/chat/libgnunetchat.la \ | ||
119 | $(top_builddir)/src/util/libgnunetutil.la | ||
120 | |||
121 | test_chat_private_SOURCES = \ | ||
122 | test_chat_private.c | ||
123 | test_chat_private_LDADD = \ | ||
124 | $(top_builddir)/src/chat/libgnunetchat.la \ | ||
125 | $(top_builddir)/src/util/libgnunetutil.la | ||
126 | |||
127 | test_chat_private_p2p_SOURCES = \ | ||
128 | test_chat_private.c | ||
129 | test_chat_private_p2p_LDADD = \ | ||
130 | $(top_builddir)/src/chat/libgnunetchat.la \ | ||
131 | $(top_builddir)/src/util/libgnunetutil.la | ||
132 | |||
133 | EXTRA_DIST = \ | ||
134 | test_chat_data.conf \ | ||
135 | test_chat_peer1.conf \ | ||
136 | test_chat_peer2.conf \ | ||
137 | test_chat_peer3.conf | ||
diff --git a/src/chat/chat.c b/src/chat/chat.c deleted file mode 100644 index 786babe34..000000000 --- a/src/chat/chat.c +++ /dev/null | |||
@@ -1,822 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2008, 2011 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file chat/chat.c | ||
23 | * @brief convenience API for sending and receiving chat messages | ||
24 | * @author Christian Grothoff | ||
25 | * @author Nathan Evans | ||
26 | * @author Vitaly Minko | ||
27 | */ | ||
28 | |||
29 | #include "platform.h" | ||
30 | #include "gnunet_constants.h" | ||
31 | #include "gnunet_protocols.h" | ||
32 | #include "gnunet_signatures.h" | ||
33 | #include "gnunet_fs_service.h" | ||
34 | #include "chat.h" | ||
35 | |||
36 | #define DEBUG_CHAT GNUNET_EXTRA_LOGGING | ||
37 | #define NICK_IDENTITY_PREFIX ".chat_identity_" | ||
38 | |||
39 | |||
40 | /** | ||
41 | * Handle for a chat room. | ||
42 | */ | ||
43 | struct GNUNET_CHAT_Room | ||
44 | { | ||
45 | struct GNUNET_CLIENT_Connection *client; | ||
46 | |||
47 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
48 | |||
49 | struct GNUNET_CONTAINER_MetaData *member_info; | ||
50 | |||
51 | char *room_name; | ||
52 | |||
53 | struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key; | ||
54 | |||
55 | struct MemberList *members; | ||
56 | |||
57 | int is_joined; | ||
58 | |||
59 | GNUNET_CHAT_JoinCallback join_callback; | ||
60 | |||
61 | void *join_callback_cls; | ||
62 | |||
63 | GNUNET_CHAT_MessageCallback message_callback; | ||
64 | |||
65 | void *message_callback_cls; | ||
66 | |||
67 | GNUNET_CHAT_MemberListCallback member_list_callback; | ||
68 | |||
69 | void *member_list_callback_cls; | ||
70 | |||
71 | GNUNET_CHAT_MessageConfirmation confirmation_callback; | ||
72 | |||
73 | void *confirmation_cls; | ||
74 | |||
75 | uint32_t sequence_number; | ||
76 | |||
77 | uint32_t msg_options; | ||
78 | |||
79 | }; | ||
80 | |||
81 | /** | ||
82 | * Linked list of members in the chat room. | ||
83 | */ | ||
84 | struct MemberList | ||
85 | { | ||
86 | struct MemberList *next; | ||
87 | |||
88 | /** | ||
89 | * Description of the member. | ||
90 | */ | ||
91 | struct GNUNET_CONTAINER_MetaData *meta; | ||
92 | |||
93 | /** | ||
94 | * Member ID (pseudonym). | ||
95 | */ | ||
96 | struct GNUNET_HashCode id; | ||
97 | |||
98 | }; | ||
99 | |||
100 | /** | ||
101 | * Context for transmitting a send-message request. | ||
102 | */ | ||
103 | struct GNUNET_CHAT_SendMessageContext | ||
104 | { | ||
105 | /** | ||
106 | * Handle for the chat room. | ||
107 | */ | ||
108 | struct GNUNET_CHAT_Room *chat_room; | ||
109 | |||
110 | /** | ||
111 | * Message that we're sending. | ||
112 | */ | ||
113 | char *message; | ||
114 | |||
115 | /** | ||
116 | * Options for the message. | ||
117 | */ | ||
118 | enum GNUNET_CHAT_MsgOptions options; | ||
119 | |||
120 | /** | ||
121 | * Receiver of the message. NULL to send to everyone in the room. | ||
122 | */ | ||
123 | const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *receiver; | ||
124 | |||
125 | /** | ||
126 | * Sequence id of the message. | ||
127 | */ | ||
128 | uint32_t sequence_number; | ||
129 | |||
130 | }; | ||
131 | |||
132 | /** | ||
133 | * Context for transmitting a confirmation receipt. | ||
134 | */ | ||
135 | struct GNUNET_CHAT_SendReceiptContext | ||
136 | { | ||
137 | /** | ||
138 | * Handle for the chat room. | ||
139 | */ | ||
140 | struct GNUNET_CHAT_Room *chat_room; | ||
141 | |||
142 | /** | ||
143 | * The original message that we're going to acknowledge. | ||
144 | */ | ||
145 | struct ReceiveNotificationMessage *received_msg; | ||
146 | |||
147 | }; | ||
148 | |||
149 | /** | ||
150 | * Ask client to send a join request. | ||
151 | */ | ||
152 | static int | ||
153 | rejoin_room (struct GNUNET_CHAT_Room *chat_room); | ||
154 | |||
155 | |||
156 | /** | ||
157 | * Transmit a confirmation receipt to the chat service. | ||
158 | * | ||
159 | * @param cls closure, pointer to the 'struct GNUNET_CHAT_SendReceiptContext' | ||
160 | * @param size number of bytes available in buf | ||
161 | * @param buf where the callee should write the message | ||
162 | * @return number of bytes written to buf | ||
163 | */ | ||
164 | static size_t | ||
165 | transmit_acknowledge_request (void *cls, size_t size, void *buf) | ||
166 | { | ||
167 | struct GNUNET_CHAT_SendReceiptContext *src = cls; | ||
168 | struct ConfirmationReceiptMessage *receipt; | ||
169 | struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub_key; | ||
170 | uint16_t msg_len; | ||
171 | size_t msg_size; | ||
172 | |||
173 | if (NULL == buf) | ||
174 | { | ||
175 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
176 | _("Could not transmit confirmation receipt\n")); | ||
177 | return 0; | ||
178 | } | ||
179 | #if DEBUG_CHAT | ||
180 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
181 | "Transmitting confirmation receipt to the service\n"); | ||
182 | #endif | ||
183 | msg_size = sizeof (struct ConfirmationReceiptMessage); | ||
184 | GNUNET_assert (size >= msg_size); | ||
185 | receipt = buf; | ||
186 | receipt->header.size = htons (msg_size); | ||
187 | receipt->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_RECEIPT); | ||
188 | receipt->reserved = htonl (0); | ||
189 | receipt->sequence_number = src->received_msg->sequence_number; | ||
190 | receipt->reserved2 = htonl (0); | ||
191 | receipt->timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ()); | ||
192 | GNUNET_CRYPTO_rsa_key_get_public (src->chat_room->my_private_key, &pub_key); | ||
193 | GNUNET_CRYPTO_hash (&pub_key, | ||
194 | sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), | ||
195 | &receipt->target); | ||
196 | receipt->author = src->received_msg->sender; | ||
197 | receipt->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CHAT_RECEIPT); | ||
198 | receipt->purpose.size = | ||
199 | htonl (msg_size - sizeof (struct GNUNET_MessageHeader) - | ||
200 | sizeof (uint32_t) - sizeof (struct GNUNET_CRYPTO_RsaSignature)); | ||
201 | msg_len = | ||
202 | ntohs (src->received_msg->header.size) - | ||
203 | sizeof (struct ReceiveNotificationMessage); | ||
204 | GNUNET_CRYPTO_hash (&src->received_msg[1], msg_len, &receipt->content); | ||
205 | GNUNET_assert (GNUNET_OK == | ||
206 | GNUNET_CRYPTO_rsa_sign (src->chat_room->my_private_key, | ||
207 | &receipt->purpose, | ||
208 | &receipt->signature)); | ||
209 | GNUNET_free (src->received_msg); | ||
210 | GNUNET_free (src); | ||
211 | return msg_size; | ||
212 | } | ||
213 | |||
214 | |||
215 | /** | ||
216 | * Handles messages received from the service. Calls the proper client | ||
217 | * callback. | ||
218 | */ | ||
219 | static void | ||
220 | process_result (struct GNUNET_CHAT_Room *room, | ||
221 | const struct GNUNET_MessageHeader *reply) | ||
222 | { | ||
223 | struct LeaveNotificationMessage *leave_msg; | ||
224 | struct JoinNotificationMessage *join_msg; | ||
225 | struct ReceiveNotificationMessage *received_msg; | ||
226 | struct ConfirmationReceiptMessage *receipt; | ||
227 | struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; | ||
228 | struct GNUNET_HashCode id; | ||
229 | const struct GNUNET_HashCode *sender; | ||
230 | struct GNUNET_CONTAINER_MetaData *meta; | ||
231 | struct GNUNET_CHAT_SendReceiptContext *src; | ||
232 | struct MemberList *pos; | ||
233 | struct MemberList *prev; | ||
234 | struct GNUNET_CRYPTO_AesSessionKey key; | ||
235 | char decrypted_msg[MAX_MESSAGE_LENGTH]; | ||
236 | uint16_t size; | ||
237 | uint16_t meta_len; | ||
238 | uint16_t msg_len; | ||
239 | char *message_content; | ||
240 | |||
241 | size = ntohs (reply->size); | ||
242 | switch (ntohs (reply->type)) | ||
243 | { | ||
244 | case GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION: | ||
245 | #if DEBUG_CHAT | ||
246 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a join notification\n"); | ||
247 | #endif | ||
248 | if (size < sizeof (struct JoinNotificationMessage)) | ||
249 | { | ||
250 | GNUNET_break (0); | ||
251 | return; | ||
252 | } | ||
253 | join_msg = (struct JoinNotificationMessage *) reply; | ||
254 | meta_len = size - sizeof (struct JoinNotificationMessage); | ||
255 | meta = | ||
256 | GNUNET_CONTAINER_meta_data_deserialize ((const char *) &join_msg[1], | ||
257 | meta_len); | ||
258 | if (NULL == meta) | ||
259 | { | ||
260 | GNUNET_break (0); | ||
261 | return; | ||
262 | } | ||
263 | pos = GNUNET_malloc (sizeof (struct MemberList)); | ||
264 | pos->meta = meta; | ||
265 | GNUNET_CRYPTO_hash (&join_msg->public_key, | ||
266 | sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), | ||
267 | &pos->id); | ||
268 | GNUNET_FS_pseudonym_add (room->cfg, &pos->id, meta); | ||
269 | pos->next = room->members; | ||
270 | room->members = pos; | ||
271 | if (GNUNET_NO == room->is_joined) | ||
272 | { | ||
273 | GNUNET_CRYPTO_rsa_key_get_public (room->my_private_key, &pkey); | ||
274 | if (0 == | ||
275 | memcmp (&join_msg->public_key, &pkey, | ||
276 | sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded))) | ||
277 | { | ||
278 | room->join_callback (room->join_callback_cls); | ||
279 | room->is_joined = GNUNET_YES; | ||
280 | } | ||
281 | else | ||
282 | { | ||
283 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
284 | _("The current user must be the the first one joined\n")); | ||
285 | GNUNET_break (0); | ||
286 | return; | ||
287 | } | ||
288 | } | ||
289 | else | ||
290 | room->member_list_callback (room->member_list_callback_cls, meta, | ||
291 | &join_msg->public_key, | ||
292 | ntohl (join_msg->msg_options)); | ||
293 | break; | ||
294 | case GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION: | ||
295 | #if DEBUG_CHAT | ||
296 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a leave notification\n"); | ||
297 | #endif | ||
298 | if (size < sizeof (struct LeaveNotificationMessage)) | ||
299 | { | ||
300 | GNUNET_break (0); | ||
301 | return; | ||
302 | } | ||
303 | leave_msg = (struct LeaveNotificationMessage *) reply; | ||
304 | room->member_list_callback (room->member_list_callback_cls, NULL, | ||
305 | &leave_msg->user, GNUNET_CHAT_MSG_OPTION_NONE); | ||
306 | GNUNET_CRYPTO_hash (&leave_msg->user, | ||
307 | sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), | ||
308 | &id); | ||
309 | prev = NULL; | ||
310 | pos = room->members; | ||
311 | while ((NULL != pos) && | ||
312 | (0 != memcmp (&pos->id, &id, sizeof (struct GNUNET_HashCode)))) | ||
313 | { | ||
314 | prev = pos; | ||
315 | pos = pos->next; | ||
316 | } | ||
317 | GNUNET_assert (NULL != pos); | ||
318 | if (NULL == prev) | ||
319 | room->members = pos->next; | ||
320 | else | ||
321 | prev->next = pos->next; | ||
322 | GNUNET_CONTAINER_meta_data_destroy (pos->meta); | ||
323 | GNUNET_free (pos); | ||
324 | break; | ||
325 | case GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION: | ||
326 | #if DEBUG_CHAT | ||
327 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a message notification\n"); | ||
328 | #endif | ||
329 | if (size <= sizeof (struct ReceiveNotificationMessage)) | ||
330 | { | ||
331 | GNUNET_break (0); | ||
332 | return; | ||
333 | } | ||
334 | received_msg = (struct ReceiveNotificationMessage *) reply; | ||
335 | if (0 != (ntohl (received_msg->msg_options) & GNUNET_CHAT_MSG_ACKNOWLEDGED)) | ||
336 | { | ||
337 | src = GNUNET_malloc (sizeof (struct GNUNET_CHAT_SendReceiptContext)); | ||
338 | src->chat_room = room; | ||
339 | src->received_msg = GNUNET_memdup (received_msg, size); | ||
340 | GNUNET_CLIENT_notify_transmit_ready (room->client, | ||
341 | sizeof (struct | ||
342 | ConfirmationReceiptMessage), | ||
343 | GNUNET_CONSTANTS_SERVICE_TIMEOUT, | ||
344 | GNUNET_YES, | ||
345 | &transmit_acknowledge_request, src); | ||
346 | } | ||
347 | msg_len = size - sizeof (struct ReceiveNotificationMessage); | ||
348 | if (0 != (ntohl (received_msg->msg_options) & GNUNET_CHAT_MSG_PRIVATE)) | ||
349 | { | ||
350 | if (-1 == | ||
351 | GNUNET_CRYPTO_rsa_decrypt (room->my_private_key, | ||
352 | &received_msg->encrypted_key, &key, | ||
353 | sizeof (struct | ||
354 | GNUNET_CRYPTO_AesSessionKey))) | ||
355 | { | ||
356 | GNUNET_break (0); | ||
357 | return; | ||
358 | } | ||
359 | msg_len = | ||
360 | GNUNET_CRYPTO_aes_decrypt (&received_msg[1], msg_len, &key, | ||
361 | (const struct | ||
362 | GNUNET_CRYPTO_AesInitializationVector *) | ||
363 | INITVALUE, decrypted_msg); | ||
364 | message_content = decrypted_msg; | ||
365 | } | ||
366 | else | ||
367 | { | ||
368 | message_content = GNUNET_malloc (msg_len + 1); | ||
369 | memcpy (message_content, &received_msg[1], msg_len); | ||
370 | } | ||
371 | message_content[msg_len] = '\0'; | ||
372 | if (0 != (ntohl (received_msg->msg_options) & GNUNET_CHAT_MSG_ANONYMOUS)) | ||
373 | { | ||
374 | sender = NULL; | ||
375 | meta = NULL; | ||
376 | } | ||
377 | else | ||
378 | { | ||
379 | pos = room->members; | ||
380 | while ((NULL != pos) && | ||
381 | (0 != | ||
382 | memcmp (&pos->id, &received_msg->sender, | ||
383 | sizeof (struct GNUNET_HashCode)))) | ||
384 | pos = pos->next; | ||
385 | GNUNET_assert (NULL != pos); | ||
386 | sender = &received_msg->sender; | ||
387 | meta = pos->meta; | ||
388 | } | ||
389 | room->message_callback (room->message_callback_cls, room, sender, meta, | ||
390 | message_content, | ||
391 | GNUNET_TIME_absolute_ntoh (received_msg->timestamp), | ||
392 | ntohl (received_msg->msg_options)); | ||
393 | if (message_content != decrypted_msg) | ||
394 | GNUNET_free (message_content); | ||
395 | break; | ||
396 | case GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION: | ||
397 | #if DEBUG_CHAT | ||
398 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a confirmation receipt\n"); | ||
399 | #endif | ||
400 | if (size < sizeof (struct ConfirmationReceiptMessage)) | ||
401 | { | ||
402 | GNUNET_break (0); | ||
403 | return; | ||
404 | } | ||
405 | receipt = (struct ConfirmationReceiptMessage *) reply; | ||
406 | if (NULL != room->confirmation_callback) | ||
407 | room->confirmation_callback (room->confirmation_cls, room, | ||
408 | ntohl (receipt->sequence_number), | ||
409 | GNUNET_TIME_absolute_ntoh | ||
410 | (receipt->timestamp), &receipt->target); | ||
411 | break; | ||
412 | default: | ||
413 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unknown message type: '%u'\n"), | ||
414 | ntohs (reply->type)); | ||
415 | GNUNET_break_op (0); | ||
416 | break; | ||
417 | } | ||
418 | } | ||
419 | |||
420 | |||
421 | /** | ||
422 | * Listen for incoming messages on this chat room. Also, support servers going | ||
423 | * away/coming back (i.e. rejoin chat room to keep server state up to date). | ||
424 | * | ||
425 | * @param cls closure, pointer to the 'struct GNUNET_CHAT_Room' | ||
426 | * @param msg message received, NULL on timeout or fatal error | ||
427 | */ | ||
428 | static void | ||
429 | receive_results (void *cls, const struct GNUNET_MessageHeader *msg) | ||
430 | { | ||
431 | struct GNUNET_CHAT_Room *chat_room = cls; | ||
432 | |||
433 | #if DEBUG_CHAT | ||
434 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a message from the service\n"); | ||
435 | #endif | ||
436 | if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & GNUNET_SCHEDULER_get_reason ())) | ||
437 | return; | ||
438 | if (NULL == msg) | ||
439 | { | ||
440 | GNUNET_break (0); | ||
441 | rejoin_room (chat_room); | ||
442 | return; | ||
443 | } | ||
444 | process_result (chat_room, msg); | ||
445 | if (NULL == chat_room->client) | ||
446 | return; /* fatal error */ | ||
447 | /* continue receiving */ | ||
448 | GNUNET_CLIENT_receive (chat_room->client, &receive_results, chat_room, | ||
449 | GNUNET_TIME_UNIT_FOREVER_REL); | ||
450 | } | ||
451 | |||
452 | |||
453 | /** | ||
454 | * Read existing private key from file or create a new one if it does not exist | ||
455 | * yet. | ||
456 | * Returns the private key on success, NULL on error. | ||
457 | */ | ||
458 | static struct GNUNET_CRYPTO_RsaPrivateKey * | ||
459 | init_private_key (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
460 | const char *nick_name) | ||
461 | { | ||
462 | char *home; | ||
463 | char *keyfile; | ||
464 | struct GNUNET_CRYPTO_RsaPrivateKey *privKey; | ||
465 | |||
466 | #if DEBUG_CHAT | ||
467 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Initializing private key\n"); | ||
468 | #endif | ||
469 | if (GNUNET_OK != | ||
470 | GNUNET_CONFIGURATION_get_value_filename (cfg, "chat", "HOME", &home)) | ||
471 | { | ||
472 | GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, | ||
473 | "chat", "HOME"); | ||
474 | return NULL; | ||
475 | } | ||
476 | GNUNET_DISK_directory_create (home); | ||
477 | if (GNUNET_YES != GNUNET_DISK_directory_test (home, GNUNET_YES)) | ||
478 | { | ||
479 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
480 | _("Failed to access chat home directory `%s'\n"), home); | ||
481 | GNUNET_free (home); | ||
482 | return NULL; | ||
483 | } | ||
484 | /* read or create private key */ | ||
485 | keyfile = | ||
486 | GNUNET_malloc (strlen (home) + strlen (NICK_IDENTITY_PREFIX) + | ||
487 | strlen (nick_name) + 2); | ||
488 | strcpy (keyfile, home); | ||
489 | GNUNET_free (home); | ||
490 | if (keyfile[strlen (keyfile) - 1] != DIR_SEPARATOR) | ||
491 | strcat (keyfile, DIR_SEPARATOR_STR); | ||
492 | strcat (keyfile, NICK_IDENTITY_PREFIX); | ||
493 | strcat (keyfile, nick_name); | ||
494 | privKey = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); | ||
495 | if (NULL == privKey) | ||
496 | { | ||
497 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
498 | _("Failed to create/open key in file `%s'\n"), keyfile); | ||
499 | } | ||
500 | GNUNET_free (keyfile); | ||
501 | return privKey; | ||
502 | } | ||
503 | |||
504 | |||
505 | /** | ||
506 | * Transmit a join request to the chat service. | ||
507 | * | ||
508 | * @param cls closure, pointer to the 'struct GNUNET_CHAT_Room' | ||
509 | * @param size number of bytes available in buf | ||
510 | * @param buf where the callee should write the message | ||
511 | * @return number of bytes written to buf | ||
512 | */ | ||
513 | static size_t | ||
514 | transmit_join_request (void *cls, size_t size, void *buf) | ||
515 | { | ||
516 | struct GNUNET_CHAT_Room *chat_room = cls; | ||
517 | struct JoinRequestMessage *join_msg; | ||
518 | char *room; | ||
519 | char *meta; | ||
520 | size_t room_len; | ||
521 | ssize_t meta_len; | ||
522 | size_t size_of_join; | ||
523 | |||
524 | if (NULL == buf) | ||
525 | { | ||
526 | #if DEBUG_CHAT | ||
527 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
528 | "Could not transmit join request, retrying...\n"); | ||
529 | #endif | ||
530 | rejoin_room (chat_room); | ||
531 | return 0; | ||
532 | } | ||
533 | #if DEBUG_CHAT | ||
534 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
535 | "Transmitting join request to the service\n"); | ||
536 | #endif | ||
537 | room_len = strlen (chat_room->room_name); | ||
538 | meta_len = | ||
539 | GNUNET_CONTAINER_meta_data_get_serialized_size (chat_room->member_info); | ||
540 | size_of_join = sizeof (struct JoinRequestMessage) + meta_len + room_len; | ||
541 | GNUNET_assert (size >= size_of_join); | ||
542 | join_msg = buf; | ||
543 | join_msg->header.size = htons (size); | ||
544 | join_msg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_REQUEST); | ||
545 | join_msg->msg_options = htonl (chat_room->msg_options); | ||
546 | join_msg->room_name_len = htons (room_len); | ||
547 | join_msg->reserved = htons (0); | ||
548 | join_msg->reserved2 = htonl (0); | ||
549 | GNUNET_CRYPTO_rsa_key_get_public (chat_room->my_private_key, | ||
550 | &join_msg->public_key); | ||
551 | room = (char *) &join_msg[1]; | ||
552 | memcpy (room, chat_room->room_name, room_len); | ||
553 | meta = &room[room_len]; | ||
554 | if (GNUNET_SYSERR == | ||
555 | GNUNET_CONTAINER_meta_data_serialize (chat_room->member_info, &meta, | ||
556 | meta_len, | ||
557 | GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL)) | ||
558 | { | ||
559 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not serialize metadata\n")); | ||
560 | return 0; | ||
561 | } | ||
562 | GNUNET_CLIENT_receive (chat_room->client, &receive_results, chat_room, | ||
563 | GNUNET_TIME_UNIT_FOREVER_REL); | ||
564 | return size_of_join; | ||
565 | } | ||
566 | |||
567 | |||
568 | /** | ||
569 | * Ask to send a join request. | ||
570 | */ | ||
571 | static int | ||
572 | rejoin_room (struct GNUNET_CHAT_Room *chat_room) | ||
573 | { | ||
574 | size_t size_of_join; | ||
575 | |||
576 | size_of_join = | ||
577 | sizeof (struct JoinRequestMessage) + | ||
578 | GNUNET_CONTAINER_meta_data_get_serialized_size (chat_room->member_info) + | ||
579 | strlen (chat_room->room_name); | ||
580 | if (NULL == | ||
581 | GNUNET_CLIENT_notify_transmit_ready (chat_room->client, size_of_join, | ||
582 | GNUNET_CONSTANTS_SERVICE_TIMEOUT, | ||
583 | GNUNET_YES, &transmit_join_request, | ||
584 | chat_room)) | ||
585 | return GNUNET_SYSERR; | ||
586 | return GNUNET_OK; | ||
587 | } | ||
588 | |||
589 | |||
590 | /** | ||
591 | * Leave a chat room. | ||
592 | */ | ||
593 | void | ||
594 | GNUNET_CHAT_leave_room (struct GNUNET_CHAT_Room *chat_room) | ||
595 | { | ||
596 | struct MemberList *pos; | ||
597 | |||
598 | #if DEBUG_CHAT | ||
599 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Leaving the room '%s'\n", | ||
600 | chat_room->room_name); | ||
601 | #endif | ||
602 | GNUNET_CLIENT_disconnect (chat_room->client); | ||
603 | GNUNET_free (chat_room->room_name); | ||
604 | GNUNET_CONTAINER_meta_data_destroy (chat_room->member_info); | ||
605 | GNUNET_CRYPTO_rsa_key_free (chat_room->my_private_key); | ||
606 | while (NULL != chat_room->members) | ||
607 | { | ||
608 | pos = chat_room->members; | ||
609 | chat_room->members = pos->next; | ||
610 | GNUNET_CONTAINER_meta_data_destroy (pos->meta); | ||
611 | GNUNET_free (pos); | ||
612 | } | ||
613 | GNUNET_free (chat_room); | ||
614 | } | ||
615 | |||
616 | |||
617 | /** | ||
618 | * Join a chat room. | ||
619 | * | ||
620 | * @param cfg configuration | ||
621 | * @param nick_name nickname of the user joining (used to | ||
622 | * determine which public key to use); | ||
623 | * the nickname should probably also | ||
624 | * be used in the member_info (as "EXTRACTOR_TITLE") | ||
625 | * @param member_info information about the joining member | ||
626 | * @param room_name name of the room | ||
627 | * @param msg_options message options of the joining user | ||
628 | * @param joinCallback function to call on successful join | ||
629 | * @param join_cls closure for joinCallback | ||
630 | * @param messageCallback which function to call if a message has | ||
631 | * been received? | ||
632 | * @param message_cls argument to callback | ||
633 | * @param memberCallback which function to call for join/leave notifications | ||
634 | * @param member_cls argument to callback | ||
635 | * @param confirmationCallback which function to call for confirmations (maybe NULL) | ||
636 | * @param confirmation_cls argument to callback | ||
637 | * @param me member ID (pseudonym) | ||
638 | * @return NULL on error | ||
639 | */ | ||
640 | struct GNUNET_CHAT_Room * | ||
641 | GNUNET_CHAT_join_room (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
642 | const char *nick_name, | ||
643 | struct GNUNET_CONTAINER_MetaData *member_info, | ||
644 | const char *room_name, | ||
645 | enum GNUNET_CHAT_MsgOptions msg_options, | ||
646 | GNUNET_CHAT_JoinCallback joinCallback, void *join_cls, | ||
647 | GNUNET_CHAT_MessageCallback messageCallback, | ||
648 | void *message_cls, | ||
649 | GNUNET_CHAT_MemberListCallback memberCallback, | ||
650 | void *member_cls, | ||
651 | GNUNET_CHAT_MessageConfirmation confirmationCallback, | ||
652 | void *confirmation_cls, struct GNUNET_HashCode * me) | ||
653 | { | ||
654 | struct GNUNET_CHAT_Room *chat_room; | ||
655 | struct GNUNET_CRYPTO_RsaPrivateKey *priv_key; | ||
656 | struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub_key; | ||
657 | struct GNUNET_CLIENT_Connection *client; | ||
658 | |||
659 | #if DEBUG_CHAT | ||
660 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Joining the room '%s'\n", room_name); | ||
661 | #endif | ||
662 | priv_key = init_private_key (cfg, nick_name); | ||
663 | if (NULL == priv_key) | ||
664 | return NULL; | ||
665 | GNUNET_CRYPTO_rsa_key_get_public (priv_key, &pub_key); | ||
666 | GNUNET_CRYPTO_hash (&pub_key, | ||
667 | sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), | ||
668 | me); | ||
669 | GNUNET_FS_pseudonym_add (cfg, me, member_info); | ||
670 | client = GNUNET_CLIENT_connect ("chat", cfg); | ||
671 | if (NULL == client) | ||
672 | { | ||
673 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
674 | _("Failed to connect to the chat service\n")); | ||
675 | return NULL; | ||
676 | } | ||
677 | if (NULL == joinCallback) | ||
678 | { | ||
679 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
680 | _("Undefined mandatory parameter: joinCallback\n")); | ||
681 | return NULL; | ||
682 | } | ||
683 | if (NULL == messageCallback) | ||
684 | { | ||
685 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
686 | _("Undefined mandatory parameter: messageCallback\n")); | ||
687 | return NULL; | ||
688 | } | ||
689 | if (NULL == memberCallback) | ||
690 | { | ||
691 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
692 | _("Undefined mandatory parameter: memberCallback\n")); | ||
693 | return NULL; | ||
694 | } | ||
695 | chat_room = GNUNET_malloc (sizeof (struct GNUNET_CHAT_Room)); | ||
696 | chat_room->msg_options = msg_options; | ||
697 | chat_room->room_name = GNUNET_strdup (room_name); | ||
698 | chat_room->member_info = GNUNET_CONTAINER_meta_data_duplicate (member_info); | ||
699 | chat_room->my_private_key = priv_key; | ||
700 | chat_room->is_joined = GNUNET_NO; | ||
701 | chat_room->join_callback = joinCallback; | ||
702 | chat_room->join_callback_cls = join_cls; | ||
703 | chat_room->message_callback = messageCallback; | ||
704 | chat_room->message_callback_cls = message_cls; | ||
705 | chat_room->member_list_callback = memberCallback; | ||
706 | chat_room->member_list_callback_cls = member_cls; | ||
707 | chat_room->confirmation_callback = confirmationCallback; | ||
708 | chat_room->confirmation_cls = confirmation_cls; | ||
709 | chat_room->cfg = cfg; | ||
710 | chat_room->client = client; | ||
711 | chat_room->members = NULL; | ||
712 | if (GNUNET_SYSERR == rejoin_room (chat_room)) | ||
713 | { | ||
714 | GNUNET_CHAT_leave_room (chat_room); | ||
715 | return NULL; | ||
716 | } | ||
717 | return chat_room; | ||
718 | } | ||
719 | |||
720 | |||
721 | /** | ||
722 | * Transmit a send-message request to the chat service. | ||
723 | * | ||
724 | * @param cls closure, pointer to the 'struct GNUNET_CHAT_SendMessageContext' | ||
725 | * @param size number of bytes available in buf | ||
726 | * @param buf where the callee should write the message | ||
727 | * @return number of bytes written to buf | ||
728 | */ | ||
729 | static size_t | ||
730 | transmit_send_request (void *cls, size_t size, void *buf) | ||
731 | { | ||
732 | struct GNUNET_CHAT_SendMessageContext *smc = cls; | ||
733 | struct TransmitRequestMessage *msg_to_send; | ||
734 | size_t msg_size; | ||
735 | |||
736 | if (NULL == buf) | ||
737 | { | ||
738 | #if DEBUG_CHAT | ||
739 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Could not transmit a chat message\n"); | ||
740 | #endif | ||
741 | return 0; | ||
742 | } | ||
743 | #if DEBUG_CHAT | ||
744 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
745 | "Transmitting a chat message to the service\n"); | ||
746 | #endif | ||
747 | msg_size = strlen (smc->message) + sizeof (struct TransmitRequestMessage); | ||
748 | GNUNET_assert (size >= msg_size); | ||
749 | msg_to_send = buf; | ||
750 | msg_to_send->header.size = htons (msg_size); | ||
751 | msg_to_send->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_TRANSMIT_REQUEST); | ||
752 | msg_to_send->msg_options = htonl (smc->options); | ||
753 | msg_to_send->sequence_number = htonl (smc->sequence_number); | ||
754 | msg_to_send->timestamp = | ||
755 | GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ()); | ||
756 | msg_to_send->reserved = htonl (0); | ||
757 | if (NULL == smc->receiver) | ||
758 | memset (&msg_to_send->target, 0, sizeof (struct GNUNET_HashCode)); | ||
759 | else | ||
760 | GNUNET_CRYPTO_hash (smc->receiver, | ||
761 | sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), | ||
762 | &msg_to_send->target); | ||
763 | memcpy (&msg_to_send[1], smc->message, strlen (smc->message)); | ||
764 | /** | ||
765 | * Client don't encode private messages since public keys of other members are | ||
766 | * stored on the service side. | ||
767 | */ | ||
768 | if (smc->options & GNUNET_CHAT_MSG_AUTHENTICATED) | ||
769 | { | ||
770 | msg_to_send->purpose.purpose = | ||
771 | htonl (GNUNET_SIGNATURE_PURPOSE_CHAT_MESSAGE); | ||
772 | msg_to_send->purpose.size = | ||
773 | htonl (msg_size - sizeof (struct GNUNET_MessageHeader) - | ||
774 | sizeof (struct GNUNET_CRYPTO_RsaSignature)); | ||
775 | GNUNET_assert (GNUNET_OK == | ||
776 | GNUNET_CRYPTO_rsa_sign (smc->chat_room->my_private_key, | ||
777 | &msg_to_send->purpose, | ||
778 | &msg_to_send->signature)); | ||
779 | } | ||
780 | GNUNET_free (smc->message); | ||
781 | GNUNET_free (smc); | ||
782 | return msg_size; | ||
783 | } | ||
784 | |||
785 | |||
786 | /** | ||
787 | * Send a message. | ||
788 | * | ||
789 | * @param room handle for the chat room | ||
790 | * @param message message to be sent | ||
791 | * @param options options for the message | ||
792 | * @param receiver use NULL to send to everyone in the room | ||
793 | * @param sequence_number where to write the sequence id of the message | ||
794 | */ | ||
795 | void | ||
796 | GNUNET_CHAT_send_message (struct GNUNET_CHAT_Room *room, const char *message, | ||
797 | enum GNUNET_CHAT_MsgOptions options, | ||
798 | const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded | ||
799 | *receiver, uint32_t * sequence_number) | ||
800 | { | ||
801 | size_t msg_size; | ||
802 | struct GNUNET_CHAT_SendMessageContext *smc; | ||
803 | |||
804 | #if DEBUG_CHAT | ||
805 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending a message\n"); | ||
806 | #endif | ||
807 | room->sequence_number++; | ||
808 | if (NULL != sequence_number) | ||
809 | *sequence_number = room->sequence_number; | ||
810 | smc = GNUNET_malloc (sizeof (struct GNUNET_CHAT_SendMessageContext)); | ||
811 | smc->chat_room = room; | ||
812 | smc->message = GNUNET_strdup (message); | ||
813 | smc->options = options; | ||
814 | smc->receiver = receiver; | ||
815 | smc->sequence_number = room->sequence_number; | ||
816 | msg_size = strlen (message) + sizeof (struct TransmitRequestMessage); | ||
817 | GNUNET_CLIENT_notify_transmit_ready (room->client, msg_size, | ||
818 | GNUNET_CONSTANTS_SERVICE_TIMEOUT, | ||
819 | GNUNET_YES, &transmit_send_request, smc); | ||
820 | } | ||
821 | |||
822 | /* end of chat.c */ | ||
diff --git a/src/chat/chat.conf.in b/src/chat/chat.conf.in deleted file mode 100644 index 560931e67..000000000 --- a/src/chat/chat.conf.in +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | [chat] | ||
2 | AUTOSTART = YES | ||
3 | @UNIXONLY@ PORT = 2090 | ||
4 | HOSTNAME = localhost | ||
5 | HOME = $SERVICEHOME | ||
6 | BINARY = gnunet-service-chat | ||
7 | ACCEPT_FROM = 127.0.0.1; | ||
8 | ACCEPT_FROM6 = ::1; | ||
9 | UNIXPATH = /tmp/gnunet-service-chat.sock | ||
10 | UNIX_MATCH_UID = NO | ||
11 | UNIX_MATCH_GID = YES | ||
12 | # DISABLE_SOCKET_FORWARDING = NO | ||
13 | # USERNAME = | ||
14 | # MAXBUF = | ||
15 | # TIMEOUT = | ||
16 | # DISABLEV6 = | ||
17 | # BINDTO = | ||
18 | # REJECT_FROM = | ||
19 | # REJECT_FROM6 = | ||
20 | # PREFIX = | ||
21 | |||
diff --git a/src/chat/chat.h b/src/chat/chat.h deleted file mode 100644 index c65b75de9..000000000 --- a/src/chat/chat.h +++ /dev/null | |||
@@ -1,485 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | (C) 2008, 2011 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 2, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file chat/chat.h | ||
23 | * @brief support for chat | ||
24 | * @author Christian Grothoff | ||
25 | * @author Nathan Evans | ||
26 | * @author Vitaly Minko | ||
27 | */ | ||
28 | |||
29 | #ifndef CHAT_H | ||
30 | #define CHAT_H | ||
31 | |||
32 | #include "gnunet_chat_service.h" | ||
33 | |||
34 | /** | ||
35 | * Constant IV since we generate a new session key per each message. | ||
36 | */ | ||
37 | #define INITVALUE "InitializationVectorValue" | ||
38 | |||
39 | |||
40 | /** | ||
41 | * Client-service messages | ||
42 | */ | ||
43 | |||
44 | GNUNET_NETWORK_STRUCT_BEGIN | ||
45 | |||
46 | /** | ||
47 | * Notification sent by service to client indicating that we've received a chat | ||
48 | * message. After this struct, the remaining bytes are the actual text message. | ||
49 | * If the mesasge is private, then the text is encrypted, otherwise it's | ||
50 | * plaintext. | ||
51 | */ | ||
52 | struct ReceiveNotificationMessage | ||
53 | { | ||
54 | /** | ||
55 | * Message type will be GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION | ||
56 | */ | ||
57 | struct GNUNET_MessageHeader header; | ||
58 | |||
59 | /** | ||
60 | * Message options, see GNUNET_CHAT_MsgOptions. | ||
61 | */ | ||
62 | uint32_t msg_options GNUNET_PACKED; | ||
63 | |||
64 | /** | ||
65 | * Sequence number of the message (unique per sender). | ||
66 | */ | ||
67 | uint32_t sequence_number GNUNET_PACKED; | ||
68 | |||
69 | /** | ||
70 | * For alignment (should be zero). | ||
71 | */ | ||
72 | uint32_t reserved GNUNET_PACKED; | ||
73 | |||
74 | /** | ||
75 | * Timestamp of the message. | ||
76 | */ | ||
77 | struct GNUNET_TIME_AbsoluteNBO timestamp; | ||
78 | |||
79 | /** | ||
80 | * Hash of the public key of the pseudonym of the sender of the message. | ||
81 | * Should be all zeros for anonymous. | ||
82 | */ | ||
83 | struct GNUNET_HashCode sender; | ||
84 | |||
85 | /** | ||
86 | * The encrypted session key. | ||
87 | */ | ||
88 | struct GNUNET_CRYPTO_RsaEncryptedData encrypted_key; | ||
89 | |||
90 | }; | ||
91 | |||
92 | |||
93 | /** | ||
94 | * Request sent by client to transmit a chat message to another room members. | ||
95 | * After this struct, the remaining bytes are the actual message in plaintext. | ||
96 | * Private messages are encrypted on the service side. | ||
97 | */ | ||
98 | struct TransmitRequestMessage | ||
99 | { | ||
100 | /** | ||
101 | * Message type will be GNUNET_MESSAGE_TYPE_CHAT_TRANSMIT_REQUEST | ||
102 | */ | ||
103 | struct GNUNET_MessageHeader header; | ||
104 | |||
105 | /** | ||
106 | * For alignment (should be zero). | ||
107 | */ | ||
108 | uint32_t reserved GNUNET_PACKED; | ||
109 | |||
110 | /** | ||
111 | * Signature confirming receipt. Signature covers everything from header | ||
112 | * through content. | ||
113 | */ | ||
114 | struct GNUNET_CRYPTO_RsaSignature signature; | ||
115 | |||
116 | /** | ||
117 | * What is being signed and why? | ||
118 | */ | ||
119 | struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; | ||
120 | |||
121 | /** | ||
122 | * Desired message options, see GNUNET_CHAT_MsgOptions. | ||
123 | */ | ||
124 | uint32_t msg_options GNUNET_PACKED; | ||
125 | |||
126 | /** | ||
127 | * Sequence number of the message (unique per sender). | ||
128 | */ | ||
129 | uint32_t sequence_number GNUNET_PACKED; | ||
130 | |||
131 | /** | ||
132 | * Timestamp of the message. | ||
133 | */ | ||
134 | struct GNUNET_TIME_AbsoluteNBO timestamp; | ||
135 | |||
136 | /** | ||
137 | * Who should receive this message? Set to all zeros for "everyone". | ||
138 | */ | ||
139 | struct GNUNET_HashCode target; | ||
140 | |||
141 | }; | ||
142 | |||
143 | |||
144 | /** | ||
145 | * Receipt sent from a message receiver to the service to confirm delivery of | ||
146 | * a chat message and from the service to sender of the original message to | ||
147 | * acknowledge delivery. | ||
148 | */ | ||
149 | struct ConfirmationReceiptMessage | ||
150 | { | ||
151 | /** | ||
152 | * Message type will be | ||
153 | * GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_RECEIPT when sending from client, | ||
154 | * GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION when sending to client. | ||
155 | */ | ||
156 | struct GNUNET_MessageHeader header; | ||
157 | |||
158 | /** | ||
159 | * For alignment (should be zero). | ||
160 | */ | ||
161 | uint32_t reserved GNUNET_PACKED; | ||
162 | |||
163 | /** | ||
164 | * Signature confirming receipt. Signature covers everything from header | ||
165 | * through content. | ||
166 | */ | ||
167 | struct GNUNET_CRYPTO_RsaSignature signature; | ||
168 | |||
169 | /** | ||
170 | * What is being signed and why? | ||
171 | */ | ||
172 | struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; | ||
173 | |||
174 | /** | ||
175 | * Sequence number of the original message. | ||
176 | */ | ||
177 | uint32_t sequence_number GNUNET_PACKED; | ||
178 | |||
179 | /** | ||
180 | * For alignment (should be zero). | ||
181 | */ | ||
182 | uint32_t reserved2 GNUNET_PACKED; | ||
183 | |||
184 | /** | ||
185 | * Time of receipt. | ||
186 | */ | ||
187 | struct GNUNET_TIME_AbsoluteNBO timestamp; | ||
188 | |||
189 | /** | ||
190 | * Who is confirming the receipt? | ||
191 | */ | ||
192 | struct GNUNET_HashCode target; | ||
193 | |||
194 | /** | ||
195 | * Who is the author of the chat message? | ||
196 | */ | ||
197 | struct GNUNET_HashCode author; | ||
198 | |||
199 | /** | ||
200 | * Hash of the (possibly encrypted) content. | ||
201 | */ | ||
202 | struct GNUNET_HashCode content; | ||
203 | |||
204 | }; | ||
205 | |||
206 | |||
207 | /** | ||
208 | * Message send from client to daemon to join a chat room. | ||
209 | * This struct is followed by the room name and then | ||
210 | * the serialized ECRS meta data describing the new member. | ||
211 | */ | ||
212 | struct JoinRequestMessage | ||
213 | { | ||
214 | /** | ||
215 | * Message type will be GNUNET_MESSAGE_TYPE_CHAT_JOIN_REQUEST | ||
216 | */ | ||
217 | struct GNUNET_MessageHeader header; | ||
218 | |||
219 | /** | ||
220 | * Options. Set all options that this client is willing to receive. | ||
221 | * For example, if the client does not want to receive anonymous or | ||
222 | * OTR messages but is willing to generate acknowledgements and | ||
223 | * receive private messages, this should be set to | ||
224 | * GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_ACKNOWLEDGED. | ||
225 | */ | ||
226 | uint32_t msg_options GNUNET_PACKED; | ||
227 | |||
228 | /** | ||
229 | * Length of the room name. | ||
230 | */ | ||
231 | uint16_t room_name_len GNUNET_PACKED; | ||
232 | |||
233 | /** | ||
234 | * For alignment (should be zero). | ||
235 | */ | ||
236 | uint16_t reserved GNUNET_PACKED; | ||
237 | uint32_t reserved2 GNUNET_PACKED; | ||
238 | |||
239 | /** | ||
240 | * Public key of the joining member. | ||
241 | */ | ||
242 | struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; | ||
243 | |||
244 | }; | ||
245 | |||
246 | |||
247 | /** | ||
248 | * Message send by server to client to indicate joining of another room member. | ||
249 | * This struct is followed by the serialized ECRS MetaData describing the new | ||
250 | * member. | ||
251 | */ | ||
252 | struct JoinNotificationMessage | ||
253 | { | ||
254 | /** | ||
255 | * Message type will be GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION | ||
256 | */ | ||
257 | struct GNUNET_MessageHeader header; | ||
258 | |||
259 | /** | ||
260 | * Options. Set to all options that the new user is willing to | ||
261 | * process. For example, if the client does not want to receive | ||
262 | * anonymous or OTR messages but is willing to generate | ||
263 | * acknowledgements and receive private messages, this should be set | ||
264 | * to GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_ACKNOWLEDGED. | ||
265 | */ | ||
266 | uint32_t msg_options GNUNET_PACKED; | ||
267 | |||
268 | /** | ||
269 | * Public key of the new user. | ||
270 | */ | ||
271 | struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; | ||
272 | |||
273 | }; | ||
274 | |||
275 | |||
276 | /** | ||
277 | * Message send by server to client to indicate leaving of another room member. | ||
278 | */ | ||
279 | struct LeaveNotificationMessage | ||
280 | { | ||
281 | /** | ||
282 | * Message type will be GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION | ||
283 | */ | ||
284 | struct GNUNET_MessageHeader header; | ||
285 | |||
286 | /** | ||
287 | * Reserved (for alignment). | ||
288 | */ | ||
289 | uint32_t reserved GNUNET_PACKED; | ||
290 | |||
291 | /** | ||
292 | * Who is leaving? | ||
293 | */ | ||
294 | struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded user; | ||
295 | |||
296 | }; | ||
297 | |||
298 | |||
299 | /** | ||
300 | * Peer-to-peer messages | ||
301 | */ | ||
302 | |||
303 | /** | ||
304 | * Message send by one peer to another to indicate joining of another room | ||
305 | * member. This struct is followed by the room name and then the serialized | ||
306 | * ECRS MetaData describing the new member. | ||
307 | */ | ||
308 | struct P2PJoinNotificationMessage | ||
309 | { | ||
310 | /** | ||
311 | * Message type will be GNUNET_MESSAGE_TYPE_CHAT_P2P_JOIN_NOTIFICATION | ||
312 | */ | ||
313 | struct GNUNET_MessageHeader header; | ||
314 | |||
315 | /** | ||
316 | * Options. Set all options that this client is willing to receive. | ||
317 | * For example, if the client does not want to receive anonymous or | ||
318 | * OTR messages but is willing to generate acknowledgements and | ||
319 | * receive private messages, this should be set to | ||
320 | * GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_ACKNOWLEDGED. | ||
321 | */ | ||
322 | uint32_t msg_options GNUNET_PACKED; | ||
323 | |||
324 | /** | ||
325 | * Length of the room name. | ||
326 | */ | ||
327 | uint16_t room_name_len GNUNET_PACKED; | ||
328 | |||
329 | /** | ||
330 | * Reserved (should be zero). | ||
331 | */ | ||
332 | uint16_t reserved GNUNET_PACKED; | ||
333 | uint32_t reserved2 GNUNET_PACKED; | ||
334 | |||
335 | /** | ||
336 | * Public key of the joining member. | ||
337 | */ | ||
338 | struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; | ||
339 | |||
340 | }; | ||
341 | |||
342 | |||
343 | /** | ||
344 | * Message send by one peer to another to indicate leaving of another room | ||
345 | * member. | ||
346 | */ | ||
347 | struct P2PLeaveNotificationMessage | ||
348 | { | ||
349 | /** | ||
350 | * Message type will be GNUNET_MESSAGE_TYPE_CHAT_P2P_LEAVE_NOTIFICATION | ||
351 | */ | ||
352 | struct GNUNET_MessageHeader header; | ||
353 | |||
354 | /** | ||
355 | * Reserved (for alignment). | ||
356 | */ | ||
357 | uint32_t reserved GNUNET_PACKED; | ||
358 | |||
359 | /** | ||
360 | * Who is leaving? | ||
361 | */ | ||
362 | struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded user; | ||
363 | |||
364 | }; | ||
365 | |||
366 | |||
367 | /** | ||
368 | * Message send by one peer to another to indicate receiving of a chat message. | ||
369 | * This struct is followed by the room name (only if the message is anonymous) | ||
370 | * and then the remaining bytes are the actual text message. If the mesasge is | ||
371 | * private, then the text is encrypted, otherwise it's plaintext. | ||
372 | */ | ||
373 | struct P2PReceiveNotificationMessage | ||
374 | { | ||
375 | /** | ||
376 | * Message type will be GNUNET_MESSAGE_TYPE_CHAT_P2P_MESSAGE_NOTIFICATION | ||
377 | */ | ||
378 | struct GNUNET_MessageHeader header; | ||
379 | |||
380 | /** | ||
381 | * Message options, see GNUNET_CHAT_MsgOptions. | ||
382 | */ | ||
383 | uint32_t msg_options GNUNET_PACKED; | ||
384 | |||
385 | /** | ||
386 | * Sequence number of the message (unique per sender). | ||
387 | */ | ||
388 | uint32_t sequence_number GNUNET_PACKED; | ||
389 | |||
390 | /** | ||
391 | * Length of the room name. This is only used for anonymous messages. | ||
392 | */ | ||
393 | uint16_t room_name_len GNUNET_PACKED; | ||
394 | |||
395 | /** | ||
396 | * Reserved (for alignment). | ||
397 | */ | ||
398 | uint16_t reserved GNUNET_PACKED; | ||
399 | |||
400 | /** | ||
401 | * Timestamp of the message. | ||
402 | */ | ||
403 | struct GNUNET_TIME_AbsoluteNBO timestamp; | ||
404 | |||
405 | /** | ||
406 | * Hash of the public key of the pseudonym of the sender of the message | ||
407 | * Should be all zeros for anonymous. | ||
408 | */ | ||
409 | struct GNUNET_HashCode sender; | ||
410 | |||
411 | /** | ||
412 | * Who should receive this message? Set to all zeros for "everyone". | ||
413 | */ | ||
414 | struct GNUNET_HashCode target; | ||
415 | |||
416 | /** | ||
417 | * The encrypted session key. | ||
418 | */ | ||
419 | struct GNUNET_CRYPTO_RsaEncryptedData encrypted_key; | ||
420 | |||
421 | }; | ||
422 | |||
423 | |||
424 | /** | ||
425 | * Receipt sent from one peer to another to confirm delivery of a chat message. | ||
426 | */ | ||
427 | struct P2PConfirmationReceiptMessage | ||
428 | { | ||
429 | /** | ||
430 | * Message type will be GNUNET_MESSAGE_TYPE_CHAT_P2P_CONFIRMATION_RECEIPT | ||
431 | */ | ||
432 | struct GNUNET_MessageHeader header; | ||
433 | |||
434 | /** | ||
435 | * For alignment (should be zero). | ||
436 | */ | ||
437 | uint32_t reserved GNUNET_PACKED; | ||
438 | |||
439 | /** | ||
440 | * Signature confirming receipt. Signature covers everything from header | ||
441 | * through content. | ||
442 | */ | ||
443 | struct GNUNET_CRYPTO_RsaSignature signature; | ||
444 | |||
445 | /** | ||
446 | * What is being signed and why? | ||
447 | */ | ||
448 | struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; | ||
449 | |||
450 | /** | ||
451 | * Sequence number of the original message. | ||
452 | */ | ||
453 | uint32_t msg_sequence_number GNUNET_PACKED; | ||
454 | |||
455 | /** | ||
456 | * Sequence number of the receipt. | ||
457 | */ | ||
458 | uint32_t sequence_number GNUNET_PACKED; | ||
459 | |||
460 | /** | ||
461 | * Time of receipt. | ||
462 | */ | ||
463 | struct GNUNET_TIME_AbsoluteNBO timestamp; | ||
464 | |||
465 | /** | ||
466 | * Who is confirming the receipt? | ||
467 | */ | ||
468 | struct GNUNET_HashCode target; | ||
469 | |||
470 | /** | ||
471 | * Who is the author of the chat message? | ||
472 | */ | ||
473 | struct GNUNET_HashCode author; | ||
474 | |||
475 | /** | ||
476 | * Hash of the (possibly encrypted) content. | ||
477 | */ | ||
478 | struct GNUNET_HashCode content; | ||
479 | |||
480 | }; | ||
481 | GNUNET_NETWORK_STRUCT_END | ||
482 | |||
483 | #endif | ||
484 | |||
485 | /* end of chat.h */ | ||
diff --git a/src/chat/gnunet-chat.c b/src/chat/gnunet-chat.c deleted file mode 100644 index 2d2f8f835..000000000 --- a/src/chat/gnunet-chat.c +++ /dev/null | |||
@@ -1,750 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2007, 2008, 2011 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file chat/gnunet-chat.c | ||
23 | * @brief Minimal chat command line tool | ||
24 | * @author Christian Grothoff | ||
25 | * @author Nathan Evans | ||
26 | * @author Vitaly Minko | ||
27 | */ | ||
28 | |||
29 | #include "platform.h" | ||
30 | #include "gnunet_getopt_lib.h" | ||
31 | #include "gnunet_program_lib.h" | ||
32 | #include "gnunet_chat_service.h" | ||
33 | #include "gnunet_fs_service.h" | ||
34 | #include <fcntl.h> | ||
35 | |||
36 | static int ret; | ||
37 | |||
38 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
39 | |||
40 | static char *nickname; | ||
41 | |||
42 | static char *room_name; | ||
43 | |||
44 | static struct GNUNET_CONTAINER_MetaData *meta; | ||
45 | |||
46 | static struct GNUNET_CHAT_Room *room; | ||
47 | |||
48 | static GNUNET_SCHEDULER_TaskIdentifier handle_cmd_task; | ||
49 | |||
50 | typedef int (*ActionFunction)(const char *argumetns, const void *xtra); | ||
51 | |||
52 | struct ChatCommand | ||
53 | { | ||
54 | const char *command; | ||
55 | ActionFunction Action; | ||
56 | const char *helptext; | ||
57 | }; | ||
58 | |||
59 | struct UserList | ||
60 | { | ||
61 | struct UserList *next; | ||
62 | struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; | ||
63 | int ignored; | ||
64 | }; | ||
65 | |||
66 | static struct UserList *users; | ||
67 | |||
68 | static void | ||
69 | free_user_list () | ||
70 | { | ||
71 | struct UserList *next; | ||
72 | |||
73 | while (NULL != users) | ||
74 | { | ||
75 | next = users->next; | ||
76 | GNUNET_free (users); | ||
77 | users = next; | ||
78 | } | ||
79 | } | ||
80 | |||
81 | static int | ||
82 | do_help (const char *args, const void *xtra); | ||
83 | |||
84 | |||
85 | /** | ||
86 | * Callback used for notification that we have joined the room. | ||
87 | * | ||
88 | * @param cls closure | ||
89 | * @return GNUNET_OK | ||
90 | */ | ||
91 | static int | ||
92 | join_cb (void *cls) | ||
93 | { | ||
94 | FPRINTF (stdout, "%s", _("Joined\n")); | ||
95 | return GNUNET_OK; | ||
96 | } | ||
97 | |||
98 | |||
99 | /** | ||
100 | * Callback used for notification about incoming messages. | ||
101 | * | ||
102 | * @param cls closure, NULL | ||
103 | * @param room in which room was the message received? | ||
104 | * @param sender what is the ID of the sender? (maybe NULL) | ||
105 | * @param member_info information about the joining member | ||
106 | * @param message the message text | ||
107 | * @param timestamp time when the member joined | ||
108 | * @param options options for the message | ||
109 | * @return GNUNET_OK to accept the message now, GNUNET_NO to | ||
110 | * accept (but user is away), GNUNET_SYSERR to signal denied delivery | ||
111 | */ | ||
112 | static int | ||
113 | receive_cb (void *cls, struct GNUNET_CHAT_Room *room, | ||
114 | const struct GNUNET_HashCode * sender, | ||
115 | const struct GNUNET_CONTAINER_MetaData *member_info, | ||
116 | const char *message, struct GNUNET_TIME_Absolute timestamp, | ||
117 | enum GNUNET_CHAT_MsgOptions options) | ||
118 | { | ||
119 | char *non_unique_nick; | ||
120 | char *nick; | ||
121 | int nick_is_a_dup; | ||
122 | const char *timestr; | ||
123 | const char *fmt; | ||
124 | |||
125 | if (NULL == sender) | ||
126 | nick = GNUNET_strdup (_("anonymous")); | ||
127 | else | ||
128 | { | ||
129 | if (GNUNET_OK != GNUNET_FS_pseudonym_get_info (cfg, | ||
130 | sender, NULL, NULL, &non_unique_nick, &nick_is_a_dup) | ||
131 | || (nick_is_a_dup == GNUNET_YES)) | ||
132 | { | ||
133 | GNUNET_free (non_unique_nick); | ||
134 | non_unique_nick = GNUNET_strdup (_("anonymous")); | ||
135 | } | ||
136 | nick = GNUNET_FS_pseudonym_name_uniquify (cfg, sender, non_unique_nick, NULL); | ||
137 | GNUNET_free (non_unique_nick); | ||
138 | } | ||
139 | |||
140 | fmt = NULL; | ||
141 | switch ((int) options) | ||
142 | { | ||
143 | case GNUNET_CHAT_MSG_OPTION_NONE: | ||
144 | case GNUNET_CHAT_MSG_ANONYMOUS: | ||
145 | fmt = _("(%s) `%s' said: %s\n"); | ||
146 | break; | ||
147 | case GNUNET_CHAT_MSG_PRIVATE: | ||
148 | fmt = _("(%s) `%s' said to you: %s\n"); | ||
149 | break; | ||
150 | case GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_ANONYMOUS: | ||
151 | fmt = _("(%s) `%s' said to you: %s\n"); | ||
152 | break; | ||
153 | case GNUNET_CHAT_MSG_AUTHENTICATED: | ||
154 | fmt = _("(%s) `%s' said for sure: %s\n"); | ||
155 | break; | ||
156 | case GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_AUTHENTICATED: | ||
157 | fmt = _("(%s) `%s' said to you for sure: %s\n"); | ||
158 | break; | ||
159 | case GNUNET_CHAT_MSG_ACKNOWLEDGED: | ||
160 | fmt = _("(%s) `%s' was confirmed that you received: %s\n"); | ||
161 | break; | ||
162 | case GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_ACKNOWLEDGED: | ||
163 | fmt = _("(%s) `%s' was confirmed that you and only you received: %s\n"); | ||
164 | break; | ||
165 | case GNUNET_CHAT_MSG_AUTHENTICATED | GNUNET_CHAT_MSG_ACKNOWLEDGED: | ||
166 | fmt = _("(%s) `%s' was confirmed that you received from him or her: %s\n"); | ||
167 | break; | ||
168 | case GNUNET_CHAT_MSG_AUTHENTICATED | GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_ACKNOWLEDGED: | ||
169 | fmt = | ||
170 | _ | ||
171 | ("(%s) `%s' was confirmed that you and only you received from him or her: %s\n"); | ||
172 | break; | ||
173 | case GNUNET_CHAT_MSG_OFF_THE_RECORD: | ||
174 | fmt = _("(%s) `%s' said off the record: %s\n"); | ||
175 | break; | ||
176 | default: | ||
177 | fmt = _("(%s) <%s> said using an unknown message type: %s\n"); | ||
178 | break; | ||
179 | } | ||
180 | timestr = GNUNET_STRINGS_absolute_time_to_string (timestamp); | ||
181 | FPRINTF (stdout, fmt, timestr, nick, message); | ||
182 | GNUNET_free (nick); | ||
183 | return GNUNET_OK; | ||
184 | } | ||
185 | |||
186 | |||
187 | /** | ||
188 | * Callback used for message delivery confirmations. | ||
189 | * | ||
190 | * @param cls closure, NULL | ||
191 | * @param room in which room was the message received? | ||
192 | * @param orig_seq_number sequence number of the original message | ||
193 | * @param timestamp when was the message received? | ||
194 | * @param receiver who is confirming the receipt? | ||
195 | * @return GNUNET_OK to continue, GNUNET_SYSERR to refuse processing further | ||
196 | * confirmations from anyone for this message | ||
197 | */ | ||
198 | static int | ||
199 | confirmation_cb (void *cls, struct GNUNET_CHAT_Room *room, | ||
200 | uint32_t orig_seq_number, | ||
201 | struct GNUNET_TIME_Absolute timestamp, | ||
202 | const struct GNUNET_HashCode * receiver) | ||
203 | { | ||
204 | char *nick; | ||
205 | char *unique_nick; | ||
206 | int nick_is_a_dup; | ||
207 | |||
208 | if (GNUNET_OK != GNUNET_FS_pseudonym_get_info (cfg, | ||
209 | receiver, NULL, NULL, &nick, &nick_is_a_dup) | ||
210 | || (nick_is_a_dup == GNUNET_YES)) | ||
211 | { | ||
212 | GNUNET_free (nick); | ||
213 | nick = GNUNET_strdup (_("anonymous")); | ||
214 | } | ||
215 | unique_nick = GNUNET_FS_pseudonym_name_uniquify (cfg, receiver, nick, NULL); | ||
216 | GNUNET_free (nick); | ||
217 | FPRINTF (stdout, _("'%s' acknowledged message #%d\n"), unique_nick, orig_seq_number); | ||
218 | GNUNET_free (unique_nick); | ||
219 | return GNUNET_OK; | ||
220 | } | ||
221 | |||
222 | |||
223 | /** | ||
224 | * Callback used for notification that another room member has joined or left. | ||
225 | * | ||
226 | * @param cls closure (not used) | ||
227 | * @param member_info will be non-null if the member is joining, NULL if he is | ||
228 | * leaving | ||
229 | * @param member_id hash of public key of the user (for unique identification) | ||
230 | * @param options what types of messages is this member willing to receive? | ||
231 | * @return GNUNET_OK | ||
232 | */ | ||
233 | static int | ||
234 | member_list_cb (void *cls, const struct GNUNET_CONTAINER_MetaData *member_info, | ||
235 | const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *member_id, | ||
236 | enum GNUNET_CHAT_MsgOptions options) | ||
237 | { | ||
238 | char *nick; | ||
239 | char *non_unique_nick; | ||
240 | int nick_is_a_dup; | ||
241 | struct GNUNET_HashCode id; | ||
242 | struct UserList *pos; | ||
243 | struct UserList *prev; | ||
244 | |||
245 | GNUNET_CRYPTO_hash (member_id, | ||
246 | sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), | ||
247 | &id); | ||
248 | if (GNUNET_OK != GNUNET_FS_pseudonym_get_info (cfg, | ||
249 | &id, NULL, NULL, &non_unique_nick, &nick_is_a_dup) | ||
250 | || (nick_is_a_dup == GNUNET_YES)) | ||
251 | { | ||
252 | GNUNET_free (non_unique_nick); | ||
253 | non_unique_nick = GNUNET_strdup (_("anonymous")); | ||
254 | } | ||
255 | nick = GNUNET_FS_pseudonym_name_uniquify (cfg, &id, non_unique_nick, NULL); | ||
256 | GNUNET_free (non_unique_nick); | ||
257 | |||
258 | FPRINTF (stdout, | ||
259 | member_info != | ||
260 | NULL ? _("`%s' entered the room\n") : _("`%s' left the room\n"), | ||
261 | nick); | ||
262 | GNUNET_free (nick); | ||
263 | if (NULL != member_info) | ||
264 | { | ||
265 | /* user joining */ | ||
266 | pos = GNUNET_malloc (sizeof (struct UserList)); | ||
267 | pos->next = users; | ||
268 | pos->pkey = *member_id; | ||
269 | pos->ignored = GNUNET_NO; | ||
270 | users = pos; | ||
271 | } | ||
272 | else | ||
273 | { | ||
274 | /* user leaving */ | ||
275 | prev = NULL; | ||
276 | pos = users; | ||
277 | while ((NULL != pos) && | ||
278 | (0 != | ||
279 | memcmp (&pos->pkey, member_id, | ||
280 | sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)))) | ||
281 | { | ||
282 | prev = pos; | ||
283 | pos = pos->next; | ||
284 | } | ||
285 | if (NULL == pos) | ||
286 | { | ||
287 | GNUNET_break (0); | ||
288 | } | ||
289 | else | ||
290 | { | ||
291 | if (NULL == prev) | ||
292 | users = pos->next; | ||
293 | else | ||
294 | prev->next = pos->next; | ||
295 | GNUNET_free (pos); | ||
296 | } | ||
297 | } | ||
298 | return GNUNET_OK; | ||
299 | } | ||
300 | |||
301 | |||
302 | static int | ||
303 | do_join (const char *arg, const void *xtra) | ||
304 | { | ||
305 | char *my_name; | ||
306 | int my_name_is_a_dup; | ||
307 | struct GNUNET_HashCode me; | ||
308 | |||
309 | if (arg[0] == '#') | ||
310 | arg++; /* ignore first hash */ | ||
311 | GNUNET_CHAT_leave_room (room); | ||
312 | free_user_list (); | ||
313 | GNUNET_free (room_name); | ||
314 | room_name = GNUNET_strdup (arg); | ||
315 | room = | ||
316 | GNUNET_CHAT_join_room (cfg, nickname, meta, room_name, -1, &join_cb, NULL, | ||
317 | &receive_cb, NULL, &member_list_cb, NULL, | ||
318 | &confirmation_cb, NULL, &me); | ||
319 | if (NULL == room) | ||
320 | { | ||
321 | FPRINTF (stdout, "%s", _("Could not change username\n")); | ||
322 | return GNUNET_SYSERR; | ||
323 | } | ||
324 | if ((GNUNET_OK != GNUNET_FS_pseudonym_get_info (cfg, | ||
325 | &me, NULL, NULL, &my_name, &my_name_is_a_dup)) || | ||
326 | (my_name_is_a_dup == GNUNET_YES)) | ||
327 | { | ||
328 | GNUNET_free (my_name); | ||
329 | my_name = GNUNET_strdup (_("anonymous")); | ||
330 | } | ||
331 | /* Don't uniquify our own name - other people will have a different | ||
332 | * suffix for our own name anyway. | ||
333 | */ | ||
334 | FPRINTF (stdout, _("Joining room `%s' as user `%s'...\n"), room_name, | ||
335 | my_name); | ||
336 | GNUNET_free (my_name); | ||
337 | return GNUNET_OK; | ||
338 | } | ||
339 | |||
340 | |||
341 | static int | ||
342 | do_nick (const char *msg, const void *xtra) | ||
343 | { | ||
344 | char *my_name; | ||
345 | int my_name_is_a_dup; | ||
346 | struct GNUNET_HashCode me; | ||
347 | |||
348 | GNUNET_CHAT_leave_room (room); | ||
349 | free_user_list (); | ||
350 | GNUNET_free (nickname); | ||
351 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
352 | nickname = GNUNET_strdup (msg); | ||
353 | meta = GNUNET_CONTAINER_meta_data_create (); | ||
354 | GNUNET_CONTAINER_meta_data_insert (meta, "<gnunet>", EXTRACTOR_METATYPE_TITLE, | ||
355 | EXTRACTOR_METAFORMAT_UTF8, "text/plain", | ||
356 | nickname, strlen (nickname) + 1); | ||
357 | room = | ||
358 | GNUNET_CHAT_join_room (cfg, nickname, meta, room_name, -1, &join_cb, NULL, | ||
359 | &receive_cb, NULL, &member_list_cb, NULL, | ||
360 | &confirmation_cb, NULL, &me); | ||
361 | if (NULL == room) | ||
362 | { | ||
363 | FPRINTF (stdout, "%s", _("Could not change username\n")); | ||
364 | return GNUNET_SYSERR; | ||
365 | } | ||
366 | if ((GNUNET_OK != GNUNET_FS_pseudonym_get_info (cfg, | ||
367 | &me, NULL, NULL, &my_name, &my_name_is_a_dup)) || | ||
368 | (my_name_is_a_dup == GNUNET_YES)) | ||
369 | { | ||
370 | GNUNET_free (my_name); | ||
371 | my_name = GNUNET_strdup (_("anonymous")); | ||
372 | } | ||
373 | FPRINTF (stdout, _("Changed username to `%s'\n"), my_name); | ||
374 | GNUNET_free (my_name); | ||
375 | return GNUNET_OK; | ||
376 | } | ||
377 | |||
378 | |||
379 | static int | ||
380 | do_names (const char *msg, const void *xtra) | ||
381 | { | ||
382 | char *name; | ||
383 | char *unique_name; | ||
384 | int name_is_a_dup; | ||
385 | struct UserList *pos; | ||
386 | struct GNUNET_HashCode pid; | ||
387 | |||
388 | FPRINTF (stdout, _("Users in room `%s': "), room_name); | ||
389 | pos = users; | ||
390 | while (NULL != pos) | ||
391 | { | ||
392 | GNUNET_CRYPTO_hash (&pos->pkey, | ||
393 | sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), | ||
394 | &pid); | ||
395 | if (GNUNET_OK != GNUNET_FS_pseudonym_get_info (cfg, | ||
396 | &pid, NULL, NULL, &name, &name_is_a_dup) | ||
397 | || (name_is_a_dup == GNUNET_YES)) | ||
398 | { | ||
399 | GNUNET_free (name); | ||
400 | name = GNUNET_strdup (_("anonymous")); | ||
401 | } | ||
402 | unique_name = GNUNET_FS_pseudonym_name_uniquify (cfg, &pid, name, NULL); | ||
403 | GNUNET_free (name); | ||
404 | FPRINTF (stdout, "`%s' ", unique_name); | ||
405 | GNUNET_free (unique_name); | ||
406 | pos = pos->next; | ||
407 | } | ||
408 | FPRINTF (stdout, "%s", "\n"); | ||
409 | return GNUNET_OK; | ||
410 | } | ||
411 | |||
412 | |||
413 | static int | ||
414 | do_send (const char *msg, const void *xtra) | ||
415 | { | ||
416 | uint32_t seq; | ||
417 | |||
418 | GNUNET_CHAT_send_message (room, msg, GNUNET_CHAT_MSG_OPTION_NONE, NULL, &seq); | ||
419 | return GNUNET_OK; | ||
420 | } | ||
421 | |||
422 | |||
423 | static int | ||
424 | do_send_pm (const char *msg, const void *xtra) | ||
425 | { | ||
426 | char *user; | ||
427 | struct GNUNET_HashCode uid; | ||
428 | struct GNUNET_HashCode pid; | ||
429 | uint32_t seq; | ||
430 | struct UserList *pos; | ||
431 | |||
432 | if (NULL == strstr (msg, " ")) | ||
433 | { | ||
434 | FPRINTF (stderr, "%s", _("Syntax: /msg USERNAME MESSAGE")); | ||
435 | return GNUNET_OK; | ||
436 | } | ||
437 | user = GNUNET_strdup (msg); | ||
438 | strstr (user, " ")[0] = '\0'; | ||
439 | msg += strlen (user) + 1; | ||
440 | if (GNUNET_OK != GNUNET_FS_pseudonym_name_to_id (cfg, user, &uid)) | ||
441 | { | ||
442 | FPRINTF (stderr, | ||
443 | _("Unknown user `%s'. Make sure you specify its numeric suffix, if any.\n"), | ||
444 | user); | ||
445 | GNUNET_free (user); | ||
446 | return GNUNET_OK; | ||
447 | } | ||
448 | pos = users; | ||
449 | while (NULL != pos) | ||
450 | { | ||
451 | GNUNET_CRYPTO_hash (&pos->pkey, | ||
452 | sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), | ||
453 | &pid); | ||
454 | if (0 == memcmp (&pid, &uid, sizeof (struct GNUNET_HashCode))) | ||
455 | break; | ||
456 | pos = pos->next; | ||
457 | } | ||
458 | if (NULL == pos) | ||
459 | { | ||
460 | FPRINTF (stderr, _("User `%s' is currently not in the room!\n"), user); | ||
461 | GNUNET_free (user); | ||
462 | return GNUNET_OK; | ||
463 | } | ||
464 | GNUNET_CHAT_send_message (room, msg, GNUNET_CHAT_MSG_PRIVATE, &pos->pkey, | ||
465 | &seq); | ||
466 | GNUNET_free (user); | ||
467 | return GNUNET_OK; | ||
468 | } | ||
469 | |||
470 | |||
471 | static int | ||
472 | do_send_sig (const char *msg, const void *xtra) | ||
473 | { | ||
474 | uint32_t seq; | ||
475 | |||
476 | GNUNET_CHAT_send_message (room, msg, GNUNET_CHAT_MSG_AUTHENTICATED, NULL, | ||
477 | &seq); | ||
478 | return GNUNET_OK; | ||
479 | } | ||
480 | |||
481 | |||
482 | static int | ||
483 | do_send_ack (const char *msg, const void *xtra) | ||
484 | { | ||
485 | uint32_t seq; | ||
486 | |||
487 | GNUNET_CHAT_send_message (room, msg, GNUNET_CHAT_MSG_ACKNOWLEDGED, NULL, | ||
488 | &seq); | ||
489 | return GNUNET_OK; | ||
490 | } | ||
491 | |||
492 | |||
493 | static int | ||
494 | do_send_anonymous (const char *msg, const void *xtra) | ||
495 | { | ||
496 | uint32_t seq; | ||
497 | |||
498 | GNUNET_CHAT_send_message (room, msg, GNUNET_CHAT_MSG_ANONYMOUS, NULL, &seq); | ||
499 | return GNUNET_OK; | ||
500 | } | ||
501 | |||
502 | |||
503 | static int | ||
504 | do_quit (const char *args, const void *xtra) | ||
505 | { | ||
506 | return GNUNET_SYSERR; | ||
507 | } | ||
508 | |||
509 | |||
510 | static int | ||
511 | do_unknown (const char *msg, const void *xtra) | ||
512 | { | ||
513 | FPRINTF (stderr, _("Unknown command `%s'\n"), msg); | ||
514 | return GNUNET_OK; | ||
515 | } | ||
516 | |||
517 | |||
518 | /** | ||
519 | * List of supported IRC commands. The order matters! | ||
520 | */ | ||
521 | static struct ChatCommand commands[] = { | ||
522 | {"/join ", &do_join, | ||
523 | gettext_noop | ||
524 | ("Use `/join #roomname' to join a chat room. Joining a room will cause you" | ||
525 | " to leave the current room")}, | ||
526 | {"/nick ", &do_nick, | ||
527 | gettext_noop | ||
528 | ("Use `/nick nickname' to change your nickname. This will cause you to" | ||
529 | " leave the current room and immediately rejoin it with the new name.")}, | ||
530 | {"/msg ", &do_send_pm, | ||
531 | gettext_noop | ||
532 | ("Use `/msg nickname message' to send a private message to the specified" | ||
533 | " user")}, | ||
534 | {"/notice ", &do_send_pm, | ||
535 | gettext_noop ("The `/notice' command is an alias for `/msg'")}, | ||
536 | {"/query ", &do_send_pm, | ||
537 | gettext_noop ("The `/query' command is an alias for `/msg'")}, | ||
538 | {"/sig ", &do_send_sig, | ||
539 | gettext_noop ("Use `/sig message' to send a signed public message")}, | ||
540 | {"/ack ", &do_send_ack, | ||
541 | gettext_noop | ||
542 | ("Use `/ack message' to require signed acknowledgment of the message")}, | ||
543 | {"/anonymous ", &do_send_anonymous, | ||
544 | gettext_noop | ||
545 | ("Use `/anonymous message' to send a public anonymous message")}, | ||
546 | {"/anon ", &do_send_anonymous, | ||
547 | gettext_noop ("The `/anon' command is an alias for `/anonymous'")}, | ||
548 | {"/quit", &do_quit, | ||
549 | gettext_noop ("Use `/quit' to terminate gnunet-chat")}, | ||
550 | {"/leave", &do_quit, | ||
551 | gettext_noop ("The `/leave' command is an alias for `/quit'")}, | ||
552 | {"/names", &do_names, | ||
553 | gettext_noop | ||
554 | ("Use `/names' to list all of the current members in the chat room")}, | ||
555 | {"/help", &do_help, | ||
556 | gettext_noop ("Use `/help command' to get help for a specific command")}, | ||
557 | /* Add standard commands: | ||
558 | * /whois (print metadata), | ||
559 | * /ignore (set flag, check on receive!) */ | ||
560 | /* the following three commands must be last! */ | ||
561 | {"/", &do_unknown, NULL}, | ||
562 | {"", &do_send, NULL}, | ||
563 | {NULL, NULL, NULL}, | ||
564 | }; | ||
565 | |||
566 | |||
567 | static int | ||
568 | do_help (const char *args, const void *xtra) | ||
569 | { | ||
570 | int i; | ||
571 | |||
572 | i = 0; | ||
573 | while ((NULL != args) && (0 != strlen (args)) && | ||
574 | (commands[i].Action != &do_help)) | ||
575 | { | ||
576 | if (0 == strncasecmp (&args[1], &commands[i].command[1], strlen (args) - 1)) | ||
577 | { | ||
578 | FPRINTF (stdout, "%s\n", gettext (commands[i].helptext)); | ||
579 | return GNUNET_OK; | ||
580 | } | ||
581 | i++; | ||
582 | } | ||
583 | i = 0; | ||
584 | FPRINTF (stdout, "%s", "Available commands:"); | ||
585 | while (commands[i].Action != &do_help) | ||
586 | { | ||
587 | FPRINTF (stdout, " %s", gettext (commands[i].command)); | ||
588 | i++; | ||
589 | } | ||
590 | FPRINTF (stdout, "%s", "\n"); | ||
591 | FPRINTF (stdout, "%s\n", gettext (commands[i].helptext)); | ||
592 | return GNUNET_OK; | ||
593 | } | ||
594 | |||
595 | |||
596 | static void | ||
597 | do_stop_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
598 | { | ||
599 | GNUNET_CHAT_leave_room (room); | ||
600 | if (handle_cmd_task != GNUNET_SCHEDULER_NO_TASK) | ||
601 | { | ||
602 | GNUNET_SCHEDULER_cancel (handle_cmd_task); | ||
603 | handle_cmd_task = GNUNET_SCHEDULER_NO_TASK; | ||
604 | } | ||
605 | free_user_list (); | ||
606 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
607 | GNUNET_free (room_name); | ||
608 | GNUNET_free (nickname); | ||
609 | } | ||
610 | |||
611 | |||
612 | void | ||
613 | handle_command (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
614 | { | ||
615 | char message[MAX_MESSAGE_LENGTH + 1]; | ||
616 | int i; | ||
617 | |||
618 | /* read message from command line and handle it */ | ||
619 | memset (message, 0, MAX_MESSAGE_LENGTH + 1); | ||
620 | if (NULL == fgets (message, MAX_MESSAGE_LENGTH, stdin)) | ||
621 | goto next; | ||
622 | if (strlen (message) == 0) | ||
623 | goto next; | ||
624 | if (message[strlen (message) - 1] == '\n') | ||
625 | message[strlen (message) - 1] = '\0'; | ||
626 | if (strlen (message) == 0) | ||
627 | goto next; | ||
628 | i = 0; | ||
629 | while ((NULL != commands[i].command) && | ||
630 | (0 != | ||
631 | strncasecmp (commands[i].command, message, | ||
632 | strlen (commands[i].command)))) | ||
633 | i++; | ||
634 | if (GNUNET_OK != | ||
635 | commands[i].Action (&message[strlen (commands[i].command)], NULL)) | ||
636 | goto out; | ||
637 | |||
638 | next: | ||
639 | handle_cmd_task = | ||
640 | GNUNET_SCHEDULER_add_delayed_with_priority (GNUNET_TIME_relative_multiply | ||
641 | (GNUNET_TIME_UNIT_MILLISECONDS, 100), | ||
642 | GNUNET_SCHEDULER_PRIORITY_UI, | ||
643 | &handle_command, NULL); | ||
644 | return; | ||
645 | |||
646 | out: | ||
647 | handle_cmd_task = GNUNET_SCHEDULER_NO_TASK; | ||
648 | GNUNET_SCHEDULER_shutdown (); | ||
649 | } | ||
650 | |||
651 | |||
652 | /** | ||
653 | * Main function that will be run by the scheduler. | ||
654 | * | ||
655 | * @param cls closure, NULL | ||
656 | * @param args remaining command-line arguments | ||
657 | * @param cfgfile name of the configuration file used (for saving, can be NULL!) | ||
658 | * @param c configuration | ||
659 | */ | ||
660 | static void | ||
661 | run (void *cls, char *const *args, const char *cfgfile, | ||
662 | const struct GNUNET_CONFIGURATION_Handle *c) | ||
663 | { | ||
664 | struct GNUNET_HashCode me; | ||
665 | char *my_name; | ||
666 | int my_name_is_a_dup; | ||
667 | |||
668 | cfg = c; | ||
669 | /* check arguments */ | ||
670 | if (NULL == nickname) | ||
671 | { | ||
672 | FPRINTF (stderr, "%s", _("You must specify a nickname\n")); | ||
673 | ret = -1; | ||
674 | return; | ||
675 | } | ||
676 | if (NULL == room_name) | ||
677 | room_name = GNUNET_strdup ("gnunet"); | ||
678 | meta = GNUNET_CONTAINER_meta_data_create (); | ||
679 | GNUNET_CONTAINER_meta_data_insert (meta, "<gnunet>", EXTRACTOR_METATYPE_TITLE, | ||
680 | EXTRACTOR_METAFORMAT_UTF8, "text/plain", | ||
681 | nickname, strlen (nickname) + 1); | ||
682 | room = | ||
683 | GNUNET_CHAT_join_room (cfg, nickname, meta, room_name, -1, &join_cb, NULL, | ||
684 | &receive_cb, NULL, &member_list_cb, NULL, | ||
685 | &confirmation_cb, NULL, &me); | ||
686 | if (NULL == room) | ||
687 | { | ||
688 | FPRINTF (stderr, _("Failed to join room `%s'\n"), room_name); | ||
689 | GNUNET_free (room_name); | ||
690 | GNUNET_free (nickname); | ||
691 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
692 | ret = -1; | ||
693 | return; | ||
694 | } | ||
695 | if ((GNUNET_OK != GNUNET_FS_pseudonym_get_info (cfg, | ||
696 | &me, NULL, NULL, &my_name, &my_name_is_a_dup)) || | ||
697 | (my_name_is_a_dup == GNUNET_YES)) | ||
698 | { | ||
699 | GNUNET_free (my_name); | ||
700 | my_name = GNUNET_strdup (_("anonymous")); | ||
701 | } | ||
702 | FPRINTF (stdout, _("Joining room `%s' as user `%s'...\n"), room_name, | ||
703 | my_name); | ||
704 | GNUNET_free (my_name); | ||
705 | handle_cmd_task = | ||
706 | GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_UI, | ||
707 | &handle_command, NULL); | ||
708 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &do_stop_task, | ||
709 | NULL); | ||
710 | } | ||
711 | |||
712 | |||
713 | /** | ||
714 | * The main function to chat via GNUnet. | ||
715 | * | ||
716 | * @param argc number of arguments from the command line | ||
717 | * @param argv command line arguments | ||
718 | * @return 0 ok, 1 on error | ||
719 | */ | ||
720 | int | ||
721 | main (int argc, char *const *argv) | ||
722 | { | ||
723 | int flags; | ||
724 | |||
725 | static const struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
726 | {'n', "nick", "NAME", | ||
727 | gettext_noop ("set the nickname to use (required)"), | ||
728 | 1, &GNUNET_GETOPT_set_string, &nickname}, | ||
729 | {'r', "room", "NAME", | ||
730 | gettext_noop ("set the chat room to join"), | ||
731 | 1, &GNUNET_GETOPT_set_string, &room_name}, | ||
732 | GNUNET_GETOPT_OPTION_END | ||
733 | }; | ||
734 | |||
735 | #ifndef WINDOWS | ||
736 | flags = fcntl (0, F_GETFL, 0); | ||
737 | flags |= O_NONBLOCK; | ||
738 | fcntl (0, F_SETFL, flags); | ||
739 | #endif | ||
740 | |||
741 | if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) | ||
742 | return 2; | ||
743 | |||
744 | return (GNUNET_OK == | ||
745 | GNUNET_PROGRAM_run (argc, argv, "gnunet-chat", | ||
746 | gettext_noop ("Join a chat on GNUnet."), options, | ||
747 | &run, NULL)) ? ret : 1; | ||
748 | } | ||
749 | |||
750 | /* end of gnunet-chat.c */ | ||
diff --git a/src/chat/gnunet-service-chat.c b/src/chat/gnunet-service-chat.c deleted file mode 100644 index 9c3fcfb39..000000000 --- a/src/chat/gnunet-service-chat.c +++ /dev/null | |||
@@ -1,1713 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2009, 2011 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file chat/gnunet-service-chat.c | ||
23 | * @brief service providing chat functionality | ||
24 | * @author Christian Grothoff | ||
25 | * @author Vitaly Minko | ||
26 | */ | ||
27 | |||
28 | #include "platform.h" | ||
29 | #include "gnunet_core_service.h" | ||
30 | #include "gnunet_crypto_lib.h" | ||
31 | #include "gnunet_protocols.h" | ||
32 | #include "gnunet_service_lib.h" | ||
33 | #include "gnunet_signatures.h" | ||
34 | #include "chat.h" | ||
35 | |||
36 | #define DEBUG_CHAT_SERVICE GNUNET_EXTRA_LOGGING | ||
37 | #define MAX_TRANSMIT_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) | ||
38 | #define EXPECTED_NEIGHBOUR_COUNT 16 | ||
39 | #define MAX_ANONYMOUS_MSG_LIST_LENGTH 16 | ||
40 | |||
41 | |||
42 | /** | ||
43 | * Linked list of our current clients. | ||
44 | */ | ||
45 | struct ChatClient | ||
46 | { | ||
47 | struct ChatClient *next; | ||
48 | |||
49 | /** | ||
50 | * Handle for a chat client (NULL for external clients). | ||
51 | */ | ||
52 | struct GNUNET_SERVER_Client *client; | ||
53 | |||
54 | /** | ||
55 | * Public key of the client. | ||
56 | */ | ||
57 | struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; | ||
58 | |||
59 | /** | ||
60 | * Name of the room which the client is in. | ||
61 | */ | ||
62 | char *room; | ||
63 | |||
64 | /** | ||
65 | * Serialized metadata of the client. | ||
66 | */ | ||
67 | char *member_info; | ||
68 | |||
69 | /** | ||
70 | * Hash of the public key (for convenience). | ||
71 | */ | ||
72 | struct GNUNET_HashCode id; | ||
73 | |||
74 | /** | ||
75 | * Options which the client is willing to receive. | ||
76 | */ | ||
77 | uint32_t msg_options; | ||
78 | |||
79 | /** | ||
80 | * Length of serialized metadata in member_info. | ||
81 | */ | ||
82 | uint16_t meta_len; | ||
83 | |||
84 | /** | ||
85 | * Sequence number of the last message sent by the client. | ||
86 | */ | ||
87 | uint32_t msg_sequence_number; | ||
88 | |||
89 | /** | ||
90 | * Sequence number of the last receipt sent by the client. | ||
91 | * Used to discard already processed receipts. | ||
92 | */ | ||
93 | uint32_t rcpt_sequence_number; | ||
94 | |||
95 | }; | ||
96 | |||
97 | /** | ||
98 | * Information about a peer that we are connected to. | ||
99 | * We track data that is useful for determining which | ||
100 | * peers should receive our requests. | ||
101 | */ | ||
102 | struct ConnectedPeer | ||
103 | { | ||
104 | /** | ||
105 | * The peer's identity. | ||
106 | */ | ||
107 | GNUNET_PEER_Id pid; | ||
108 | }; | ||
109 | |||
110 | /** | ||
111 | * Linked list of recent anonymous messages. | ||
112 | */ | ||
113 | struct AnonymousMessage | ||
114 | { | ||
115 | struct AnonymousMessage *next; | ||
116 | |||
117 | /** | ||
118 | * Hash of the message. | ||
119 | */ | ||
120 | struct GNUNET_HashCode hash; | ||
121 | |||
122 | }; | ||
123 | |||
124 | |||
125 | /** | ||
126 | * Handle to the core service (NULL until we've connected to it). | ||
127 | */ | ||
128 | static struct GNUNET_CORE_Handle *core; | ||
129 | |||
130 | /** | ||
131 | * Our configuration. | ||
132 | */ | ||
133 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
134 | |||
135 | /** | ||
136 | * The identity of this host. | ||
137 | */ | ||
138 | static struct GNUNET_PeerIdentity me; | ||
139 | |||
140 | /** | ||
141 | * Head of the list of current clients. | ||
142 | */ | ||
143 | static struct ChatClient *client_list_head = NULL; | ||
144 | |||
145 | /** | ||
146 | * Notification context containing all connected clients. | ||
147 | */ | ||
148 | struct GNUNET_SERVER_NotificationContext *nc = NULL; | ||
149 | |||
150 | /** | ||
151 | * Head of the list of recent anonymous messages. | ||
152 | */ | ||
153 | static struct AnonymousMessage *anonymous_list_head = NULL; | ||
154 | |||
155 | /** | ||
156 | * Map of peer identifiers to "struct ConnectedPeer" (for that peer). | ||
157 | */ | ||
158 | static struct GNUNET_CONTAINER_MultiHashMap *connected_peers; | ||
159 | |||
160 | |||
161 | static void | ||
162 | remember_anonymous_message (const struct P2PReceiveNotificationMessage | ||
163 | *p2p_rnmsg) | ||
164 | { | ||
165 | static struct GNUNET_HashCode hash; | ||
166 | struct AnonymousMessage *anon_msg; | ||
167 | struct AnonymousMessage *prev; | ||
168 | int anon_list_len; | ||
169 | |||
170 | GNUNET_CRYPTO_hash (p2p_rnmsg, ntohs (p2p_rnmsg->header.size), &hash); | ||
171 | anon_msg = GNUNET_malloc (sizeof (struct AnonymousMessage)); | ||
172 | anon_msg->hash = hash; | ||
173 | anon_msg->next = anonymous_list_head; | ||
174 | anonymous_list_head = anon_msg; | ||
175 | anon_list_len = 1; | ||
176 | prev = NULL; | ||
177 | while ((NULL != anon_msg->next)) | ||
178 | { | ||
179 | prev = anon_msg; | ||
180 | anon_msg = anon_msg->next; | ||
181 | anon_list_len++; | ||
182 | } | ||
183 | if (anon_list_len == MAX_ANONYMOUS_MSG_LIST_LENGTH) | ||
184 | { | ||
185 | GNUNET_free (anon_msg); | ||
186 | if (NULL != prev) | ||
187 | prev->next = NULL; | ||
188 | } | ||
189 | } | ||
190 | |||
191 | |||
192 | static int | ||
193 | lookup_anonymous_message (const struct P2PReceiveNotificationMessage *p2p_rnmsg) | ||
194 | { | ||
195 | static struct GNUNET_HashCode hash; | ||
196 | struct AnonymousMessage *anon_msg; | ||
197 | |||
198 | GNUNET_CRYPTO_hash (p2p_rnmsg, ntohs (p2p_rnmsg->header.size), &hash); | ||
199 | anon_msg = anonymous_list_head; | ||
200 | while ((NULL != anon_msg) && | ||
201 | (0 != memcmp (&anon_msg->hash, &hash, sizeof (struct GNUNET_HashCode)))) | ||
202 | anon_msg = anon_msg->next; | ||
203 | return (NULL != anon_msg); | ||
204 | } | ||
205 | |||
206 | |||
207 | /** | ||
208 | * Transmit a message notification to the peer. | ||
209 | * | ||
210 | * @param cls closure, pointer to the 'struct P2PReceiveNotificationMessage' | ||
211 | * @param size number of bytes available in buf | ||
212 | * @param buf where the callee should write the message | ||
213 | * @return number of bytes written to buf | ||
214 | */ | ||
215 | static size_t | ||
216 | transmit_message_notification_to_peer (void *cls, size_t size, void *buf) | ||
217 | { | ||
218 | struct P2PReceiveNotificationMessage *my_msg = cls; | ||
219 | struct P2PReceiveNotificationMessage *m = buf; | ||
220 | size_t msg_size; | ||
221 | |||
222 | #if DEBUG_CHAT_SERVICE | ||
223 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
224 | "Transmitting P2P message notification\n"); | ||
225 | #endif | ||
226 | if (buf == NULL) | ||
227 | { | ||
228 | /* client disconnected */ | ||
229 | #if DEBUG_CHAT_SERVICE | ||
230 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
231 | "Buffer is NULL, dropping the message\n"); | ||
232 | #endif | ||
233 | return 0; | ||
234 | } | ||
235 | msg_size = ntohs (my_msg->header.size); | ||
236 | GNUNET_assert (size >= msg_size); | ||
237 | memcpy (m, my_msg, msg_size); | ||
238 | GNUNET_free (my_msg); | ||
239 | return msg_size; | ||
240 | } | ||
241 | |||
242 | |||
243 | /** | ||
244 | * Ask to send a message notification to the peer. | ||
245 | */ | ||
246 | static int | ||
247 | send_message_noficiation (void *cls, const struct GNUNET_HashCode * key, void *value) | ||
248 | { | ||
249 | struct P2PReceiveNotificationMessage *msg = cls; | ||
250 | struct ConnectedPeer *cp = value; | ||
251 | struct GNUNET_PeerIdentity pid; | ||
252 | struct P2PReceiveNotificationMessage *my_msg; | ||
253 | |||
254 | GNUNET_PEER_resolve (cp->pid, &pid); | ||
255 | #if DEBUG_CHAT_SERVICE | ||
256 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message notification to `%s'\n", | ||
257 | GNUNET_i2s (&pid)); | ||
258 | #endif | ||
259 | my_msg = GNUNET_memdup (msg, ntohs (msg->header.size)); | ||
260 | if (NULL == | ||
261 | GNUNET_CORE_notify_transmit_ready (core, GNUNET_NO, 1, MAX_TRANSMIT_DELAY, | ||
262 | &pid, ntohs (msg->header.size), | ||
263 | &transmit_message_notification_to_peer, | ||
264 | my_msg)) | ||
265 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
266 | _("Failed to queue a message notification\n")); | ||
267 | return GNUNET_YES; | ||
268 | } | ||
269 | |||
270 | |||
271 | /** | ||
272 | * A client sent a chat message. Encrypt the message text if the message is | ||
273 | * private. Send the message to local room members and to all connected peers. | ||
274 | * | ||
275 | * @param cls closure, NULL | ||
276 | * @param client identification of the client | ||
277 | * @param message the actual message | ||
278 | */ | ||
279 | static void | ||
280 | handle_transmit_request (void *cls, struct GNUNET_SERVER_Client *client, | ||
281 | const struct GNUNET_MessageHeader *message) | ||
282 | { | ||
283 | static struct GNUNET_HashCode all_zeros; | ||
284 | const struct TransmitRequestMessage *trmsg; | ||
285 | struct ReceiveNotificationMessage *rnmsg; | ||
286 | struct P2PReceiveNotificationMessage *p2p_rnmsg; | ||
287 | struct ChatClient *pos; | ||
288 | struct ChatClient *target; | ||
289 | struct GNUNET_CRYPTO_AesSessionKey key; | ||
290 | char encrypted_msg[MAX_MESSAGE_LENGTH]; | ||
291 | const char *room; | ||
292 | size_t room_len; | ||
293 | int msg_len; | ||
294 | int is_priv; | ||
295 | int is_anon; | ||
296 | |||
297 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client sent a chat message\n"); | ||
298 | if (ntohs (message->size) <= sizeof (struct TransmitRequestMessage)) | ||
299 | { | ||
300 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n"); | ||
301 | GNUNET_break (0); | ||
302 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
303 | return; | ||
304 | } | ||
305 | trmsg = (const struct TransmitRequestMessage *) message; | ||
306 | msg_len = ntohs (trmsg->header.size) - sizeof (struct TransmitRequestMessage); | ||
307 | is_priv = (0 != (ntohl (trmsg->msg_options) & GNUNET_CHAT_MSG_PRIVATE)); | ||
308 | if (is_priv) | ||
309 | { | ||
310 | #if DEBUG_CHAT_SERVICE | ||
311 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypting the message text\n"); | ||
312 | #endif | ||
313 | GNUNET_CRYPTO_aes_create_session_key (&key); | ||
314 | msg_len = | ||
315 | GNUNET_CRYPTO_aes_encrypt (&trmsg[1], msg_len, &key, | ||
316 | (const struct | ||
317 | GNUNET_CRYPTO_AesInitializationVector *) | ||
318 | INITVALUE, encrypted_msg); | ||
319 | if (-1 == msg_len) | ||
320 | { | ||
321 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
322 | "Could not encrypt the message text\n"); | ||
323 | GNUNET_break (0); | ||
324 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
325 | return; | ||
326 | } | ||
327 | } | ||
328 | rnmsg = GNUNET_malloc (sizeof (struct ReceiveNotificationMessage) + msg_len); | ||
329 | rnmsg->header.size = | ||
330 | htons (sizeof (struct ReceiveNotificationMessage) + msg_len); | ||
331 | rnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION); | ||
332 | rnmsg->msg_options = trmsg->msg_options; | ||
333 | rnmsg->timestamp = trmsg->timestamp; | ||
334 | pos = client_list_head; | ||
335 | while ((NULL != pos) && (pos->client != client)) | ||
336 | pos = pos->next; | ||
337 | if (NULL == pos) | ||
338 | { | ||
339 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
340 | "The client is not a member of a chat room. Client has to " | ||
341 | "join a chat room first\n"); | ||
342 | GNUNET_break (0); | ||
343 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
344 | GNUNET_free (rnmsg); | ||
345 | return; | ||
346 | } | ||
347 | room = pos->room; | ||
348 | pos->msg_sequence_number = ntohl (trmsg->sequence_number); | ||
349 | is_anon = (0 != (ntohl (trmsg->msg_options) & GNUNET_CHAT_MSG_ANONYMOUS)); | ||
350 | if (is_anon) | ||
351 | { | ||
352 | memset (&rnmsg->sender, 0, sizeof (struct GNUNET_HashCode)); | ||
353 | rnmsg->sequence_number = 0; | ||
354 | } | ||
355 | else | ||
356 | { | ||
357 | rnmsg->sender = pos->id; | ||
358 | rnmsg->sequence_number = trmsg->sequence_number; | ||
359 | } | ||
360 | if (is_priv) | ||
361 | { | ||
362 | #if DEBUG_CHAT_SERVICE | ||
363 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
364 | "Encrypting the session key using the public key of '%s'\n", | ||
365 | GNUNET_h2s (&trmsg->target)); | ||
366 | #endif | ||
367 | if (0 == memcmp (&all_zeros, &trmsg->target, sizeof (struct GNUNET_HashCode))) | ||
368 | { | ||
369 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
370 | "Malformed message: private, but no target\n"); | ||
371 | GNUNET_break (0); | ||
372 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
373 | GNUNET_free (rnmsg); | ||
374 | return; | ||
375 | } | ||
376 | memcpy (&rnmsg[1], encrypted_msg, msg_len); | ||
377 | target = client_list_head; | ||
378 | while ((NULL != target) && | ||
379 | (0 != | ||
380 | memcmp (&target->id, &trmsg->target, sizeof (struct GNUNET_HashCode)))) | ||
381 | target = target->next; | ||
382 | if (NULL == target) | ||
383 | { | ||
384 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
385 | "Unknown target of the private message\n"); | ||
386 | GNUNET_break (0); | ||
387 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
388 | GNUNET_free (rnmsg); | ||
389 | return; | ||
390 | } | ||
391 | if (GNUNET_SYSERR == | ||
392 | GNUNET_CRYPTO_rsa_encrypt (&key, | ||
393 | sizeof (struct GNUNET_CRYPTO_AesSessionKey), | ||
394 | &target->public_key, &rnmsg->encrypted_key)) | ||
395 | { | ||
396 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
397 | "Could not encrypt the session key\n"); | ||
398 | GNUNET_break (0); | ||
399 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
400 | GNUNET_free (rnmsg); | ||
401 | return; | ||
402 | } | ||
403 | } | ||
404 | else | ||
405 | { | ||
406 | memcpy (&rnmsg[1], &trmsg[1], msg_len); | ||
407 | } | ||
408 | pos = client_list_head; | ||
409 | #if DEBUG_CHAT_SERVICE | ||
410 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
411 | "Sending message to local room members\n"); | ||
412 | #endif | ||
413 | while (NULL != pos) | ||
414 | { | ||
415 | if ((0 == strcmp (room, pos->room)) && (NULL != pos->client) && | ||
416 | (pos->client != client)) | ||
417 | { | ||
418 | if (((!is_priv) || | ||
419 | (0 == memcmp (&trmsg->target, &pos->id, sizeof (struct GNUNET_HashCode)))) | ||
420 | && (0 == (ntohl (trmsg->msg_options) & (~pos->msg_options)))) | ||
421 | { | ||
422 | GNUNET_SERVER_notification_context_unicast (nc, pos->client, | ||
423 | &rnmsg->header, GNUNET_NO); | ||
424 | } | ||
425 | } | ||
426 | pos = pos->next; | ||
427 | } | ||
428 | #if DEBUG_CHAT_SERVICE | ||
429 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
430 | "Broadcasting message to neighbour peers\n"); | ||
431 | #endif | ||
432 | if (is_anon) | ||
433 | { | ||
434 | room_len = strlen (room); | ||
435 | p2p_rnmsg = | ||
436 | GNUNET_malloc (sizeof (struct P2PReceiveNotificationMessage) + msg_len + | ||
437 | room_len); | ||
438 | p2p_rnmsg->header.size = | ||
439 | htons (sizeof (struct P2PReceiveNotificationMessage) + msg_len + | ||
440 | room_len); | ||
441 | p2p_rnmsg->room_name_len = htons (room_len); | ||
442 | memcpy ((char *) &p2p_rnmsg[1], room, room_len); | ||
443 | memcpy ((char *) &p2p_rnmsg[1] + room_len, &trmsg[1], msg_len); | ||
444 | } | ||
445 | else | ||
446 | { | ||
447 | p2p_rnmsg = | ||
448 | GNUNET_malloc (sizeof (struct P2PReceiveNotificationMessage) + msg_len); | ||
449 | p2p_rnmsg->header.size = | ||
450 | htons (sizeof (struct P2PReceiveNotificationMessage) + msg_len); | ||
451 | if (is_priv) | ||
452 | { | ||
453 | memcpy (&p2p_rnmsg[1], encrypted_msg, msg_len); | ||
454 | memcpy (&p2p_rnmsg->encrypted_key, &rnmsg->encrypted_key, | ||
455 | sizeof (struct GNUNET_CRYPTO_RsaEncryptedData)); | ||
456 | } | ||
457 | else | ||
458 | memcpy (&p2p_rnmsg[1], &trmsg[1], msg_len); | ||
459 | } | ||
460 | p2p_rnmsg->header.type = | ||
461 | htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_MESSAGE_NOTIFICATION); | ||
462 | p2p_rnmsg->msg_options = trmsg->msg_options; | ||
463 | p2p_rnmsg->sequence_number = trmsg->sequence_number; | ||
464 | p2p_rnmsg->timestamp = trmsg->timestamp; | ||
465 | p2p_rnmsg->reserved = htons (0); | ||
466 | p2p_rnmsg->sender = rnmsg->sender; | ||
467 | p2p_rnmsg->target = trmsg->target; | ||
468 | if (is_anon) | ||
469 | remember_anonymous_message (p2p_rnmsg); | ||
470 | GNUNET_CONTAINER_multihashmap_iterate (connected_peers, | ||
471 | &send_message_noficiation, p2p_rnmsg); | ||
472 | GNUNET_free (p2p_rnmsg); | ||
473 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
474 | GNUNET_free (rnmsg); | ||
475 | } | ||
476 | |||
477 | |||
478 | /** | ||
479 | * Transmit a join notification to the peer. | ||
480 | * | ||
481 | * @param cls closure, pointer to the 'struct ChatClient' | ||
482 | * @param size number of bytes available in buf | ||
483 | * @param buf where the callee should write the message | ||
484 | * @return number of bytes written to buf | ||
485 | */ | ||
486 | static size_t | ||
487 | transmit_join_notification_to_peer (void *cls, size_t size, void *buf) | ||
488 | { | ||
489 | struct ChatClient *entry = cls; | ||
490 | struct P2PJoinNotificationMessage *m = buf; | ||
491 | size_t room_len; | ||
492 | size_t meta_len; | ||
493 | size_t msg_size; | ||
494 | char *roomptr; | ||
495 | |||
496 | #if DEBUG_CHAT_SERVICE | ||
497 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting P2P join notification\n"); | ||
498 | #endif | ||
499 | room_len = strlen (entry->room); | ||
500 | meta_len = entry->meta_len; | ||
501 | msg_size = sizeof (struct P2PJoinNotificationMessage) + meta_len + room_len; | ||
502 | GNUNET_assert (size >= msg_size); | ||
503 | GNUNET_assert (NULL != buf); | ||
504 | m = buf; | ||
505 | m->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_JOIN_NOTIFICATION); | ||
506 | m->header.size = htons (msg_size); | ||
507 | m->msg_options = htonl (entry->msg_options); | ||
508 | m->room_name_len = htons (room_len); | ||
509 | m->reserved = htons (0); | ||
510 | m->reserved2 = htonl (0); | ||
511 | m->public_key = entry->public_key; | ||
512 | roomptr = (char *) &m[1]; | ||
513 | memcpy (roomptr, entry->room, room_len); | ||
514 | if (meta_len > 0) | ||
515 | memcpy (&roomptr[room_len], entry->member_info, meta_len); | ||
516 | return msg_size; | ||
517 | } | ||
518 | |||
519 | |||
520 | /** | ||
521 | * Ask to send a join notification to the peer. | ||
522 | */ | ||
523 | static int | ||
524 | send_join_noficiation (void *cls, const struct GNUNET_HashCode * key, void *value) | ||
525 | { | ||
526 | struct ChatClient *entry = cls; | ||
527 | struct ConnectedPeer *cp = value; | ||
528 | struct GNUNET_PeerIdentity pid; | ||
529 | size_t msg_size; | ||
530 | |||
531 | GNUNET_PEER_resolve (cp->pid, &pid); | ||
532 | #if DEBUG_CHAT_SERVICE | ||
533 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending join notification to `%s'\n", | ||
534 | GNUNET_i2s (&pid)); | ||
535 | #endif | ||
536 | msg_size = | ||
537 | sizeof (struct P2PJoinNotificationMessage) + strlen (entry->room) + | ||
538 | entry->meta_len; | ||
539 | if (NULL == | ||
540 | GNUNET_CORE_notify_transmit_ready (core, GNUNET_NO, 1, MAX_TRANSMIT_DELAY, | ||
541 | &pid, msg_size, | ||
542 | &transmit_join_notification_to_peer, | ||
543 | entry)) | ||
544 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
545 | _("Failed to queue a join notification\n")); | ||
546 | return GNUNET_YES; | ||
547 | } | ||
548 | |||
549 | |||
550 | /** | ||
551 | * A client asked for entering a chat room. Add the new member to the list of | ||
552 | * clients and notify remaining room members. | ||
553 | * | ||
554 | * @param cls closure, NULL | ||
555 | * @param client identification of the client | ||
556 | * @param message the actual message | ||
557 | */ | ||
558 | static void | ||
559 | handle_join_request (void *cls, struct GNUNET_SERVER_Client *client, | ||
560 | const struct GNUNET_MessageHeader *message) | ||
561 | { | ||
562 | const struct JoinRequestMessage *jrmsg; | ||
563 | char *room_name; | ||
564 | const char *roomptr; | ||
565 | uint16_t header_size; | ||
566 | uint16_t meta_len; | ||
567 | uint16_t room_name_len; | ||
568 | struct ChatClient *new_entry; | ||
569 | struct ChatClient *entry; | ||
570 | struct JoinNotificationMessage *jnmsg; | ||
571 | struct JoinNotificationMessage *entry_jnmsg; | ||
572 | |||
573 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client sent a join request\n"); | ||
574 | if (ntohs (message->size) <= sizeof (struct JoinRequestMessage)) | ||
575 | { | ||
576 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n"); | ||
577 | GNUNET_break (0); | ||
578 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
579 | return; | ||
580 | } | ||
581 | jrmsg = (const struct JoinRequestMessage *) message; | ||
582 | header_size = ntohs (jrmsg->header.size); | ||
583 | room_name_len = ntohs (jrmsg->room_name_len); | ||
584 | if (header_size - sizeof (struct JoinRequestMessage) <= room_name_len) | ||
585 | { | ||
586 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
587 | "Malformed message: wrong length of the room name\n"); | ||
588 | GNUNET_break (0); | ||
589 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
590 | return; | ||
591 | } | ||
592 | meta_len = header_size - sizeof (struct JoinRequestMessage) - room_name_len; | ||
593 | roomptr = (const char *) &jrmsg[1]; | ||
594 | room_name = GNUNET_malloc (room_name_len + 1); | ||
595 | memcpy (room_name, roomptr, room_name_len); | ||
596 | room_name[room_name_len] = '\0'; | ||
597 | new_entry = GNUNET_malloc (sizeof (struct ChatClient)); | ||
598 | memset (new_entry, 0, sizeof (struct ChatClient)); | ||
599 | new_entry->client = client; | ||
600 | new_entry->room = room_name; | ||
601 | new_entry->public_key = jrmsg->public_key; | ||
602 | new_entry->meta_len = meta_len; | ||
603 | if (meta_len > 0) | ||
604 | { | ||
605 | new_entry->member_info = GNUNET_malloc (meta_len); | ||
606 | memcpy (new_entry->member_info, &roomptr[room_name_len], meta_len); | ||
607 | } | ||
608 | else | ||
609 | new_entry->member_info = NULL; | ||
610 | GNUNET_CRYPTO_hash (&new_entry->public_key, | ||
611 | sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), | ||
612 | &new_entry->id); | ||
613 | new_entry->msg_options = ntohl (jrmsg->msg_options); | ||
614 | new_entry->next = client_list_head; | ||
615 | client_list_head = new_entry; | ||
616 | #if DEBUG_CHAT_SERVICE | ||
617 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
618 | "Synchronizing room members between local clients\n"); | ||
619 | #endif | ||
620 | jnmsg = GNUNET_malloc (sizeof (struct JoinNotificationMessage) + meta_len); | ||
621 | jnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION); | ||
622 | jnmsg->header.size = | ||
623 | htons (sizeof (struct JoinNotificationMessage) + meta_len); | ||
624 | jnmsg->msg_options = jrmsg->msg_options; | ||
625 | jnmsg->public_key = new_entry->public_key; | ||
626 | memcpy (&jnmsg[1], &roomptr[room_name_len], meta_len); | ||
627 | GNUNET_SERVER_notification_context_add (nc, client); | ||
628 | entry = client_list_head; | ||
629 | while (NULL != entry) | ||
630 | { | ||
631 | if (0 == strcmp (room_name, entry->room)) | ||
632 | { | ||
633 | if (NULL != entry->client) | ||
634 | GNUNET_SERVER_notification_context_unicast (nc, entry->client, | ||
635 | &jnmsg->header, GNUNET_NO); | ||
636 | if (entry->client != client) | ||
637 | { | ||
638 | entry_jnmsg = | ||
639 | GNUNET_malloc (sizeof (struct JoinNotificationMessage) + | ||
640 | entry->meta_len); | ||
641 | entry_jnmsg->header.type = | ||
642 | htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION); | ||
643 | entry_jnmsg->header.size = | ||
644 | htons (sizeof (struct JoinNotificationMessage) + entry->meta_len); | ||
645 | entry_jnmsg->msg_options = entry->msg_options; | ||
646 | entry_jnmsg->public_key = entry->public_key; | ||
647 | memcpy (&entry_jnmsg[1], entry->member_info, entry->meta_len); | ||
648 | GNUNET_SERVER_notification_context_unicast (nc, client, | ||
649 | &entry_jnmsg->header, | ||
650 | GNUNET_NO); | ||
651 | GNUNET_free (entry_jnmsg); | ||
652 | } | ||
653 | } | ||
654 | entry = entry->next; | ||
655 | } | ||
656 | #if DEBUG_CHAT_SERVICE | ||
657 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
658 | "Broadcasting join notification to neighbour peers\n"); | ||
659 | #endif | ||
660 | GNUNET_CONTAINER_multihashmap_iterate (connected_peers, | ||
661 | &send_join_noficiation, new_entry); | ||
662 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
663 | GNUNET_free (jnmsg); | ||
664 | } | ||
665 | |||
666 | /** | ||
667 | * Transmit a confirmation receipt to the peer. | ||
668 | * | ||
669 | * @param cls closure, pointer to the 'struct P2PConfirmationReceiptMessage' | ||
670 | * @param size number of bytes available in buf | ||
671 | * @param buf where the callee should write the message | ||
672 | * @return number of bytes written to buf | ||
673 | */ | ||
674 | static size_t | ||
675 | transmit_confirmation_receipt_to_peer (void *cls, size_t size, void *buf) | ||
676 | { | ||
677 | struct P2PConfirmationReceiptMessage *receipt = cls; | ||
678 | size_t msg_size; | ||
679 | |||
680 | #if DEBUG_CHAT_SERVICE | ||
681 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
682 | "Transmitting P2P confirmation receipt to '%s'\n", | ||
683 | GNUNET_h2s (&receipt->target)); | ||
684 | #endif | ||
685 | if (buf == NULL) | ||
686 | { | ||
687 | /* client disconnected */ | ||
688 | #if DEBUG_CHAT_SERVICE | ||
689 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
690 | "Buffer is NULL, dropping the message\n"); | ||
691 | #endif | ||
692 | return 0; | ||
693 | } | ||
694 | msg_size = sizeof (struct P2PConfirmationReceiptMessage); | ||
695 | GNUNET_assert (size >= msg_size); | ||
696 | memcpy (buf, receipt, msg_size); | ||
697 | GNUNET_free (receipt); | ||
698 | return msg_size; | ||
699 | } | ||
700 | |||
701 | |||
702 | /** | ||
703 | * Ask to send a confirmation receipt to the peer. | ||
704 | */ | ||
705 | static int | ||
706 | send_confirmation_receipt (void *cls, const struct GNUNET_HashCode * key, void *value) | ||
707 | { | ||
708 | struct P2PConfirmationReceiptMessage *receipt = cls; | ||
709 | struct ConnectedPeer *cp = value; | ||
710 | struct GNUNET_PeerIdentity pid; | ||
711 | struct P2PConfirmationReceiptMessage *my_receipt; | ||
712 | size_t msg_size; | ||
713 | |||
714 | GNUNET_PEER_resolve (cp->pid, &pid); | ||
715 | #if DEBUG_CHAT_SERVICE | ||
716 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending confirmation receipt to `%s'\n", | ||
717 | GNUNET_i2s (&pid)); | ||
718 | #endif | ||
719 | msg_size = sizeof (struct P2PConfirmationReceiptMessage); | ||
720 | my_receipt = | ||
721 | GNUNET_memdup (receipt, sizeof (struct P2PConfirmationReceiptMessage)); | ||
722 | if (NULL == | ||
723 | GNUNET_CORE_notify_transmit_ready (core, GNUNET_YES, 1, | ||
724 | MAX_TRANSMIT_DELAY, &pid, msg_size, | ||
725 | &transmit_confirmation_receipt_to_peer, | ||
726 | my_receipt)) | ||
727 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
728 | _("Failed to queue a confirmation receipt\n")); | ||
729 | return GNUNET_YES; | ||
730 | } | ||
731 | |||
732 | |||
733 | /** | ||
734 | * A client sent a confirmation receipt. Broadcast the receipt to all connected | ||
735 | * peers if the author of the original message is a local client. Otherwise | ||
736 | * check the signature and notify the user if the signature is valid. | ||
737 | * | ||
738 | * @param cls closure, NULL | ||
739 | * @param client identification of the client | ||
740 | * @param message the actual message | ||
741 | */ | ||
742 | static void | ||
743 | handle_acknowledge_request (void *cls, struct GNUNET_SERVER_Client *client, | ||
744 | const struct GNUNET_MessageHeader *message) | ||
745 | { | ||
746 | const struct ConfirmationReceiptMessage *receipt; | ||
747 | struct ConfirmationReceiptMessage *crmsg; | ||
748 | struct P2PConfirmationReceiptMessage *p2p_crmsg; | ||
749 | struct ChatClient *target; | ||
750 | struct ChatClient *author; | ||
751 | |||
752 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client sent a confirmation receipt\n"); | ||
753 | receipt = (const struct ConfirmationReceiptMessage *) message; | ||
754 | author = client_list_head; | ||
755 | while ((NULL != author) && | ||
756 | (0 != | ||
757 | memcmp (&receipt->author, &author->id, sizeof (struct GNUNET_HashCode)))) | ||
758 | author = author->next; | ||
759 | if (NULL == author) | ||
760 | { | ||
761 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
762 | "Unknown author of the original message\n"); | ||
763 | GNUNET_break (0); | ||
764 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
765 | return; | ||
766 | } | ||
767 | target = client_list_head; | ||
768 | while ((NULL != target) && | ||
769 | (0 != | ||
770 | memcmp (&receipt->target, &target->id, sizeof (struct GNUNET_HashCode)))) | ||
771 | target = target->next; | ||
772 | if (NULL == target) | ||
773 | { | ||
774 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
775 | "Unknown target of the confirmation receipt\n"); | ||
776 | GNUNET_break (0); | ||
777 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
778 | return; | ||
779 | } | ||
780 | if (NULL == author->client) | ||
781 | { | ||
782 | target->rcpt_sequence_number++; | ||
783 | #if DEBUG_CHAT_SERVICE | ||
784 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
785 | "Broadcasting %s's receipt #%u to neighbour peers\n", | ||
786 | GNUNET_h2s (&target->id), target->rcpt_sequence_number); | ||
787 | #endif | ||
788 | p2p_crmsg = GNUNET_malloc (sizeof (struct P2PConfirmationReceiptMessage)); | ||
789 | p2p_crmsg->header.size = | ||
790 | htons (sizeof (struct P2PConfirmationReceiptMessage)); | ||
791 | p2p_crmsg->header.type = | ||
792 | htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_CONFIRMATION_RECEIPT); | ||
793 | p2p_crmsg->reserved = htonl (0); | ||
794 | p2p_crmsg->signature = receipt->signature; | ||
795 | p2p_crmsg->purpose = receipt->purpose; | ||
796 | p2p_crmsg->msg_sequence_number = receipt->sequence_number; | ||
797 | p2p_crmsg->timestamp = receipt->timestamp; | ||
798 | p2p_crmsg->target = receipt->target; | ||
799 | p2p_crmsg->author = receipt->author; | ||
800 | p2p_crmsg->content = receipt->content; | ||
801 | p2p_crmsg->sequence_number = htonl (target->rcpt_sequence_number); | ||
802 | GNUNET_CONTAINER_multihashmap_iterate (connected_peers, | ||
803 | &send_confirmation_receipt, | ||
804 | p2p_crmsg); | ||
805 | GNUNET_free (p2p_crmsg); | ||
806 | } | ||
807 | else | ||
808 | { | ||
809 | #if DEBUG_CHAT_SERVICE | ||
810 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
811 | "Verifying signature of the receipt\n"); | ||
812 | #endif | ||
813 | if (GNUNET_OK != | ||
814 | GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_CHAT_RECEIPT, | ||
815 | &receipt->purpose, &receipt->signature, | ||
816 | &target->public_key)) | ||
817 | { | ||
818 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
819 | "Invalid signature of the receipt\n"); | ||
820 | GNUNET_break (0); | ||
821 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
822 | return; | ||
823 | } | ||
824 | #if DEBUG_CHAT_SERVICE | ||
825 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
826 | "Sending receipt to the client which sent the original message\n"); | ||
827 | #endif | ||
828 | crmsg = GNUNET_memdup (receipt, sizeof (struct ConfirmationReceiptMessage)); | ||
829 | crmsg->header.type = | ||
830 | htons (GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION); | ||
831 | GNUNET_SERVER_notification_context_unicast (nc, author->client, | ||
832 | &crmsg->header, GNUNET_NO); | ||
833 | GNUNET_free (crmsg); | ||
834 | } | ||
835 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
836 | } | ||
837 | |||
838 | |||
839 | /** | ||
840 | * Transmit a leave notification to the peer. | ||
841 | * | ||
842 | * @param cls closure, pointer to the | ||
843 | * 'struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded' | ||
844 | * @param size number of bytes available in buf | ||
845 | * @param buf where the callee should write the message | ||
846 | * @return number of bytes written to buf | ||
847 | */ | ||
848 | static size_t | ||
849 | transmit_leave_notification_to_peer (void *cls, size_t size, void *buf) | ||
850 | { | ||
851 | struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key = cls; | ||
852 | struct P2PLeaveNotificationMessage *m = buf; | ||
853 | size_t msg_size; | ||
854 | |||
855 | #if DEBUG_CHAT_SERVICE | ||
856 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting P2P leave notification\n"); | ||
857 | #endif | ||
858 | if (buf == NULL) | ||
859 | { | ||
860 | /* client disconnected */ | ||
861 | #if DEBUG_CHAT_SERVICE | ||
862 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
863 | "Buffer is NULL, dropping the message\n"); | ||
864 | #endif | ||
865 | return 0; | ||
866 | } | ||
867 | msg_size = sizeof (struct P2PLeaveNotificationMessage); | ||
868 | GNUNET_assert (size >= msg_size); | ||
869 | m = buf; | ||
870 | m->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_LEAVE_NOTIFICATION); | ||
871 | m->header.size = htons (msg_size); | ||
872 | m->reserved = htonl (0); | ||
873 | m->user = *public_key; | ||
874 | GNUNET_free (public_key); | ||
875 | return msg_size; | ||
876 | } | ||
877 | |||
878 | |||
879 | /** | ||
880 | * Ask to send a leave notification to the peer. | ||
881 | */ | ||
882 | static int | ||
883 | send_leave_noficiation (void *cls, const struct GNUNET_HashCode * key, void *value) | ||
884 | { | ||
885 | struct ChatClient *entry = cls; | ||
886 | struct ConnectedPeer *cp = value; | ||
887 | struct GNUNET_PeerIdentity pid; | ||
888 | struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key; | ||
889 | size_t msg_size; | ||
890 | |||
891 | GNUNET_PEER_resolve (cp->pid, &pid); | ||
892 | #if DEBUG_CHAT_SERVICE | ||
893 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending leave notification to `%s'\n", | ||
894 | GNUNET_i2s (&pid)); | ||
895 | #endif | ||
896 | msg_size = sizeof (struct P2PLeaveNotificationMessage); | ||
897 | public_key = | ||
898 | GNUNET_memdup (&entry->public_key, | ||
899 | sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); | ||
900 | if (NULL == | ||
901 | GNUNET_CORE_notify_transmit_ready (core, GNUNET_YES, 1, | ||
902 | MAX_TRANSMIT_DELAY, &pid, msg_size, | ||
903 | &transmit_leave_notification_to_peer, | ||
904 | public_key)) | ||
905 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
906 | _("Failed to queue a leave notification\n")); | ||
907 | return GNUNET_YES; | ||
908 | } | ||
909 | |||
910 | |||
911 | /** | ||
912 | * A client disconnected. Remove all of its data structure entries and notify | ||
913 | * remaining room members. | ||
914 | * | ||
915 | * @param cls closure, NULL | ||
916 | * @param client identification of the client | ||
917 | */ | ||
918 | static void | ||
919 | handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) | ||
920 | { | ||
921 | struct ChatClient *entry; | ||
922 | struct ChatClient *pos; | ||
923 | struct ChatClient *prev; | ||
924 | struct LeaveNotificationMessage lnmsg; | ||
925 | |||
926 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client disconnected\n"); | ||
927 | pos = client_list_head; | ||
928 | prev = NULL; | ||
929 | while ((NULL != pos) && (pos->client != client)) | ||
930 | { | ||
931 | prev = pos; | ||
932 | pos = pos->next; | ||
933 | } | ||
934 | if (NULL == pos) | ||
935 | { | ||
936 | #if DEBUG_CHAT_SERVICE | ||
937 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
938 | "No such client. There is nothing to do\n"); | ||
939 | #endif | ||
940 | return; | ||
941 | } | ||
942 | if (NULL == prev) | ||
943 | client_list_head = pos->next; | ||
944 | else | ||
945 | prev->next = pos->next; | ||
946 | entry = client_list_head; | ||
947 | #if DEBUG_CHAT_SERVICE | ||
948 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
949 | "Notifying local room members that the client has disconnected\n"); | ||
950 | #endif | ||
951 | lnmsg.header.size = htons (sizeof (struct LeaveNotificationMessage)); | ||
952 | lnmsg.header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION); | ||
953 | lnmsg.reserved = htonl (0); | ||
954 | lnmsg.user = pos->public_key; | ||
955 | while (NULL != entry) | ||
956 | { | ||
957 | if ((0 == strcmp (pos->room, entry->room)) && (NULL != entry->client)) | ||
958 | { | ||
959 | GNUNET_SERVER_notification_context_unicast (nc, entry->client, | ||
960 | &lnmsg.header, GNUNET_NO); | ||
961 | } | ||
962 | entry = entry->next; | ||
963 | } | ||
964 | #if DEBUG_CHAT_SERVICE | ||
965 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
966 | "Broadcasting leave notification to neighbour peers\n"); | ||
967 | #endif | ||
968 | GNUNET_CONTAINER_multihashmap_iterate (connected_peers, | ||
969 | &send_leave_noficiation, pos); | ||
970 | GNUNET_free (pos->room); | ||
971 | GNUNET_free_non_null (pos->member_info); | ||
972 | GNUNET_free (pos); | ||
973 | } | ||
974 | |||
975 | |||
976 | /** | ||
977 | * Handle P2P join notification. | ||
978 | * | ||
979 | * @param cls closure, always NULL | ||
980 | * @param other the other peer involved | ||
981 | * @param message the actual message | ||
982 | |||
983 | * @return GNUNET_OK to keep the connection open, | ||
984 | * GNUNET_SYSERR to close it (signal serious error) | ||
985 | */ | ||
986 | static int | ||
987 | handle_p2p_join_notification (void *cls, | ||
988 | const struct GNUNET_PeerIdentity *other, | ||
989 | const struct GNUNET_MessageHeader *message) | ||
990 | { | ||
991 | const struct P2PJoinNotificationMessage *p2p_jnmsg; | ||
992 | char *room_name; | ||
993 | const char *roomptr; | ||
994 | uint16_t header_size; | ||
995 | uint16_t meta_len; | ||
996 | uint16_t room_name_len; | ||
997 | struct ChatClient *new_entry; | ||
998 | struct ChatClient *entry; | ||
999 | struct JoinNotificationMessage *jnmsg; | ||
1000 | struct GNUNET_HashCode id; | ||
1001 | |||
1002 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P join notification\n"); | ||
1003 | if (ntohs (message->size) <= sizeof (struct P2PJoinNotificationMessage)) | ||
1004 | { | ||
1005 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n"); | ||
1006 | GNUNET_break_op (0); | ||
1007 | return GNUNET_SYSERR; | ||
1008 | } | ||
1009 | p2p_jnmsg = (const struct P2PJoinNotificationMessage *) message; | ||
1010 | header_size = ntohs (p2p_jnmsg->header.size); | ||
1011 | room_name_len = ntohs (p2p_jnmsg->room_name_len); | ||
1012 | if (header_size - sizeof (struct P2PJoinNotificationMessage) <= room_name_len) | ||
1013 | { | ||
1014 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1015 | "Malformed message: wrong length of the room name\n"); | ||
1016 | GNUNET_break_op (0); | ||
1017 | return GNUNET_SYSERR; | ||
1018 | } | ||
1019 | GNUNET_CRYPTO_hash (&p2p_jnmsg->public_key, | ||
1020 | sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), | ||
1021 | &id); | ||
1022 | entry = client_list_head; | ||
1023 | while (NULL != entry) | ||
1024 | { | ||
1025 | if (0 == memcmp (&entry->id, &id, sizeof (struct GNUNET_HashCode))) | ||
1026 | { | ||
1027 | #if DEBUG_CHAT_SERVICE | ||
1028 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1029 | "The client has already joined. There is nothing to do\n"); | ||
1030 | #endif | ||
1031 | return GNUNET_OK; | ||
1032 | } | ||
1033 | entry = entry->next; | ||
1034 | } | ||
1035 | meta_len = | ||
1036 | header_size - sizeof (struct P2PJoinNotificationMessage) - room_name_len; | ||
1037 | roomptr = (const char *) &p2p_jnmsg[1]; | ||
1038 | room_name = GNUNET_malloc (room_name_len + 1); | ||
1039 | memcpy (room_name, roomptr, room_name_len); | ||
1040 | room_name[room_name_len] = '\0'; | ||
1041 | new_entry = GNUNET_malloc (sizeof (struct ChatClient)); | ||
1042 | memset (new_entry, 0, sizeof (struct ChatClient)); | ||
1043 | new_entry->id = id; | ||
1044 | new_entry->client = NULL; | ||
1045 | new_entry->room = room_name; | ||
1046 | new_entry->public_key = p2p_jnmsg->public_key; | ||
1047 | new_entry->meta_len = meta_len; | ||
1048 | if (meta_len > 0) | ||
1049 | { | ||
1050 | new_entry->member_info = GNUNET_malloc (meta_len); | ||
1051 | memcpy (new_entry->member_info, &roomptr[room_name_len], meta_len); | ||
1052 | } | ||
1053 | else | ||
1054 | new_entry->member_info = NULL; | ||
1055 | new_entry->msg_options = ntohl (p2p_jnmsg->msg_options); | ||
1056 | new_entry->next = client_list_head; | ||
1057 | client_list_head = new_entry; | ||
1058 | #if DEBUG_CHAT_SERVICE | ||
1059 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1060 | "Notifying local room members that we have a new client\n"); | ||
1061 | #endif | ||
1062 | jnmsg = GNUNET_malloc (sizeof (struct JoinNotificationMessage) + meta_len); | ||
1063 | jnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION); | ||
1064 | jnmsg->header.size = | ||
1065 | htons (sizeof (struct JoinNotificationMessage) + meta_len); | ||
1066 | jnmsg->msg_options = p2p_jnmsg->msg_options; | ||
1067 | jnmsg->public_key = new_entry->public_key; | ||
1068 | memcpy (&jnmsg[1], &roomptr[room_name_len], meta_len); | ||
1069 | entry = client_list_head; | ||
1070 | while (NULL != entry) | ||
1071 | { | ||
1072 | if ((0 == strcmp (room_name, entry->room)) && (NULL != entry->client)) | ||
1073 | { | ||
1074 | GNUNET_SERVER_notification_context_unicast (nc, entry->client, | ||
1075 | &jnmsg->header, GNUNET_NO); | ||
1076 | } | ||
1077 | entry = entry->next; | ||
1078 | } | ||
1079 | #if DEBUG_CHAT_SERVICE | ||
1080 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1081 | "Broadcasting join notification to neighbour peers\n"); | ||
1082 | #endif | ||
1083 | GNUNET_CONTAINER_multihashmap_iterate (connected_peers, | ||
1084 | &send_join_noficiation, new_entry); | ||
1085 | GNUNET_free (jnmsg); | ||
1086 | return GNUNET_OK; | ||
1087 | } | ||
1088 | |||
1089 | |||
1090 | /** | ||
1091 | * Handle P2P leave notification. | ||
1092 | * | ||
1093 | * @param cls closure, always NULL | ||
1094 | * @param other the other peer involved | ||
1095 | * @param message the actual message | ||
1096 | * @return GNUNET_OK to keep the connection open, | ||
1097 | * GNUNET_SYSERR to close it (signal serious error) | ||
1098 | */ | ||
1099 | static int | ||
1100 | handle_p2p_leave_notification (void *cls, | ||
1101 | const struct GNUNET_PeerIdentity *other, | ||
1102 | const struct GNUNET_MessageHeader *message) | ||
1103 | { | ||
1104 | const struct P2PLeaveNotificationMessage *p2p_lnmsg; | ||
1105 | struct GNUNET_HashCode id; | ||
1106 | struct ChatClient *pos; | ||
1107 | struct ChatClient *prev; | ||
1108 | struct ChatClient *entry; | ||
1109 | struct LeaveNotificationMessage lnmsg; | ||
1110 | |||
1111 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P leave notification\n"); | ||
1112 | p2p_lnmsg = (const struct P2PLeaveNotificationMessage *) message; | ||
1113 | GNUNET_CRYPTO_hash (&p2p_lnmsg->user, | ||
1114 | sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), | ||
1115 | &id); | ||
1116 | pos = client_list_head; | ||
1117 | prev = NULL; | ||
1118 | while (NULL != pos) | ||
1119 | { | ||
1120 | if (0 == memcmp (&pos->id, &id, sizeof (struct GNUNET_HashCode))) | ||
1121 | break; | ||
1122 | prev = pos; | ||
1123 | pos = pos->next; | ||
1124 | } | ||
1125 | if (NULL == pos) | ||
1126 | { | ||
1127 | #if DEBUG_CHAT_SERVICE | ||
1128 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1129 | "No such client. There is nothing to do\n"); | ||
1130 | #endif | ||
1131 | return GNUNET_OK; | ||
1132 | } | ||
1133 | if (NULL == prev) | ||
1134 | client_list_head = pos->next; | ||
1135 | else | ||
1136 | prev->next = pos->next; | ||
1137 | #if DEBUG_CHAT_SERVICE | ||
1138 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1139 | "Notifying local room members that the client has gone away\n"); | ||
1140 | #endif | ||
1141 | lnmsg.header.size = htons (sizeof (struct LeaveNotificationMessage)); | ||
1142 | lnmsg.header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION); | ||
1143 | lnmsg.reserved = htonl (0); | ||
1144 | lnmsg.user = pos->public_key; | ||
1145 | entry = client_list_head; | ||
1146 | while (NULL != entry) | ||
1147 | { | ||
1148 | if (0 == strcmp (pos->room, entry->room) && (NULL != entry->client)) | ||
1149 | { | ||
1150 | GNUNET_SERVER_notification_context_unicast (nc, entry->client, | ||
1151 | &lnmsg.header, GNUNET_NO); | ||
1152 | } | ||
1153 | entry = entry->next; | ||
1154 | } | ||
1155 | #if DEBUG_CHAT_SERVICE | ||
1156 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1157 | "Broadcasting leave notification to neighbour peers\n"); | ||
1158 | #endif | ||
1159 | GNUNET_CONTAINER_multihashmap_iterate (connected_peers, | ||
1160 | &send_leave_noficiation, pos); | ||
1161 | GNUNET_free (pos->room); | ||
1162 | GNUNET_free_non_null (pos->member_info); | ||
1163 | GNUNET_free (pos); | ||
1164 | return GNUNET_OK; | ||
1165 | } | ||
1166 | |||
1167 | |||
1168 | /** | ||
1169 | * Handle P2P message notification. | ||
1170 | * | ||
1171 | * @param cls closure, always NULL | ||
1172 | * @param other the other peer involved | ||
1173 | * @param message the actual message | ||
1174 | * @return GNUNET_OK to keep the connection open, | ||
1175 | * GNUNET_SYSERR to close it (signal serious error) | ||
1176 | */ | ||
1177 | static int | ||
1178 | handle_p2p_message_notification (void *cls, | ||
1179 | const struct GNUNET_PeerIdentity *other, | ||
1180 | const struct GNUNET_MessageHeader *message) | ||
1181 | { | ||
1182 | const struct P2PReceiveNotificationMessage *p2p_rnmsg; | ||
1183 | struct P2PReceiveNotificationMessage *my_p2p_rnmsg; | ||
1184 | struct ReceiveNotificationMessage *rnmsg; | ||
1185 | struct ChatClient *sender; | ||
1186 | struct ChatClient *pos; | ||
1187 | static struct GNUNET_HashCode all_zeros; | ||
1188 | int is_priv; | ||
1189 | int is_anon; | ||
1190 | uint16_t msg_len; | ||
1191 | uint16_t room_name_len; | ||
1192 | char *room_name = NULL; | ||
1193 | char *text; | ||
1194 | |||
1195 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P message notification\n"); | ||
1196 | if (ntohs (message->size) <= sizeof (struct P2PReceiveNotificationMessage)) | ||
1197 | { | ||
1198 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n"); | ||
1199 | GNUNET_break_op (0); | ||
1200 | return GNUNET_SYSERR; | ||
1201 | } | ||
1202 | p2p_rnmsg = (const struct P2PReceiveNotificationMessage *) message; | ||
1203 | msg_len = | ||
1204 | ntohs (p2p_rnmsg->header.size) - | ||
1205 | sizeof (struct P2PReceiveNotificationMessage); | ||
1206 | |||
1207 | is_anon = (0 != (ntohl (p2p_rnmsg->msg_options) & GNUNET_CHAT_MSG_ANONYMOUS)); | ||
1208 | if (is_anon) | ||
1209 | { | ||
1210 | room_name_len = ntohs (p2p_rnmsg->room_name_len); | ||
1211 | if (msg_len <= room_name_len) | ||
1212 | { | ||
1213 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1214 | "Malformed message: wrong length of the room name\n"); | ||
1215 | GNUNET_break_op (0); | ||
1216 | return GNUNET_SYSERR; | ||
1217 | } | ||
1218 | msg_len -= room_name_len; | ||
1219 | if (lookup_anonymous_message (p2p_rnmsg)) | ||
1220 | { | ||
1221 | #if DEBUG_CHAT_SERVICE | ||
1222 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1223 | "This anonymous message has already been handled."); | ||
1224 | #endif | ||
1225 | return GNUNET_OK; | ||
1226 | } | ||
1227 | remember_anonymous_message (p2p_rnmsg); | ||
1228 | room_name = GNUNET_malloc (room_name_len + 1); | ||
1229 | memcpy (room_name, (char *) &p2p_rnmsg[1], room_name_len); | ||
1230 | room_name[room_name_len] = '\0'; | ||
1231 | text = (char *) &p2p_rnmsg[1] + room_name_len; | ||
1232 | } | ||
1233 | else | ||
1234 | { | ||
1235 | sender = client_list_head; | ||
1236 | while ((NULL != sender) && | ||
1237 | (0 != | ||
1238 | memcmp (&sender->id, &p2p_rnmsg->sender, sizeof (struct GNUNET_HashCode)))) | ||
1239 | sender = sender->next; | ||
1240 | if (NULL == sender) | ||
1241 | { | ||
1242 | /* not an error since the sender may have left before we got the | ||
1243 | * message */ | ||
1244 | #if DEBUG_CHAT_SERVICE | ||
1245 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1246 | "Unknown source. Rejecting the message\n"); | ||
1247 | #endif | ||
1248 | return GNUNET_OK; | ||
1249 | } | ||
1250 | if (sender->msg_sequence_number >= ntohl (p2p_rnmsg->sequence_number)) | ||
1251 | { | ||
1252 | #if DEBUG_CHAT_SERVICE | ||
1253 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1254 | "This message has already been handled." | ||
1255 | " Sequence numbers (msg/sender): %u/%u\n", | ||
1256 | ntohl (p2p_rnmsg->sequence_number), | ||
1257 | sender->msg_sequence_number); | ||
1258 | #endif | ||
1259 | return GNUNET_OK; | ||
1260 | } | ||
1261 | sender->msg_sequence_number = ntohl (p2p_rnmsg->sequence_number); | ||
1262 | room_name = sender->room; | ||
1263 | text = (char *) &p2p_rnmsg[1]; | ||
1264 | } | ||
1265 | |||
1266 | #if DEBUG_CHAT_SERVICE | ||
1267 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1268 | "Sending message to local room members\n"); | ||
1269 | #endif | ||
1270 | rnmsg = GNUNET_malloc (sizeof (struct ReceiveNotificationMessage) + msg_len); | ||
1271 | rnmsg->header.size = | ||
1272 | htons (sizeof (struct ReceiveNotificationMessage) + msg_len); | ||
1273 | rnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION); | ||
1274 | rnmsg->msg_options = p2p_rnmsg->msg_options; | ||
1275 | rnmsg->sequence_number = p2p_rnmsg->sequence_number; | ||
1276 | rnmsg->reserved = htonl (0); | ||
1277 | rnmsg->timestamp = p2p_rnmsg->timestamp; | ||
1278 | is_priv = | ||
1279 | (0 != memcmp (&all_zeros, &p2p_rnmsg->target, sizeof (struct GNUNET_HashCode))); | ||
1280 | if (is_priv) | ||
1281 | memcpy (&rnmsg->encrypted_key, &p2p_rnmsg->encrypted_key, | ||
1282 | sizeof (struct GNUNET_CRYPTO_RsaEncryptedData)); | ||
1283 | rnmsg->sender = p2p_rnmsg->sender; | ||
1284 | memcpy (&rnmsg[1], text, msg_len); | ||
1285 | pos = client_list_head; | ||
1286 | while (NULL != pos) | ||
1287 | { | ||
1288 | if ((0 == strcmp (room_name, pos->room)) && (NULL != pos->client)) | ||
1289 | { | ||
1290 | if (((!is_priv) || | ||
1291 | (0 == | ||
1292 | memcmp (&p2p_rnmsg->target, &pos->id, sizeof (struct GNUNET_HashCode)))) && | ||
1293 | (0 == (ntohl (p2p_rnmsg->msg_options) & (~pos->msg_options)))) | ||
1294 | { | ||
1295 | GNUNET_SERVER_notification_context_unicast (nc, pos->client, | ||
1296 | &rnmsg->header, GNUNET_NO); | ||
1297 | } | ||
1298 | } | ||
1299 | pos = pos->next; | ||
1300 | } | ||
1301 | if (is_anon) | ||
1302 | GNUNET_free (room_name); | ||
1303 | #if DEBUG_CHAT_SERVICE | ||
1304 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1305 | "Broadcasting message notification to neighbour peers\n"); | ||
1306 | #endif | ||
1307 | my_p2p_rnmsg = GNUNET_memdup (p2p_rnmsg, ntohs (p2p_rnmsg->header.size)); | ||
1308 | GNUNET_CONTAINER_multihashmap_iterate (connected_peers, | ||
1309 | &send_message_noficiation, | ||
1310 | my_p2p_rnmsg); | ||
1311 | GNUNET_free (rnmsg); | ||
1312 | return GNUNET_OK; | ||
1313 | } | ||
1314 | |||
1315 | |||
1316 | /** | ||
1317 | * Handle P2P sync request. | ||
1318 | * | ||
1319 | * @param cls closure, always NULL | ||
1320 | * @param other the other peer involved | ||
1321 | * @param message the actual message | ||
1322 | * @return GNUNET_OK to keep the connection open, | ||
1323 | * GNUNET_SYSERR to close it (signal serious error) | ||
1324 | */ | ||
1325 | static int | ||
1326 | handle_p2p_sync_request (void *cls, const struct GNUNET_PeerIdentity *other, | ||
1327 | const struct GNUNET_MessageHeader *message) | ||
1328 | { | ||
1329 | struct ChatClient *entry; | ||
1330 | struct GNUNET_CORE_TransmitHandle *th; | ||
1331 | size_t msg_size; | ||
1332 | |||
1333 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P sync request\n"); | ||
1334 | #if DEBUG_CHAT_SERVICE | ||
1335 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1336 | "Notifying the requester of all known clients\n"); | ||
1337 | #endif | ||
1338 | entry = client_list_head; | ||
1339 | while (NULL != entry) | ||
1340 | { | ||
1341 | msg_size = | ||
1342 | sizeof (struct P2PJoinNotificationMessage) + strlen (entry->room) + | ||
1343 | entry->meta_len; | ||
1344 | th = GNUNET_CORE_notify_transmit_ready (core, GNUNET_NO, 1, | ||
1345 | MAX_TRANSMIT_DELAY, other, msg_size, | ||
1346 | &transmit_join_notification_to_peer, | ||
1347 | entry); | ||
1348 | GNUNET_assert (NULL != th); | ||
1349 | entry = entry->next; | ||
1350 | } | ||
1351 | return GNUNET_OK; | ||
1352 | } | ||
1353 | |||
1354 | |||
1355 | /** | ||
1356 | * Handle P2P confirmation receipt. | ||
1357 | * | ||
1358 | * @param cls closure, always NULL | ||
1359 | * @param other the other peer involved | ||
1360 | * @param message the actual message | ||
1361 | * @return GNUNET_OK to keep the connection open, | ||
1362 | * GNUNET_SYSERR to close it (signal serious error) | ||
1363 | */ | ||
1364 | static int | ||
1365 | handle_p2p_confirmation_receipt (void *cls, | ||
1366 | const struct GNUNET_PeerIdentity *other, | ||
1367 | const struct GNUNET_MessageHeader *message) | ||
1368 | { | ||
1369 | const struct P2PConfirmationReceiptMessage *p2p_crmsg; | ||
1370 | struct P2PConfirmationReceiptMessage *my_p2p_crmsg; | ||
1371 | struct ConfirmationReceiptMessage *crmsg; | ||
1372 | struct ChatClient *target; | ||
1373 | struct ChatClient *author; | ||
1374 | |||
1375 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P confirmation receipt\n"); | ||
1376 | p2p_crmsg = (const struct P2PConfirmationReceiptMessage *) message; | ||
1377 | target = client_list_head; | ||
1378 | while ((NULL != target) && | ||
1379 | (0 != | ||
1380 | memcmp (&target->id, &p2p_crmsg->target, sizeof (struct GNUNET_HashCode)))) | ||
1381 | target = target->next; | ||
1382 | if (NULL == target) | ||
1383 | { | ||
1384 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1385 | "Unknown source of the receipt. Rejecting the message\n"); | ||
1386 | GNUNET_break_op (0); | ||
1387 | return GNUNET_SYSERR; | ||
1388 | } | ||
1389 | if (target->rcpt_sequence_number >= ntohl (p2p_crmsg->sequence_number)) | ||
1390 | { | ||
1391 | #if DEBUG_CHAT_SERVICE | ||
1392 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1393 | "This receipt has already been handled." | ||
1394 | " Sequence numbers (msg/sender): %u/%u\n", | ||
1395 | ntohl (p2p_crmsg->sequence_number), | ||
1396 | target->rcpt_sequence_number); | ||
1397 | #endif | ||
1398 | return GNUNET_OK; | ||
1399 | } | ||
1400 | target->rcpt_sequence_number = ntohl (p2p_crmsg->sequence_number); | ||
1401 | author = client_list_head; | ||
1402 | while ((NULL != author) && | ||
1403 | (0 != | ||
1404 | memcmp (&author->id, &p2p_crmsg->author, sizeof (struct GNUNET_HashCode)))) | ||
1405 | author = author->next; | ||
1406 | if (NULL == author) | ||
1407 | { | ||
1408 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1409 | "Unknown addressee. Rejecting the receipt\n"); | ||
1410 | GNUNET_break_op (0); | ||
1411 | return GNUNET_SYSERR; | ||
1412 | } | ||
1413 | |||
1414 | if (NULL == author->client) | ||
1415 | { | ||
1416 | #if DEBUG_CHAT_SERVICE | ||
1417 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1418 | "The author of the original message is not a local client." | ||
1419 | " Broadcasting receipt to neighbour peers\n"); | ||
1420 | #endif | ||
1421 | my_p2p_crmsg = | ||
1422 | GNUNET_memdup (p2p_crmsg, | ||
1423 | sizeof (struct P2PConfirmationReceiptMessage)); | ||
1424 | GNUNET_CONTAINER_multihashmap_iterate (connected_peers, | ||
1425 | &send_confirmation_receipt, | ||
1426 | my_p2p_crmsg); | ||
1427 | GNUNET_free (my_p2p_crmsg); | ||
1428 | } | ||
1429 | else | ||
1430 | { | ||
1431 | #if DEBUG_CHAT_SERVICE | ||
1432 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1433 | "The author of the original message is a local client." | ||
1434 | " Verifying signature of the receipt\n"); | ||
1435 | #endif | ||
1436 | crmsg = GNUNET_malloc (sizeof (struct ConfirmationReceiptMessage)); | ||
1437 | crmsg->header.size = htons (sizeof (struct ConfirmationReceiptMessage)); | ||
1438 | crmsg->header.type = | ||
1439 | htons (GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION); | ||
1440 | crmsg->signature = p2p_crmsg->signature; | ||
1441 | crmsg->purpose = p2p_crmsg->purpose; | ||
1442 | crmsg->sequence_number = p2p_crmsg->msg_sequence_number; | ||
1443 | crmsg->reserved2 = 0; | ||
1444 | crmsg->timestamp = p2p_crmsg->timestamp; | ||
1445 | crmsg->target = p2p_crmsg->target; | ||
1446 | crmsg->author = p2p_crmsg->author; | ||
1447 | crmsg->content = p2p_crmsg->content; | ||
1448 | if (GNUNET_OK != | ||
1449 | GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_CHAT_RECEIPT, | ||
1450 | &crmsg->purpose, &crmsg->signature, | ||
1451 | &target->public_key)) | ||
1452 | { | ||
1453 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1454 | "Invalid signature of the receipt\n"); | ||
1455 | GNUNET_break_op (0); | ||
1456 | return GNUNET_SYSERR; | ||
1457 | } | ||
1458 | #if DEBUG_CHAT_SERVICE | ||
1459 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1460 | "The author of the original message is a local client." | ||
1461 | " Sending receipt to the client\n"); | ||
1462 | #endif | ||
1463 | GNUNET_SERVER_notification_context_unicast (nc, author->client, | ||
1464 | &crmsg->header, GNUNET_NO); | ||
1465 | GNUNET_free (crmsg); | ||
1466 | } | ||
1467 | return GNUNET_OK; | ||
1468 | } | ||
1469 | |||
1470 | |||
1471 | /** | ||
1472 | * Transmit a sync request to the peer. | ||
1473 | * | ||
1474 | * @param cls closure, NULL | ||
1475 | * @param size number of bytes available in buf | ||
1476 | * @param buf where the callee should write the message | ||
1477 | * @return number of bytes written to buf | ||
1478 | */ | ||
1479 | static size_t | ||
1480 | transmit_sync_request_to_peer (void *cls, size_t size, void *buf) | ||
1481 | { | ||
1482 | struct GNUNET_MessageHeader *m = buf; | ||
1483 | size_t msg_size; | ||
1484 | |||
1485 | #if DEBUG_CHAT_SERVICE | ||
1486 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting P2P sync request\n"); | ||
1487 | #endif | ||
1488 | msg_size = sizeof (struct GNUNET_MessageHeader); | ||
1489 | GNUNET_assert (size >= msg_size); | ||
1490 | GNUNET_assert (NULL != buf); | ||
1491 | m = buf; | ||
1492 | m->type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_SYNC_REQUEST); | ||
1493 | m->size = htons (msg_size); | ||
1494 | return msg_size; | ||
1495 | } | ||
1496 | |||
1497 | |||
1498 | /** | ||
1499 | * Method called whenever a peer connects. | ||
1500 | * | ||
1501 | * @param cls closure | ||
1502 | * @param peer peer identity this notification is about | ||
1503 | */ | ||
1504 | static void | ||
1505 | peer_connect_handler (void *cls, const struct GNUNET_PeerIdentity *peer) | ||
1506 | { | ||
1507 | struct ConnectedPeer *cp; | ||
1508 | struct GNUNET_CORE_TransmitHandle *th; | ||
1509 | |||
1510 | if (0 == memcmp (peer, &me, sizeof (struct GNUNET_PeerIdentity))) | ||
1511 | return; | ||
1512 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Peer connected: %s\n", | ||
1513 | GNUNET_i2s (peer)); | ||
1514 | th = GNUNET_CORE_notify_transmit_ready (core, GNUNET_YES, 1, | ||
1515 | MAX_TRANSMIT_DELAY, peer, | ||
1516 | sizeof (struct GNUNET_MessageHeader), | ||
1517 | &transmit_sync_request_to_peer, NULL); | ||
1518 | GNUNET_assert (NULL != th); | ||
1519 | cp = GNUNET_CONTAINER_multihashmap_get (connected_peers, &peer->hashPubKey); | ||
1520 | if (NULL != cp) | ||
1521 | { | ||
1522 | GNUNET_break (0); | ||
1523 | return; | ||
1524 | } | ||
1525 | cp = GNUNET_malloc (sizeof (struct ConnectedPeer)); | ||
1526 | cp->pid = GNUNET_PEER_intern (peer); | ||
1527 | GNUNET_break (GNUNET_OK == | ||
1528 | GNUNET_CONTAINER_multihashmap_put (connected_peers, | ||
1529 | &peer->hashPubKey, cp, | ||
1530 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
1531 | } | ||
1532 | |||
1533 | |||
1534 | /** | ||
1535 | * Iterator to free peer entries. | ||
1536 | * | ||
1537 | * @param cls closure, unused | ||
1538 | * @param key current key code | ||
1539 | * @param value value in the hash map (peer entry) | ||
1540 | * @return GNUNET_YES (we should continue to iterate) | ||
1541 | */ | ||
1542 | static int | ||
1543 | clean_peer (void *cls, const struct GNUNET_HashCode * key, void *value) | ||
1544 | { | ||
1545 | struct ConnectedPeer *cp; | ||
1546 | const struct GNUNET_PeerIdentity *peer = | ||
1547 | (const struct GNUNET_PeerIdentity *) key; | ||
1548 | |||
1549 | cp = GNUNET_CONTAINER_multihashmap_get (connected_peers, &peer->hashPubKey); | ||
1550 | if (cp == NULL) | ||
1551 | return GNUNET_YES; | ||
1552 | GNUNET_break (GNUNET_YES == | ||
1553 | GNUNET_CONTAINER_multihashmap_remove (connected_peers, | ||
1554 | &peer->hashPubKey, cp)); | ||
1555 | GNUNET_PEER_change_rc (cp->pid, -1); | ||
1556 | GNUNET_free (cp); | ||
1557 | return GNUNET_YES; | ||
1558 | } | ||
1559 | |||
1560 | |||
1561 | /** | ||
1562 | * Method called whenever a peer disconnects. | ||
1563 | * | ||
1564 | * @param cls closure, not used | ||
1565 | * @param peer peer identity this notification is about | ||
1566 | */ | ||
1567 | static void | ||
1568 | peer_disconnect_handler (void *cls, const struct GNUNET_PeerIdentity *peer) | ||
1569 | { | ||
1570 | |||
1571 | if (0 == memcmp (peer, &me, sizeof (struct GNUNET_PeerIdentity))) | ||
1572 | return; | ||
1573 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Peer disconnected: %s\n", | ||
1574 | GNUNET_i2s (peer)); | ||
1575 | clean_peer (NULL, (const struct GNUNET_HashCode *) peer, NULL); | ||
1576 | } | ||
1577 | |||
1578 | |||
1579 | /** | ||
1580 | * Task run during shutdown. | ||
1581 | * | ||
1582 | * @param cls unused | ||
1583 | * @param tc unused | ||
1584 | */ | ||
1585 | static void | ||
1586 | cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
1587 | { | ||
1588 | struct AnonymousMessage *next_msg; | ||
1589 | struct ChatClient *next_client; | ||
1590 | |||
1591 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Cleaning up\n"); | ||
1592 | if (NULL != core) | ||
1593 | { | ||
1594 | GNUNET_CORE_disconnect (core); | ||
1595 | core = NULL; | ||
1596 | } | ||
1597 | if (NULL != nc) | ||
1598 | { | ||
1599 | GNUNET_SERVER_notification_context_destroy (nc); | ||
1600 | nc = NULL; | ||
1601 | } | ||
1602 | while (NULL != client_list_head) | ||
1603 | { | ||
1604 | next_client = client_list_head->next; | ||
1605 | GNUNET_free (client_list_head->room); | ||
1606 | GNUNET_free_non_null (client_list_head->member_info); | ||
1607 | GNUNET_free (client_list_head); | ||
1608 | client_list_head = next_client; | ||
1609 | } | ||
1610 | while (NULL != anonymous_list_head) | ||
1611 | { | ||
1612 | next_msg = anonymous_list_head->next; | ||
1613 | GNUNET_free (anonymous_list_head); | ||
1614 | anonymous_list_head = next_msg; | ||
1615 | } | ||
1616 | GNUNET_CONTAINER_multihashmap_iterate (connected_peers, &clean_peer, NULL); | ||
1617 | GNUNET_CONTAINER_multihashmap_destroy (connected_peers); | ||
1618 | connected_peers = NULL; | ||
1619 | } | ||
1620 | |||
1621 | |||
1622 | /** | ||
1623 | * To be called on core init/fail. | ||
1624 | * | ||
1625 | * @param cls closure, NULL | ||
1626 | * @param server handle to the server for this service | ||
1627 | * @param my_identity the public identity of this peer | ||
1628 | */ | ||
1629 | static void | ||
1630 | core_init (void *cls, struct GNUNET_CORE_Handle *server, | ||
1631 | const struct GNUNET_PeerIdentity *my_identity) | ||
1632 | { | ||
1633 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Core initialized\n"); | ||
1634 | me = *my_identity; | ||
1635 | } | ||
1636 | |||
1637 | |||
1638 | /** | ||
1639 | * Process chat requests. | ||
1640 | * | ||
1641 | * @param cls closure, NULL | ||
1642 | * @param server the initialized server | ||
1643 | * @param c configuration to use | ||
1644 | */ | ||
1645 | static void | ||
1646 | run (void *cls, struct GNUNET_SERVER_Handle *server, | ||
1647 | const struct GNUNET_CONFIGURATION_Handle *c) | ||
1648 | { | ||
1649 | static const struct GNUNET_SERVER_MessageHandler handlers[] = { | ||
1650 | {&handle_join_request, NULL, | ||
1651 | GNUNET_MESSAGE_TYPE_CHAT_JOIN_REQUEST, 0}, | ||
1652 | {&handle_transmit_request, NULL, | ||
1653 | GNUNET_MESSAGE_TYPE_CHAT_TRANSMIT_REQUEST, 0}, | ||
1654 | {&handle_acknowledge_request, NULL, | ||
1655 | GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_RECEIPT, | ||
1656 | sizeof (struct ConfirmationReceiptMessage)}, | ||
1657 | {NULL, NULL, 0, 0} | ||
1658 | }; | ||
1659 | static const struct GNUNET_CORE_MessageHandler p2p_handlers[] = { | ||
1660 | {&handle_p2p_join_notification, | ||
1661 | GNUNET_MESSAGE_TYPE_CHAT_P2P_JOIN_NOTIFICATION, 0}, | ||
1662 | {&handle_p2p_leave_notification, | ||
1663 | GNUNET_MESSAGE_TYPE_CHAT_P2P_LEAVE_NOTIFICATION, | ||
1664 | sizeof (struct P2PLeaveNotificationMessage)}, | ||
1665 | {&handle_p2p_message_notification, | ||
1666 | GNUNET_MESSAGE_TYPE_CHAT_P2P_MESSAGE_NOTIFICATION, 0}, | ||
1667 | {&handle_p2p_sync_request, | ||
1668 | GNUNET_MESSAGE_TYPE_CHAT_P2P_SYNC_REQUEST, | ||
1669 | sizeof (struct GNUNET_MessageHeader)}, | ||
1670 | {&handle_p2p_confirmation_receipt, | ||
1671 | GNUNET_MESSAGE_TYPE_CHAT_P2P_CONFIRMATION_RECEIPT, | ||
1672 | sizeof (struct P2PConfirmationReceiptMessage)}, | ||
1673 | {NULL, 0, 0} | ||
1674 | }; | ||
1675 | |||
1676 | GNUNET_log_setup ("gnunet-service-chat", | ||
1677 | #if DEBUG_CHAT_SERVICE | ||
1678 | "DEBUG", | ||
1679 | #else | ||
1680 | "WARNING", | ||
1681 | #endif | ||
1682 | NULL); | ||
1683 | cfg = c; | ||
1684 | nc = GNUNET_SERVER_notification_context_create (server, 16); | ||
1685 | connected_peers = | ||
1686 | GNUNET_CONTAINER_multihashmap_create (EXPECTED_NEIGHBOUR_COUNT, GNUNET_NO); | ||
1687 | GNUNET_SERVER_add_handlers (server, handlers); | ||
1688 | core = | ||
1689 | GNUNET_CORE_connect (cfg, NULL, &core_init, | ||
1690 | &peer_connect_handler, &peer_disconnect_handler, | ||
1691 | NULL, GNUNET_NO, NULL, GNUNET_NO, p2p_handlers); | ||
1692 | GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL); | ||
1693 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task, | ||
1694 | NULL); | ||
1695 | } | ||
1696 | |||
1697 | |||
1698 | /** | ||
1699 | * The main function for the chat service. | ||
1700 | * | ||
1701 | * @param argc number of arguments from the command line | ||
1702 | * @param argv command line arguments | ||
1703 | * @return 0 ok, 1 on error | ||
1704 | */ | ||
1705 | int | ||
1706 | main (int argc, char *const *argv) | ||
1707 | { | ||
1708 | return (GNUNET_OK == | ||
1709 | GNUNET_SERVICE_run (argc, argv, "chat", GNUNET_SERVICE_OPTION_NONE, | ||
1710 | &run, NULL)) ? 0 : 1; | ||
1711 | } | ||
1712 | |||
1713 | /* end of gnunet-service-chat.c */ | ||
diff --git a/src/chat/test_chat.c b/src/chat/test_chat.c deleted file mode 100644 index 78b31f1b1..000000000 --- a/src/chat/test_chat.c +++ /dev/null | |||
@@ -1,556 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2005, 2006, 2007, 2008, 2011 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file chat/test_chat.c | ||
23 | * @brief base test case for the chat library | ||
24 | * @author Christian Grothoff | ||
25 | * @author Nathan Evans | ||
26 | * @author Vitaly Minko | ||
27 | * | ||
28 | * This test case serves as a base for simple chatting, anonymous chatting, | ||
29 | * authenticated chatting and acknowledgements test cases. Based on the | ||
30 | * executable being run the correct test case will be performed. Private | ||
31 | * chatting is covered by a separate test case since it requires 3 users. | ||
32 | */ | ||
33 | |||
34 | #include "platform.h" | ||
35 | #include "gnunet_crypto_lib.h" | ||
36 | #include "gnunet_util_lib.h" | ||
37 | #include "gnunet_arm_service.h" | ||
38 | #include "gnunet_chat_service.h" | ||
39 | |||
40 | /** | ||
41 | * How long until we give up on passing the test? | ||
42 | */ | ||
43 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) | ||
44 | |||
45 | struct PeerContext | ||
46 | { | ||
47 | struct GNUNET_CONFIGURATION_Handle *cfg; | ||
48 | struct GNUNET_OS_Process *arm_proc; | ||
49 | }; | ||
50 | |||
51 | struct Wanted | ||
52 | { | ||
53 | struct GNUNET_CONTAINER_MetaData *meta; | ||
54 | |||
55 | struct GNUNET_HashCode *sender; | ||
56 | |||
57 | char *msg; | ||
58 | |||
59 | const char *me; | ||
60 | |||
61 | enum GNUNET_CHAT_MsgOptions opt; | ||
62 | |||
63 | uint32_t sequence_number; | ||
64 | |||
65 | struct GNUNET_TIME_Absolute timestamp; | ||
66 | |||
67 | GNUNET_SCHEDULER_Task next_task; | ||
68 | |||
69 | void *next_task_cls; | ||
70 | |||
71 | }; | ||
72 | |||
73 | static struct PeerContext p1; | ||
74 | |||
75 | static struct PeerContext p2; | ||
76 | |||
77 | static struct GNUNET_HashCode alice; | ||
78 | |||
79 | static struct GNUNET_HashCode bob; | ||
80 | |||
81 | static struct GNUNET_CHAT_Room *alice_room; | ||
82 | |||
83 | static struct GNUNET_CHAT_Room *bob_room; | ||
84 | |||
85 | static struct GNUNET_CONTAINER_MetaData *alice_meta; | ||
86 | |||
87 | static struct GNUNET_CONTAINER_MetaData *bob_meta; | ||
88 | |||
89 | static struct Wanted alice_wanted; | ||
90 | |||
91 | static struct Wanted bob_wanted; | ||
92 | |||
93 | static GNUNET_SCHEDULER_TaskIdentifier kill_task; | ||
94 | |||
95 | static GNUNET_SCHEDULER_TaskIdentifier wait_task; | ||
96 | |||
97 | static int err; | ||
98 | |||
99 | static int is_ready; | ||
100 | |||
101 | static int is_p2p; | ||
102 | |||
103 | static int is_ackn; | ||
104 | |||
105 | static int is_anon; | ||
106 | |||
107 | static int is_auth; | ||
108 | |||
109 | |||
110 | static void | ||
111 | setup_peer (struct PeerContext *p, const char *cfgname) | ||
112 | { | ||
113 | char *binary; | ||
114 | |||
115 | binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm"); | ||
116 | p->cfg = GNUNET_CONFIGURATION_create (); | ||
117 | p->arm_proc = | ||
118 | GNUNET_OS_start_process (GNUNET_YES, GNUNET_OS_INHERIT_STD_OUT_AND_ERR, NULL, NULL, binary, | ||
119 | "gnunet-service-arm", | ||
120 | "-c", cfgname, NULL); | ||
121 | GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); | ||
122 | GNUNET_free (binary); | ||
123 | } | ||
124 | |||
125 | |||
126 | static void | ||
127 | stop_arm (struct PeerContext *p) | ||
128 | { | ||
129 | if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) | ||
130 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); | ||
131 | if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) | ||
132 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); | ||
133 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", | ||
134 | GNUNET_OS_process_get_pid (p->arm_proc)); | ||
135 | GNUNET_OS_process_destroy (p->arm_proc); | ||
136 | p->arm_proc = NULL; | ||
137 | GNUNET_CONFIGURATION_destroy (p->cfg); | ||
138 | } | ||
139 | |||
140 | |||
141 | static void | ||
142 | abort_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
143 | { | ||
144 | if (alice_room != NULL) | ||
145 | { | ||
146 | GNUNET_CHAT_leave_room (alice_room); | ||
147 | alice_room = NULL; | ||
148 | } | ||
149 | if (bob_room != NULL) | ||
150 | { | ||
151 | GNUNET_CHAT_leave_room (bob_room); | ||
152 | bob_room = NULL; | ||
153 | } | ||
154 | err = 1; | ||
155 | } | ||
156 | |||
157 | |||
158 | static void | ||
159 | timeout_kill (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
160 | { | ||
161 | fprintf (stderr, | ||
162 | "Timed out, stopping the test.\n"); | ||
163 | kill_task = GNUNET_SCHEDULER_NO_TASK; | ||
164 | if (wait_task != GNUNET_SCHEDULER_NO_TASK) | ||
165 | { | ||
166 | GNUNET_SCHEDULER_cancel (wait_task); | ||
167 | wait_task = GNUNET_SCHEDULER_NO_TASK; | ||
168 | } | ||
169 | GNUNET_SCHEDULER_add_continuation (&abort_test, NULL, | ||
170 | GNUNET_SCHEDULER_REASON_PREREQ_DONE); | ||
171 | } | ||
172 | |||
173 | |||
174 | static int | ||
175 | join_cb (void *cls) | ||
176 | { | ||
177 | struct Wanted *want = cls; | ||
178 | |||
179 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
180 | "%s has joined\n", want->me); | ||
181 | if (NULL != want->next_task) | ||
182 | GNUNET_SCHEDULER_add_now (want->next_task, want->next_task_cls); | ||
183 | return GNUNET_OK; | ||
184 | } | ||
185 | |||
186 | |||
187 | static int | ||
188 | member_list_cb (void *cls, const struct GNUNET_CONTAINER_MetaData *member_info, | ||
189 | const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *member_id, | ||
190 | enum GNUNET_CHAT_MsgOptions options) | ||
191 | { | ||
192 | struct Wanted *want = cls; | ||
193 | struct GNUNET_HashCode sender; | ||
194 | |||
195 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
196 | "%s - told that %s has %s\n", want->me, | ||
197 | member_info == | ||
198 | NULL ? NULL : GNUNET_CONTAINER_meta_data_get_by_type (member_info, | ||
199 | EXTRACTOR_METATYPE_TITLE), | ||
200 | member_info == NULL ? "left" : "joined"); | ||
201 | GNUNET_CRYPTO_hash (member_id, | ||
202 | sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), | ||
203 | &sender); | ||
204 | if ((0 == memcmp (&sender, want->sender, sizeof (struct GNUNET_HashCode))) && | ||
205 | (((member_info == NULL) && (want->meta == NULL)) || | ||
206 | ((member_info != NULL) && (want->meta != NULL) && | ||
207 | (GNUNET_CONTAINER_meta_data_test_equal (member_info, want->meta)))) && | ||
208 | (options == want->opt)) | ||
209 | { | ||
210 | if (NULL != want->next_task) | ||
211 | GNUNET_SCHEDULER_add_now (want->next_task, want->next_task_cls); | ||
212 | } | ||
213 | else | ||
214 | { | ||
215 | GNUNET_SCHEDULER_cancel (kill_task); | ||
216 | kill_task = GNUNET_SCHEDULER_NO_TASK; | ||
217 | GNUNET_SCHEDULER_add_now (&abort_test, NULL); | ||
218 | } | ||
219 | return GNUNET_OK; | ||
220 | } | ||
221 | |||
222 | |||
223 | static int | ||
224 | receive_cb (void *cls, struct GNUNET_CHAT_Room *room, | ||
225 | const struct GNUNET_HashCode * sender, | ||
226 | const struct GNUNET_CONTAINER_MetaData *meta, const char *message, | ||
227 | struct GNUNET_TIME_Absolute timestamp, | ||
228 | enum GNUNET_CHAT_MsgOptions options) | ||
229 | { | ||
230 | struct Wanted *want = cls; | ||
231 | |||
232 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
233 | |||
234 | "%s - told that %s said %s\n", want->me, | ||
235 | meta == NULL ? NULL : GNUNET_CONTAINER_meta_data_get_by_type (meta, | ||
236 | EXTRACTOR_METATYPE_TITLE), | ||
237 | message); | ||
238 | if ((0 == strcmp (message, want->msg)) && | ||
239 | (((sender == NULL) && (want->sender == NULL)) || | ||
240 | ((sender != NULL) && (want->sender != NULL) && | ||
241 | (0 == memcmp (sender, want->sender, sizeof (struct GNUNET_HashCode))))) && | ||
242 | (GNUNET_CONTAINER_meta_data_test_equal (meta, want->meta)) && | ||
243 | (options == want->opt) && | ||
244 | /* Not == since the library sets the actual timestamp, so it may be | ||
245 | * slightly greater | ||
246 | */ | ||
247 | (timestamp.abs_value >= want->timestamp.abs_value)) | ||
248 | { | ||
249 | if (NULL != want->next_task) | ||
250 | GNUNET_SCHEDULER_add_now (want->next_task, want->next_task_cls); | ||
251 | } | ||
252 | else | ||
253 | { | ||
254 | GNUNET_SCHEDULER_cancel (kill_task); | ||
255 | kill_task = GNUNET_SCHEDULER_NO_TASK; | ||
256 | GNUNET_SCHEDULER_add_now (&abort_test, NULL); | ||
257 | } | ||
258 | return GNUNET_OK; | ||
259 | } | ||
260 | |||
261 | |||
262 | static int | ||
263 | confirmation_cb (void *cls, struct GNUNET_CHAT_Room *room, | ||
264 | uint32_t orig_seq_number, | ||
265 | struct GNUNET_TIME_Absolute timestamp, | ||
266 | const struct GNUNET_HashCode * receiver) | ||
267 | { | ||
268 | struct Wanted *want = cls; | ||
269 | |||
270 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
271 | "%s - told that %s acknowledged message #%d\n", want->me, | ||
272 | GNUNET_CONTAINER_meta_data_get_by_type (want->meta, | ||
273 | EXTRACTOR_METATYPE_TITLE), | ||
274 | orig_seq_number); | ||
275 | if ((0 == memcmp (receiver, want->sender, sizeof (struct GNUNET_HashCode))) && | ||
276 | (orig_seq_number == want->sequence_number) && | ||
277 | (timestamp.abs_value >= want->timestamp.abs_value)) | ||
278 | { | ||
279 | if (NULL != want->next_task) | ||
280 | GNUNET_SCHEDULER_add_now (want->next_task, want->next_task_cls); | ||
281 | } | ||
282 | else | ||
283 | { | ||
284 | GNUNET_SCHEDULER_cancel (kill_task); | ||
285 | kill_task = GNUNET_SCHEDULER_NO_TASK; | ||
286 | GNUNET_SCHEDULER_add_now (&abort_test, NULL); | ||
287 | } | ||
288 | return GNUNET_OK; | ||
289 | } | ||
290 | |||
291 | |||
292 | static void | ||
293 | wait_until_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
294 | { | ||
295 | GNUNET_SCHEDULER_Task task = cls; | ||
296 | |||
297 | if (is_ready) | ||
298 | { | ||
299 | wait_task = GNUNET_SCHEDULER_NO_TASK; | ||
300 | GNUNET_SCHEDULER_add_now (task, NULL); | ||
301 | } | ||
302 | else | ||
303 | wait_task = | ||
304 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
305 | (GNUNET_TIME_UNIT_MILLISECONDS, 50), | ||
306 | &wait_until_ready, task); | ||
307 | } | ||
308 | |||
309 | |||
310 | static void | ||
311 | disconnect_alice (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
312 | { | ||
313 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
314 | "Alice is leaving.\n"); | ||
315 | if (is_p2p) | ||
316 | stop_arm (&p2); | ||
317 | GNUNET_CHAT_leave_room (alice_room); | ||
318 | alice_room = NULL; | ||
319 | GNUNET_SCHEDULER_cancel (kill_task); | ||
320 | kill_task = GNUNET_SCHEDULER_NO_TASK; | ||
321 | } | ||
322 | |||
323 | |||
324 | static void | ||
325 | disconnect_bob (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
326 | { | ||
327 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
328 | "Bob is leaving.\n"); | ||
329 | alice_wanted.meta = NULL; | ||
330 | alice_wanted.sender = &bob; | ||
331 | alice_wanted.msg = NULL; | ||
332 | alice_wanted.opt = 0; | ||
333 | alice_wanted.next_task = &disconnect_alice; | ||
334 | alice_wanted.next_task_cls = NULL; | ||
335 | GNUNET_CHAT_leave_room (bob_room); | ||
336 | bob_room = NULL; | ||
337 | } | ||
338 | |||
339 | |||
340 | static void | ||
341 | set_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
342 | { | ||
343 | is_ready = GNUNET_YES; | ||
344 | } | ||
345 | |||
346 | |||
347 | static void | ||
348 | send_to_alice (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
349 | { | ||
350 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
351 | "Bob says 'Hi!'\n"); | ||
352 | alice_wanted.meta = bob_meta; | ||
353 | alice_wanted.sender = &bob; | ||
354 | alice_wanted.msg = "Hi Alice!"; | ||
355 | alice_wanted.opt = GNUNET_CHAT_MSG_OPTION_NONE; | ||
356 | alice_wanted.timestamp = GNUNET_TIME_absolute_get (); | ||
357 | alice_wanted.next_task = &disconnect_bob; | ||
358 | alice_wanted.next_task_cls = NULL; | ||
359 | GNUNET_CHAT_send_message (bob_room, "Hi Alice!", GNUNET_CHAT_MSG_OPTION_NONE, | ||
360 | NULL, NULL); | ||
361 | } | ||
362 | |||
363 | |||
364 | static void | ||
365 | send_to_bob (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
366 | { | ||
367 | enum GNUNET_CHAT_MsgOptions options; | ||
368 | uint32_t *seq = NULL; | ||
369 | |||
370 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
371 | "Alice says 'Hi!'\n"); | ||
372 | if (is_ackn) | ||
373 | { | ||
374 | options = GNUNET_CHAT_MSG_ACKNOWLEDGED; | ||
375 | alice_wanted.meta = bob_meta; | ||
376 | alice_wanted.sender = &bob; | ||
377 | alice_wanted.timestamp = GNUNET_TIME_absolute_get (); | ||
378 | alice_wanted.next_task = &disconnect_bob; | ||
379 | alice_wanted.next_task_cls = NULL; | ||
380 | bob_wanted.meta = alice_meta; | ||
381 | bob_wanted.sender = &alice; | ||
382 | bob_wanted.next_task = NULL; | ||
383 | seq = &(alice_wanted.sequence_number); | ||
384 | } | ||
385 | else if (is_anon) | ||
386 | { | ||
387 | options = GNUNET_CHAT_MSG_ANONYMOUS; | ||
388 | bob_wanted.meta = NULL; | ||
389 | bob_wanted.sender = NULL; | ||
390 | bob_wanted.next_task = &disconnect_bob; | ||
391 | } | ||
392 | else if (is_auth) | ||
393 | { | ||
394 | options = GNUNET_CHAT_MSG_AUTHENTICATED; | ||
395 | bob_wanted.meta = alice_meta; | ||
396 | bob_wanted.sender = &alice; | ||
397 | bob_wanted.next_task = &disconnect_bob; | ||
398 | } | ||
399 | else | ||
400 | { | ||
401 | options = GNUNET_CHAT_MSG_OPTION_NONE; | ||
402 | bob_wanted.meta = alice_meta; | ||
403 | bob_wanted.sender = &alice; | ||
404 | bob_wanted.next_task = &send_to_alice; | ||
405 | } | ||
406 | bob_wanted.msg = "Hi Bob!"; | ||
407 | bob_wanted.opt = options; | ||
408 | bob_wanted.timestamp = GNUNET_TIME_absolute_get (); | ||
409 | bob_wanted.next_task_cls = NULL; | ||
410 | GNUNET_CHAT_send_message (alice_room, "Hi Bob!", options, NULL, seq); | ||
411 | } | ||
412 | |||
413 | |||
414 | static void | ||
415 | prepare_for_alice_task (void *cls, | ||
416 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
417 | { | ||
418 | bob_wanted.meta = alice_meta; | ||
419 | bob_wanted.sender = &alice; | ||
420 | bob_wanted.msg = NULL; | ||
421 | bob_wanted.opt = -1; | ||
422 | bob_wanted.next_task = &set_ready; | ||
423 | bob_wanted.next_task_cls = NULL; | ||
424 | } | ||
425 | |||
426 | |||
427 | static void | ||
428 | join_bob_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
429 | { | ||
430 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
431 | "Bob joining\n"); | ||
432 | alice_wanted.meta = bob_meta; | ||
433 | alice_wanted.sender = &bob; | ||
434 | alice_wanted.msg = NULL; | ||
435 | alice_wanted.opt = -1; | ||
436 | alice_wanted.next_task = &wait_until_ready; | ||
437 | alice_wanted.next_task_cls = &send_to_bob; | ||
438 | bob_wanted.next_task = &prepare_for_alice_task; | ||
439 | bob_wanted.next_task_cls = NULL; | ||
440 | is_ready = GNUNET_NO; | ||
441 | bob_room = | ||
442 | GNUNET_CHAT_join_room (is_p2p ? p2.cfg : p1.cfg, "bob", bob_meta, "test", | ||
443 | -1, &join_cb, &bob_wanted, &receive_cb, | ||
444 | &bob_wanted, &member_list_cb, &bob_wanted, | ||
445 | &confirmation_cb, &bob_wanted, &bob); | ||
446 | if (NULL == bob_room) | ||
447 | { | ||
448 | GNUNET_SCHEDULER_cancel (kill_task); | ||
449 | kill_task = GNUNET_SCHEDULER_NO_TASK; | ||
450 | GNUNET_CHAT_leave_room (alice_room); | ||
451 | alice_room = NULL; | ||
452 | err = 1; | ||
453 | } | ||
454 | } | ||
455 | |||
456 | |||
457 | static void | ||
458 | join_alice_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
459 | { | ||
460 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
461 | "Alice joining\n"); | ||
462 | alice_wanted.next_task = &join_bob_task; | ||
463 | alice_wanted.next_task_cls = NULL; | ||
464 | alice_room = | ||
465 | GNUNET_CHAT_join_room (p1.cfg, "alice", alice_meta, "test", -1, &join_cb, | ||
466 | &alice_wanted, &receive_cb, &alice_wanted, | ||
467 | &member_list_cb, &alice_wanted, &confirmation_cb, | ||
468 | &alice_wanted, &alice); | ||
469 | if (NULL == alice_room) | ||
470 | { | ||
471 | GNUNET_SCHEDULER_cancel (kill_task); | ||
472 | kill_task = GNUNET_SCHEDULER_NO_TASK; | ||
473 | err = 1; | ||
474 | } | ||
475 | } | ||
476 | |||
477 | |||
478 | static void | ||
479 | run (void *cls, char *const *args, const char *cfgfile, | ||
480 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
481 | { | ||
482 | if (is_p2p) | ||
483 | { | ||
484 | setup_peer (&p1, "test_chat_peer1.conf"); | ||
485 | setup_peer (&p2, "test_chat_peer2.conf"); | ||
486 | } | ||
487 | else | ||
488 | setup_peer (&p1, "test_chat_data.conf"); | ||
489 | |||
490 | memset (&alice_wanted, 0, sizeof (struct Wanted)); | ||
491 | memset (&bob_wanted, 0, sizeof (struct Wanted)); | ||
492 | alice_wanted.me = "Alice"; | ||
493 | bob_wanted.me = "Bob"; | ||
494 | alice_meta = GNUNET_CONTAINER_meta_data_create (); | ||
495 | GNUNET_CONTAINER_meta_data_insert (alice_meta, "<gnunet>", | ||
496 | EXTRACTOR_METATYPE_TITLE, | ||
497 | EXTRACTOR_METAFORMAT_UTF8, "text/plain", | ||
498 | "Alice", strlen ("Alice") + 1); | ||
499 | bob_meta = GNUNET_CONTAINER_meta_data_create (); | ||
500 | GNUNET_CONTAINER_meta_data_insert (bob_meta, "<gnunet>", | ||
501 | EXTRACTOR_METATYPE_TITLE, | ||
502 | EXTRACTOR_METAFORMAT_UTF8, "text/plain", | ||
503 | "Bob", strlen ("Bob") + 1); | ||
504 | kill_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout_kill, NULL); | ||
505 | GNUNET_SCHEDULER_add_now (&join_alice_task, NULL); | ||
506 | } | ||
507 | |||
508 | |||
509 | int | ||
510 | main (int argc, char *argv[]) | ||
511 | { | ||
512 | char *const argvx[] = { | ||
513 | "test-chat", | ||
514 | "-c", | ||
515 | "test_chat_data.conf", | ||
516 | NULL | ||
517 | }; | ||
518 | struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
519 | GNUNET_GETOPT_OPTION_END | ||
520 | }; | ||
521 | |||
522 | GNUNET_log_setup ("test_chat", | ||
523 | "WARNING", | ||
524 | NULL); | ||
525 | if (strstr (argv[0], "p2p") != NULL) | ||
526 | { | ||
527 | is_p2p = GNUNET_YES; | ||
528 | } | ||
529 | if (strstr (argv[0], "acknowledgment") != NULL) | ||
530 | { | ||
531 | is_ackn = GNUNET_YES; | ||
532 | } | ||
533 | else if (strstr (argv[0], "anonymous") != NULL) | ||
534 | { | ||
535 | is_anon = GNUNET_YES; | ||
536 | } | ||
537 | else if (strstr (argv[0], "authentication") != NULL) | ||
538 | { | ||
539 | is_auth = GNUNET_YES; | ||
540 | } | ||
541 | GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, | ||
542 | "test-chat", "nohelp", options, &run, NULL); | ||
543 | stop_arm (&p1); | ||
544 | GNUNET_CONTAINER_meta_data_destroy (alice_meta); | ||
545 | GNUNET_CONTAINER_meta_data_destroy (bob_meta); | ||
546 | if (is_p2p) | ||
547 | { | ||
548 | GNUNET_DISK_directory_remove ("/tmp/gnunet-test-chat-peer-1/"); | ||
549 | GNUNET_DISK_directory_remove ("/tmp/gnunet-test-chat-peer-2/"); | ||
550 | } | ||
551 | else | ||
552 | GNUNET_DISK_directory_remove ("/tmp/gnunet-test-chat/"); | ||
553 | return err; | ||
554 | } | ||
555 | |||
556 | /* end of test_chat.c */ | ||
diff --git a/src/chat/test_chat_data.conf b/src/chat/test_chat_data.conf deleted file mode 100644 index 45a6ce7c9..000000000 --- a/src/chat/test_chat_data.conf +++ /dev/null | |||
@@ -1,55 +0,0 @@ | |||
1 | [PATHS] | ||
2 | SERVICEHOME = /tmp/gnunet-test-chat/ | ||
3 | |||
4 | [gnunetd] | ||
5 | HOSTKEY = $SERVICEHOME/.hostkey | ||
6 | |||
7 | [resolver] | ||
8 | PORT = 42464 | ||
9 | HOSTNAME = localhost | ||
10 | |||
11 | [transport] | ||
12 | PORT = 42465 | ||
13 | PLUGINS = | ||
14 | |||
15 | [arm] | ||
16 | PORT = 42466 | ||
17 | HOSTNAME = localhost | ||
18 | DEFAULTSERVICES = core chat | ||
19 | |||
20 | [peerinfo] | ||
21 | PORT = 42469 | ||
22 | HOSTNAME = localhost | ||
23 | |||
24 | [core] | ||
25 | PORT = 42470 | ||
26 | HOSTNAME = localhost | ||
27 | |||
28 | [chat] | ||
29 | PORT = 42471 | ||
30 | HOSTNAME = localhost | ||
31 | HOME = $SERVICEHOME | ||
32 | BINARY = gnunet-service-chat | ||
33 | |||
34 | [testing] | ||
35 | WEAKRANDOM = YES | ||
36 | |||
37 | [nat] | ||
38 | DISABLEV6 = YES | ||
39 | BINDTO = 127.0.0.1 | ||
40 | ENABLE_UPNP = NO | ||
41 | BEHIND_NAT = NO | ||
42 | ALLOW_NAT = NO | ||
43 | INTERNAL_ADDRESS = 127.0.0.1 | ||
44 | EXTERNAL_ADDRESS = 127.0.0.1 | ||
45 | |||
46 | [dns] | ||
47 | AUTOSTART = NO | ||
48 | |||
49 | [consensus] | ||
50 | AUTOSTART = NO | ||
51 | |||
52 | [nse] | ||
53 | AUTOSTART = NO | ||
54 | |||
55 | |||
diff --git a/src/chat/test_chat_peer1.conf b/src/chat/test_chat_peer1.conf deleted file mode 100644 index 0193188de..000000000 --- a/src/chat/test_chat_peer1.conf +++ /dev/null | |||
@@ -1,92 +0,0 @@ | |||
1 | [PATHS] | ||
2 | SERVICEHOME = /tmp/gnunet-test-chat-peer-1/ | ||
3 | |||
4 | [gnunetd] | ||
5 | HOSTKEY = $SERVICEHOME/.hostkey | ||
6 | |||
7 | [hostlist] | ||
8 | HTTPPORT = 31000 | ||
9 | OPTIONS = -p | ||
10 | |||
11 | [resolver] | ||
12 | PORT = 31001 | ||
13 | HOSTNAME = localhost | ||
14 | UNIXPATH = /tmp/gnunet-chat-p1-service-resolver.sock | ||
15 | |||
16 | [transport] | ||
17 | PORT = 31002 | ||
18 | UNIXPATH = /tmp/gnunet-chat-p1-service-transport.sock | ||
19 | PLUGINS = tcp | ||
20 | #BINARY = /home/grothoff/bin/gnunet-service-transport | ||
21 | #PREFIX = valgrind | ||
22 | |||
23 | [transport-tcp] | ||
24 | PORT = 31003 | ||
25 | |||
26 | [arm] | ||
27 | PORT = 31004 | ||
28 | UNIXPATH = /tmp/gnunet-chat-p1-service-arm.sock | ||
29 | HOSTNAME = localhost | ||
30 | DEFAULTSERVICES = resolver transport core topology hostlist statistics chat | ||
31 | |||
32 | [core] | ||
33 | PORT = 31005 | ||
34 | UNIXPATH = /tmp/gnunet-chat-p1-service-core.sock | ||
35 | HOSTNAME = localhost | ||
36 | |||
37 | [topology] | ||
38 | MINIMUM-FRIENDS = 0 | ||
39 | FRIENDS-ONLY = NO | ||
40 | AUTOCONNECT = YES | ||
41 | TARGET-CONNECTION-COUNT = 16 | ||
42 | FRIENDS = $SERVICEHOME/friends | ||
43 | BINARY = gnunet-daemon-topology | ||
44 | |||
45 | [peerinfo] | ||
46 | PORT = 31006 | ||
47 | UNIXPATH = /tmp/gnunet-chat-p1-service-peerinfo.sock | ||
48 | HOSTNAME = localhost | ||
49 | |||
50 | [statistics] | ||
51 | PORT = 31007 | ||
52 | HOSTNAME = localhost | ||
53 | UNIXPATH = /tmp/gnunet-chat-p1-service-statistics.sock | ||
54 | |||
55 | [chat] | ||
56 | PORT = 31008 | ||
57 | HOSTNAME = localhost | ||
58 | HOME = $SERVICEHOME | ||
59 | BINARY = gnunet-service-chat | ||
60 | |||
61 | [testing] | ||
62 | WEAKRANDOM = YES | ||
63 | |||
64 | [fs] | ||
65 | AUTOSTART = NO | ||
66 | |||
67 | [datastore] | ||
68 | AUTOSTART = NO | ||
69 | |||
70 | [dht] | ||
71 | AUTOSTART = NO | ||
72 | |||
73 | [mesh] | ||
74 | AUTOSTART = NO | ||
75 | [nat] | ||
76 | DISABLEV6 = YES | ||
77 | BINDTO = 127.0.0.1 | ||
78 | ENABLE_UPNP = NO | ||
79 | BEHIND_NAT = NO | ||
80 | ALLOW_NAT = NO | ||
81 | INTERNAL_ADDRESS = 127.0.0.1 | ||
82 | EXTERNAL_ADDRESS = 127.0.0.1 | ||
83 | |||
84 | [dns] | ||
85 | AUTOSTART = NO | ||
86 | |||
87 | [nse] | ||
88 | AUTOSTART = NO | ||
89 | |||
90 | [ats] | ||
91 | PORT = 31971 | ||
92 | UNIXPATH = /tmp/gnunet-chat-p1-service-ats.sock | ||
diff --git a/src/chat/test_chat_peer2.conf b/src/chat/test_chat_peer2.conf deleted file mode 100644 index c4a31a0f3..000000000 --- a/src/chat/test_chat_peer2.conf +++ /dev/null | |||
@@ -1,94 +0,0 @@ | |||
1 | [PATHS] | ||
2 | SERVICEHOME = /tmp/gnunet-test-chat-peer-2/ | ||
3 | |||
4 | [gnunetd] | ||
5 | HOSTKEY = $SERVICEHOME/.hostkey | ||
6 | |||
7 | [hostlist] | ||
8 | SERVERS = http://localhost:31000/ | ||
9 | OPTIONS = -b | ||
10 | |||
11 | [resolver] | ||
12 | PORT = 32001 | ||
13 | HOSTNAME = localhost | ||
14 | UNIXPATH = /tmp/gnunet-chat-p2-service-resolver.sock | ||
15 | |||
16 | [transport] | ||
17 | PORT = 32002 | ||
18 | UNIXPATH = /tmp/gnunet-chat-p2-service-transport.sock | ||
19 | PLUGINS = tcp | ||
20 | #BINARY = /home/grothoff/bin/gnunet-service-transport | ||
21 | #PREFIX = valgrind | ||
22 | |||
23 | [transport-tcp] | ||
24 | PORT = 32003 | ||
25 | |||
26 | [arm] | ||
27 | PORT = 32004 | ||
28 | UNIXPATH = /tmp/gnunet-chat-p2-service-arm.sock | ||
29 | HOSTNAME = localhost | ||
30 | DEFAULTSERVICES = resolver transport core topology hostlist statistics chat | ||
31 | |||
32 | [core] | ||
33 | PORT = 32005 | ||
34 | UNIXPATH = /tmp/gnunet-chat-p2-service-core.sock | ||
35 | HOSTNAME = localhost | ||
36 | |||
37 | [topology] | ||
38 | MINIMUM-FRIENDS = 0 | ||
39 | FRIENDS-ONLY = NO | ||
40 | AUTOCONNECT = YES | ||
41 | TARGET-CONNECTION-COUNT = 16 | ||
42 | FRIENDS = $SERVICEHOME/friends | ||
43 | BINARY = gnunet-daemon-topology | ||
44 | |||
45 | [peerinfo] | ||
46 | PORT = 32006 | ||
47 | UNIXPATH = /tmp/gnunet-chat-p2-service-peerinfo.sock | ||
48 | HOSTNAME = localhost | ||
49 | |||
50 | [statistics] | ||
51 | PORT = 32007 | ||
52 | HOSTNAME = localhost | ||
53 | UNIXPATH = /tmp/gnunet-chat-p2-service-statistics.sock | ||
54 | |||
55 | [chat] | ||
56 | PORT = 32008 | ||
57 | HOSTNAME = localhost | ||
58 | HOME = $SERVICEHOME | ||
59 | BINARY = gnunet-service-chat | ||
60 | |||
61 | [testing] | ||
62 | WEAKRANDOM = YES | ||
63 | |||
64 | [fs] | ||
65 | AUTOSTART = NO | ||
66 | |||
67 | [datastore] | ||
68 | AUTOSTART = NO | ||
69 | |||
70 | [dht] | ||
71 | AUTOSTART = NO | ||
72 | |||
73 | [mesh] | ||
74 | AUTOSTART = NO | ||
75 | |||
76 | [nat] | ||
77 | DISABLEV6 = YES | ||
78 | BINDTO = 127.0.0.1 | ||
79 | ENABLE_UPNP = NO | ||
80 | BEHIND_NAT = NO | ||
81 | ALLOW_NAT = NO | ||
82 | INTERNAL_ADDRESS = 127.0.0.1 | ||
83 | EXTERNAL_ADDRESS = 127.0.0.1 | ||
84 | |||
85 | [dns] | ||
86 | AUTOSTART = NO | ||
87 | |||
88 | [nse] | ||
89 | AUTOSTART = NO | ||
90 | |||
91 | [ats] | ||
92 | PORT = 32971 | ||
93 | UNIXPATH = /tmp/gnunet-chat-p2-service-ats.sock | ||
94 | |||
diff --git a/src/chat/test_chat_peer3.conf b/src/chat/test_chat_peer3.conf deleted file mode 100644 index d8dcedc29..000000000 --- a/src/chat/test_chat_peer3.conf +++ /dev/null | |||
@@ -1,93 +0,0 @@ | |||
1 | [PATHS] | ||
2 | SERVICEHOME = /tmp/gnunet-test-chat-peer-3/ | ||
3 | |||
4 | [gnunetd] | ||
5 | HOSTKEY = $SERVICEHOME/.hostkey | ||
6 | |||
7 | [hostlist] | ||
8 | SERVERS = http://localhost:31000/ | ||
9 | OPTIONS = -b | ||
10 | |||
11 | [resolver] | ||
12 | PORT = 33001 | ||
13 | HOSTNAME = localhost | ||
14 | UNIXPATH = /tmp/gnunet-chat-p3-service-resolver.sock | ||
15 | |||
16 | [transport] | ||
17 | PORT = 33002 | ||
18 | UNIXPATH = /tmp/gnunet-chat-p3-service-transport.sock | ||
19 | PLUGINS = tcp | ||
20 | #BINARY = /home/grothoff/bin/gnunet-service-transport | ||
21 | #PREFIX = valgrind | ||
22 | |||
23 | [transport-tcp] | ||
24 | PORT = 33003 | ||
25 | |||
26 | [arm] | ||
27 | PORT = 33004 | ||
28 | UNIXPATH = /tmp/gnunet-chat-p3-service-arm.sock | ||
29 | HOSTNAME = localhost | ||
30 | DEFAULTSERVICES = resolver transport core topology hostlist statistics chat | ||
31 | |||
32 | [core] | ||
33 | PORT = 33005 | ||
34 | UNIXPATH = /tmp/gnunet-chat-p3-service-core.sock | ||
35 | HOSTNAME = localhost | ||
36 | |||
37 | [topology] | ||
38 | MINIMUM-FRIENDS = 0 | ||
39 | FRIENDS-ONLY = NO | ||
40 | AUTOCONNECT = YES | ||
41 | TARGET-CONNECTION-COUNT = 16 | ||
42 | FRIENDS = $SERVICEHOME/friends | ||
43 | BINARY = gnunet-daemon-topology | ||
44 | |||
45 | [peerinfo] | ||
46 | PORT = 33006 | ||
47 | UNIXPATH = /tmp/gnunet-chat-p3-service-peerinfo.sock | ||
48 | HOSTNAME = localhost | ||
49 | |||
50 | [statistics] | ||
51 | PORT = 33007 | ||
52 | HOSTNAME = localhost | ||
53 | UNIXPATH = /tmp/gnunet-chat-p3-service-statistics.sock | ||
54 | |||
55 | [chat] | ||
56 | PORT = 33008 | ||
57 | HOSTNAME = localhost | ||
58 | HOME = $SERVICEHOME | ||
59 | BINARY = gnunet-service-chat | ||
60 | |||
61 | [testing] | ||
62 | WEAKRANDOM = YES | ||
63 | |||
64 | [fs] | ||
65 | AUTOSTART = NO | ||
66 | |||
67 | [datastore] | ||
68 | AUTOSTART = NO | ||
69 | |||
70 | [dht] | ||
71 | AUTOSTART = NO | ||
72 | |||
73 | [mesh] | ||
74 | AUTOSTART = NO | ||
75 | |||
76 | [nat] | ||
77 | DISABLEV6 = YES | ||
78 | BINDTO = 127.0.0.1 | ||
79 | ENABLE_UPNP = NO | ||
80 | BEHIND_NAT = NO | ||
81 | ALLOW_NAT = NO | ||
82 | INTERNAL_ADDRESS = 127.0.0.1 | ||
83 | EXTERNAL_ADDRESS = 127.0.0.1 | ||
84 | |||
85 | [dns] | ||
86 | AUTOSTART = NO | ||
87 | |||
88 | |||
89 | |||
90 | [nse] | ||
91 | AUTOSTART = NO | ||
92 | |||
93 | |||
diff --git a/src/chat/test_chat_private.c b/src/chat/test_chat_private.c deleted file mode 100644 index b911d091f..000000000 --- a/src/chat/test_chat_private.c +++ /dev/null | |||
@@ -1,640 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2011 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file chat/test_chat_private.c | ||
23 | * @brief testcase for private chatting | ||
24 | * @author Vitaly Minko | ||
25 | */ | ||
26 | |||
27 | #include "platform.h" | ||
28 | #include "gnunet_crypto_lib.h" | ||
29 | #include "gnunet_util_lib.h" | ||
30 | #include "gnunet_arm_service.h" | ||
31 | #include "gnunet_chat_service.h" | ||
32 | |||
33 | #define VERBOSE GNUNET_NO | ||
34 | |||
35 | /** | ||
36 | * How long until we give up on passing the test? | ||
37 | */ | ||
38 | #define KILL_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) | ||
39 | |||
40 | /** | ||
41 | * How long until we give up on receiving somebody else's private message? | ||
42 | */ | ||
43 | #define PM_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) | ||
44 | |||
45 | struct PeerContext | ||
46 | { | ||
47 | struct GNUNET_CONFIGURATION_Handle *cfg; | ||
48 | struct GNUNET_OS_Process *arm_proc; | ||
49 | }; | ||
50 | |||
51 | struct Wanted | ||
52 | { | ||
53 | struct GNUNET_CONTAINER_MetaData *meta; | ||
54 | |||
55 | struct GNUNET_HashCode *sender; | ||
56 | |||
57 | /** | ||
58 | * Alternative meta/sender is used when we expect join/leave notification | ||
59 | * from two peers and don't know which one will come first. | ||
60 | */ | ||
61 | struct GNUNET_CONTAINER_MetaData *meta2; | ||
62 | |||
63 | struct GNUNET_HashCode *sender2; | ||
64 | |||
65 | char *msg; | ||
66 | |||
67 | const char *me; | ||
68 | |||
69 | enum GNUNET_CHAT_MsgOptions opt; | ||
70 | |||
71 | struct GNUNET_TIME_Absolute timestamp; | ||
72 | |||
73 | GNUNET_SCHEDULER_Task next_task; | ||
74 | |||
75 | void *next_task_cls; | ||
76 | |||
77 | }; | ||
78 | |||
79 | static struct PeerContext p1; | ||
80 | |||
81 | static struct PeerContext p2; | ||
82 | |||
83 | static struct PeerContext p3; | ||
84 | |||
85 | static struct GNUNET_HashCode alice; | ||
86 | |||
87 | static struct GNUNET_HashCode bob; | ||
88 | |||
89 | static struct GNUNET_HashCode carol; | ||
90 | |||
91 | static struct GNUNET_CHAT_Room *alice_room; | ||
92 | |||
93 | static struct GNUNET_CHAT_Room *bob_room; | ||
94 | |||
95 | static struct GNUNET_CHAT_Room *carol_room; | ||
96 | |||
97 | static struct GNUNET_CONTAINER_MetaData *alice_meta; | ||
98 | |||
99 | static struct GNUNET_CONTAINER_MetaData *bob_meta; | ||
100 | |||
101 | static struct GNUNET_CONTAINER_MetaData *carol_meta; | ||
102 | |||
103 | static struct Wanted alice_wanted; | ||
104 | |||
105 | static struct Wanted bob_wanted; | ||
106 | |||
107 | static struct Wanted carol_wanted; | ||
108 | |||
109 | static GNUNET_SCHEDULER_TaskIdentifier kill_task; | ||
110 | |||
111 | static GNUNET_SCHEDULER_TaskIdentifier finish_task; | ||
112 | |||
113 | static GNUNET_SCHEDULER_TaskIdentifier wait_task; | ||
114 | |||
115 | static int err; | ||
116 | |||
117 | static int alice_ready; | ||
118 | |||
119 | static int bob_ready; | ||
120 | |||
121 | static int is_p2p; | ||
122 | |||
123 | static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *bob_public_key; | ||
124 | |||
125 | |||
126 | static void | ||
127 | setup_peer (struct PeerContext *p, const char *cfgname) | ||
128 | { | ||
129 | char *binary; | ||
130 | |||
131 | binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm"); | ||
132 | p->cfg = GNUNET_CONFIGURATION_create (); | ||
133 | p->arm_proc = | ||
134 | GNUNET_OS_start_process (GNUNET_YES, GNUNET_OS_INHERIT_STD_OUT_AND_ERR, NULL, NULL, binary, | ||
135 | "gnunet-service-arm", | ||
136 | "-c", cfgname, NULL); | ||
137 | GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); | ||
138 | GNUNET_free (binary); | ||
139 | } | ||
140 | |||
141 | |||
142 | static void | ||
143 | stop_arm (struct PeerContext *p) | ||
144 | { | ||
145 | if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) | ||
146 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); | ||
147 | if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) | ||
148 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); | ||
149 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", | ||
150 | GNUNET_OS_process_get_pid (p->arm_proc)); | ||
151 | GNUNET_OS_process_destroy (p->arm_proc); | ||
152 | p->arm_proc = NULL; | ||
153 | GNUNET_CONFIGURATION_destroy (p->cfg); | ||
154 | } | ||
155 | |||
156 | |||
157 | static void | ||
158 | abort_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
159 | { | ||
160 | if (alice_room != NULL) | ||
161 | { | ||
162 | GNUNET_CHAT_leave_room (alice_room); | ||
163 | alice_room = NULL; | ||
164 | } | ||
165 | if (bob_room != NULL) | ||
166 | { | ||
167 | GNUNET_CHAT_leave_room (bob_room); | ||
168 | bob_room = NULL; | ||
169 | } | ||
170 | if (carol_room != NULL) | ||
171 | { | ||
172 | GNUNET_CHAT_leave_room (carol_room); | ||
173 | carol_room = NULL; | ||
174 | } | ||
175 | err = 1; | ||
176 | } | ||
177 | |||
178 | |||
179 | static void | ||
180 | timeout_kill (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
181 | { | ||
182 | #if VERBOSE | ||
183 | printf ("Timed out, stopping the test.\n"); | ||
184 | #endif | ||
185 | kill_task = GNUNET_SCHEDULER_NO_TASK; | ||
186 | if (wait_task != GNUNET_SCHEDULER_NO_TASK) | ||
187 | { | ||
188 | GNUNET_SCHEDULER_cancel (wait_task); | ||
189 | wait_task = GNUNET_SCHEDULER_NO_TASK; | ||
190 | } | ||
191 | GNUNET_SCHEDULER_add_continuation (&abort_test, NULL, | ||
192 | GNUNET_SCHEDULER_REASON_PREREQ_DONE); | ||
193 | } | ||
194 | |||
195 | |||
196 | static int | ||
197 | join_cb (void *cls) | ||
198 | { | ||
199 | struct Wanted *want = cls; | ||
200 | |||
201 | #if VERBOSE | ||
202 | printf ("%s has joined\n", want->me); | ||
203 | #endif | ||
204 | if (NULL != want->next_task) | ||
205 | GNUNET_SCHEDULER_add_now (want->next_task, want->next_task_cls); | ||
206 | return GNUNET_OK; | ||
207 | } | ||
208 | |||
209 | |||
210 | static int | ||
211 | member_list_cb (void *cls, const struct GNUNET_CONTAINER_MetaData *member_info, | ||
212 | const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *member_id, | ||
213 | enum GNUNET_CHAT_MsgOptions options) | ||
214 | { | ||
215 | struct Wanted *want = cls; | ||
216 | struct GNUNET_HashCode sender; | ||
217 | |||
218 | #if VERBOSE | ||
219 | printf ("%s - told that %s has %s\n", want->me, | ||
220 | member_info == | ||
221 | NULL ? NULL : GNUNET_CONTAINER_meta_data_get_by_type (member_info, | ||
222 | EXTRACTOR_METATYPE_TITLE), | ||
223 | member_info == NULL ? "left" : "joined"); | ||
224 | #endif | ||
225 | GNUNET_CRYPTO_hash (member_id, | ||
226 | sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), | ||
227 | &sender); | ||
228 | /* entertain both primary and an alternative sender/meta */ | ||
229 | if (((0 == memcmp (&sender, want->sender, sizeof (struct GNUNET_HashCode))) || | ||
230 | ((want->sender2 != NULL) && | ||
231 | (0 == memcmp (&sender, want->sender2, sizeof (struct GNUNET_HashCode))))) && | ||
232 | (((member_info == NULL) && (want->meta == NULL)) || | ||
233 | ((member_info != NULL) && | ||
234 | (((want->meta != NULL) && | ||
235 | GNUNET_CONTAINER_meta_data_test_equal (member_info, want->meta)) || | ||
236 | ((want->meta2 != NULL) && | ||
237 | GNUNET_CONTAINER_meta_data_test_equal (member_info, want->meta2))))) | ||
238 | && (options == want->opt)) | ||
239 | { | ||
240 | /* remember Bob's public key, we need it to send private message */ | ||
241 | if (NULL == bob_public_key && | ||
242 | (0 == memcmp (&bob, want->sender, sizeof (struct GNUNET_HashCode)))) | ||
243 | bob_public_key = | ||
244 | GNUNET_memdup (member_id, | ||
245 | sizeof (struct | ||
246 | GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); | ||
247 | if (want->sender2 != NULL) | ||
248 | { | ||
249 | /* flush alternative sender */ | ||
250 | if (0 == memcmp (&sender, want->sender, sizeof (struct GNUNET_HashCode))) | ||
251 | { | ||
252 | want->sender = want->sender2; | ||
253 | want->meta = want->meta2; | ||
254 | } | ||
255 | want->sender2 = NULL; | ||
256 | want->meta2 = NULL; | ||
257 | } | ||
258 | else if (NULL != want->next_task) | ||
259 | GNUNET_SCHEDULER_add_now (want->next_task, want->next_task_cls); | ||
260 | } | ||
261 | else | ||
262 | { | ||
263 | GNUNET_SCHEDULER_cancel (kill_task); | ||
264 | kill_task = GNUNET_SCHEDULER_NO_TASK; | ||
265 | GNUNET_SCHEDULER_add_now (&abort_test, NULL); | ||
266 | } | ||
267 | return GNUNET_OK; | ||
268 | } | ||
269 | |||
270 | |||
271 | static int | ||
272 | receive_cb (void *cls, struct GNUNET_CHAT_Room *room, | ||
273 | const struct GNUNET_HashCode * sender, | ||
274 | const struct GNUNET_CONTAINER_MetaData *meta, const char *message, | ||
275 | struct GNUNET_TIME_Absolute timestamp, | ||
276 | enum GNUNET_CHAT_MsgOptions options) | ||
277 | { | ||
278 | struct Wanted *want = cls; | ||
279 | |||
280 | #if VERBOSE | ||
281 | printf ("%s - told that %s said '%s'\n", want->me, | ||
282 | meta == NULL ? NULL : GNUNET_CONTAINER_meta_data_get_by_type (meta, | ||
283 | EXTRACTOR_METATYPE_TITLE), | ||
284 | message); | ||
285 | #endif | ||
286 | |||
287 | if ((want->msg != NULL) && (0 == strcmp (message, want->msg)) && | ||
288 | (((sender == NULL) && (want->sender == NULL)) || | ||
289 | ((sender != NULL) && (want->sender != NULL) && | ||
290 | (0 == memcmp (sender, want->sender, sizeof (struct GNUNET_HashCode))))) && | ||
291 | (GNUNET_CONTAINER_meta_data_test_equal (meta, want->meta)) && | ||
292 | (options == want->opt) && | ||
293 | /* Not == since the library sets the actual timestamp, so it may be | ||
294 | * slightly greater | ||
295 | */ | ||
296 | (timestamp.abs_value >= want->timestamp.abs_value)) | ||
297 | { | ||
298 | if (NULL != want->next_task) | ||
299 | GNUNET_SCHEDULER_add_now (want->next_task, want->next_task_cls); | ||
300 | } | ||
301 | else | ||
302 | { | ||
303 | GNUNET_SCHEDULER_cancel (kill_task); | ||
304 | kill_task = GNUNET_SCHEDULER_NO_TASK; | ||
305 | GNUNET_SCHEDULER_cancel (finish_task); | ||
306 | finish_task = GNUNET_SCHEDULER_NO_TASK; | ||
307 | GNUNET_SCHEDULER_add_now (&abort_test, NULL); | ||
308 | } | ||
309 | return GNUNET_OK; | ||
310 | } | ||
311 | |||
312 | |||
313 | static void | ||
314 | wait_until_all_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
315 | { | ||
316 | GNUNET_SCHEDULER_Task task = cls; | ||
317 | |||
318 | #if VERBOSE | ||
319 | printf ("Waiting...\n"); | ||
320 | #endif | ||
321 | if (alice_ready && bob_ready) | ||
322 | { | ||
323 | wait_task = GNUNET_SCHEDULER_NO_TASK; | ||
324 | GNUNET_SCHEDULER_add_now (task, NULL); | ||
325 | } | ||
326 | else | ||
327 | wait_task = | ||
328 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
329 | (GNUNET_TIME_UNIT_MILLISECONDS, 5000), | ||
330 | &wait_until_all_ready, task); | ||
331 | } | ||
332 | |||
333 | |||
334 | static void | ||
335 | set_alice_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
336 | { | ||
337 | alice_ready = GNUNET_YES; | ||
338 | } | ||
339 | |||
340 | |||
341 | static void | ||
342 | set_bob_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
343 | { | ||
344 | bob_ready = GNUNET_YES; | ||
345 | } | ||
346 | |||
347 | |||
348 | static void | ||
349 | disconnect_alice (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
350 | { | ||
351 | #if VERBOSE | ||
352 | printf ("Alice is leaving.\n"); | ||
353 | #endif | ||
354 | if (is_p2p) | ||
355 | stop_arm (&p2); | ||
356 | GNUNET_CHAT_leave_room (alice_room); | ||
357 | alice_room = NULL; | ||
358 | GNUNET_SCHEDULER_cancel (kill_task); | ||
359 | kill_task = GNUNET_SCHEDULER_NO_TASK; | ||
360 | } | ||
361 | |||
362 | |||
363 | static void | ||
364 | disconnect_bob (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
365 | { | ||
366 | #if VERBOSE | ||
367 | printf ("Bod is leaving.\n"); | ||
368 | #endif | ||
369 | if (is_p2p) | ||
370 | stop_arm (&p3); | ||
371 | alice_wanted.meta = NULL; | ||
372 | alice_wanted.sender = &bob; | ||
373 | alice_wanted.msg = NULL; | ||
374 | alice_wanted.opt = 0; | ||
375 | alice_wanted.next_task = &disconnect_alice; | ||
376 | alice_wanted.next_task_cls = NULL; | ||
377 | GNUNET_CHAT_leave_room (bob_room); | ||
378 | bob_room = NULL; | ||
379 | } | ||
380 | |||
381 | |||
382 | static void | ||
383 | disconnect_carol (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
384 | { | ||
385 | #if VERBOSE | ||
386 | printf ("Carol is leaving.\n"); | ||
387 | #endif | ||
388 | alice_wanted.meta = NULL; | ||
389 | alice_wanted.sender = &carol; | ||
390 | alice_wanted.msg = NULL; | ||
391 | alice_wanted.opt = 0; | ||
392 | alice_wanted.next_task = &set_alice_ready; | ||
393 | alice_wanted.next_task_cls = NULL; | ||
394 | alice_ready = GNUNET_NO; | ||
395 | bob_wanted.meta = NULL; | ||
396 | bob_wanted.sender = &carol; | ||
397 | bob_wanted.msg = NULL; | ||
398 | bob_wanted.opt = 0; | ||
399 | bob_wanted.next_task = &wait_until_all_ready; | ||
400 | bob_wanted.next_task_cls = &disconnect_bob; | ||
401 | bob_ready = GNUNET_YES; | ||
402 | GNUNET_CHAT_leave_room (carol_room); | ||
403 | carol_room = NULL; | ||
404 | } | ||
405 | |||
406 | |||
407 | static void | ||
408 | send_from_alice_to_bob (void *cls, | ||
409 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
410 | { | ||
411 | uint32_t seq; | ||
412 | |||
413 | #if VERBOSE | ||
414 | printf ("Alice says 'Hi!' to Bob\n"); | ||
415 | #endif | ||
416 | alice_ready = GNUNET_YES; | ||
417 | bob_ready = GNUNET_NO; | ||
418 | bob_wanted.meta = alice_meta; | ||
419 | bob_wanted.sender = &alice; | ||
420 | bob_wanted.msg = "Hi Bob!"; | ||
421 | bob_wanted.opt = GNUNET_CHAT_MSG_PRIVATE; | ||
422 | bob_wanted.next_task = &set_bob_ready; | ||
423 | bob_wanted.next_task_cls = NULL; | ||
424 | /* Carol should not receive this message */ | ||
425 | carol_wanted.meta = NULL; | ||
426 | carol_wanted.sender = NULL; | ||
427 | carol_wanted.msg = NULL; | ||
428 | carol_wanted.opt = 0; | ||
429 | carol_wanted.next_task = NULL; | ||
430 | carol_wanted.next_task_cls = NULL; | ||
431 | GNUNET_CHAT_send_message (alice_room, "Hi Bob!", GNUNET_CHAT_MSG_PRIVATE, | ||
432 | bob_public_key, &seq); | ||
433 | finish_task = | ||
434 | GNUNET_SCHEDULER_add_delayed (PM_TIMEOUT, &wait_until_all_ready, | ||
435 | &disconnect_carol); | ||
436 | } | ||
437 | |||
438 | |||
439 | static void | ||
440 | prepare_bob_for_alice_task (void *cls, | ||
441 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
442 | { | ||
443 | bob_wanted.meta = alice_meta; | ||
444 | bob_wanted.sender = &alice; | ||
445 | bob_wanted.msg = NULL; | ||
446 | bob_wanted.opt = -1; | ||
447 | bob_wanted.next_task = &set_bob_ready; | ||
448 | bob_wanted.next_task_cls = NULL; | ||
449 | } | ||
450 | |||
451 | |||
452 | static void | ||
453 | prepare_carol_for_alice_and_bob_task (void *cls, | ||
454 | const struct GNUNET_SCHEDULER_TaskContext | ||
455 | *tc) | ||
456 | { | ||
457 | carol_wanted.meta = alice_meta; | ||
458 | carol_wanted.sender = &alice; | ||
459 | /* set alternative meta/sender since we don't know from which peer | ||
460 | * notification will come first */ | ||
461 | carol_wanted.meta2 = bob_meta; | ||
462 | carol_wanted.sender2 = &bob; | ||
463 | carol_wanted.msg = NULL; | ||
464 | carol_wanted.opt = -1; | ||
465 | carol_wanted.next_task = &wait_until_all_ready; | ||
466 | carol_wanted.next_task_cls = &send_from_alice_to_bob; | ||
467 | } | ||
468 | |||
469 | |||
470 | static void | ||
471 | join_carol_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
472 | { | ||
473 | #if VERBOSE | ||
474 | printf ("Carol joining\n"); | ||
475 | #endif | ||
476 | alice_wanted.meta = carol_meta; | ||
477 | alice_wanted.sender = &carol; | ||
478 | alice_wanted.msg = NULL; | ||
479 | alice_wanted.opt = -1; | ||
480 | alice_wanted.next_task = &set_alice_ready; | ||
481 | alice_wanted.next_task_cls = NULL; | ||
482 | alice_ready = GNUNET_NO; | ||
483 | bob_wanted.meta = carol_meta; | ||
484 | bob_wanted.sender = &carol; | ||
485 | bob_wanted.msg = NULL; | ||
486 | bob_wanted.opt = -1; | ||
487 | bob_wanted.next_task = &set_bob_ready; | ||
488 | bob_wanted.next_task_cls = NULL; | ||
489 | bob_ready = GNUNET_NO; | ||
490 | carol_wanted.next_task = &prepare_carol_for_alice_and_bob_task; | ||
491 | carol_wanted.next_task_cls = NULL; | ||
492 | carol_room = | ||
493 | GNUNET_CHAT_join_room (is_p2p ? p3.cfg : p1.cfg, "carol", carol_meta, | ||
494 | "test", -1, &join_cb, &carol_wanted, &receive_cb, | ||
495 | &carol_wanted, &member_list_cb, &carol_wanted, | ||
496 | NULL, NULL, &carol); | ||
497 | if (NULL == carol_room) | ||
498 | { | ||
499 | GNUNET_SCHEDULER_cancel (kill_task); | ||
500 | kill_task = GNUNET_SCHEDULER_NO_TASK; | ||
501 | GNUNET_CHAT_leave_room (alice_room); | ||
502 | alice_room = NULL; | ||
503 | GNUNET_CHAT_leave_room (bob_room); | ||
504 | bob_room = NULL; | ||
505 | err = 1; | ||
506 | } | ||
507 | } | ||
508 | |||
509 | |||
510 | static void | ||
511 | join_bob_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
512 | { | ||
513 | #if VERBOSE | ||
514 | printf ("Bob joining\n"); | ||
515 | #endif | ||
516 | alice_wanted.meta = bob_meta; | ||
517 | alice_wanted.sender = &bob; | ||
518 | alice_wanted.msg = NULL; | ||
519 | alice_wanted.opt = -1; | ||
520 | alice_wanted.next_task = &wait_until_all_ready; | ||
521 | alice_wanted.next_task_cls = &join_carol_task; | ||
522 | alice_ready = GNUNET_YES; | ||
523 | bob_wanted.next_task = &prepare_bob_for_alice_task; | ||
524 | bob_wanted.next_task_cls = NULL; | ||
525 | bob_ready = GNUNET_NO; | ||
526 | bob_room = | ||
527 | GNUNET_CHAT_join_room (is_p2p ? p2.cfg : p1.cfg, "bob", bob_meta, "test", | ||
528 | -1, &join_cb, &bob_wanted, &receive_cb, | ||
529 | &bob_wanted, &member_list_cb, &bob_wanted, NULL, | ||
530 | NULL, &bob); | ||
531 | if (NULL == bob_room) | ||
532 | { | ||
533 | GNUNET_SCHEDULER_cancel (kill_task); | ||
534 | kill_task = GNUNET_SCHEDULER_NO_TASK; | ||
535 | GNUNET_CHAT_leave_room (alice_room); | ||
536 | alice_room = NULL; | ||
537 | err = 1; | ||
538 | } | ||
539 | } | ||
540 | |||
541 | |||
542 | static void | ||
543 | join_alice_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
544 | { | ||
545 | #if VERBOSE | ||
546 | printf ("Alice joining\n"); | ||
547 | #endif | ||
548 | alice_wanted.next_task = &join_bob_task; | ||
549 | alice_wanted.next_task_cls = NULL; | ||
550 | alice_room = | ||
551 | GNUNET_CHAT_join_room (p1.cfg, "alice", alice_meta, "test", -1, &join_cb, | ||
552 | &alice_wanted, &receive_cb, &alice_wanted, | ||
553 | &member_list_cb, &alice_wanted, NULL, NULL, | ||
554 | &alice); | ||
555 | if (NULL == alice_room) | ||
556 | { | ||
557 | GNUNET_SCHEDULER_cancel (kill_task); | ||
558 | kill_task = GNUNET_SCHEDULER_NO_TASK; | ||
559 | err = 1; | ||
560 | } | ||
561 | } | ||
562 | |||
563 | |||
564 | static void | ||
565 | run (void *cls, char *const *args, const char *cfgfile, | ||
566 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
567 | { | ||
568 | if (is_p2p) | ||
569 | { | ||
570 | setup_peer (&p1, "test_chat_peer1.conf"); | ||
571 | setup_peer (&p2, "test_chat_peer2.conf"); | ||
572 | setup_peer (&p3, "test_chat_peer3.conf"); | ||
573 | } | ||
574 | else | ||
575 | setup_peer (&p1, "test_chat_data.conf"); | ||
576 | |||
577 | memset (&alice_wanted, 0, sizeof (struct Wanted)); | ||
578 | memset (&bob_wanted, 0, sizeof (struct Wanted)); | ||
579 | memset (&carol_wanted, 0, sizeof (struct Wanted)); | ||
580 | alice_wanted.me = "Alice"; | ||
581 | bob_wanted.me = "Bob"; | ||
582 | carol_wanted.me = "Carol"; | ||
583 | alice_meta = GNUNET_CONTAINER_meta_data_create (); | ||
584 | GNUNET_CONTAINER_meta_data_insert (alice_meta, "<gnunet>", | ||
585 | EXTRACTOR_METATYPE_TITLE, | ||
586 | EXTRACTOR_METAFORMAT_UTF8, "text/plain", | ||
587 | "Alice", strlen ("Alice") + 1); | ||
588 | bob_meta = GNUNET_CONTAINER_meta_data_create (); | ||
589 | GNUNET_CONTAINER_meta_data_insert (bob_meta, "<gnunet>", | ||
590 | EXTRACTOR_METATYPE_TITLE, | ||
591 | EXTRACTOR_METAFORMAT_UTF8, "text/plain", | ||
592 | "Bob", strlen ("Bob") + 1); | ||
593 | carol_meta = GNUNET_CONTAINER_meta_data_create (); | ||
594 | GNUNET_CONTAINER_meta_data_insert (carol_meta, "<gnunet>", | ||
595 | EXTRACTOR_METATYPE_TITLE, | ||
596 | EXTRACTOR_METAFORMAT_UTF8, "text/plain", | ||
597 | "Carol", strlen ("Carol") + 1); | ||
598 | kill_task = GNUNET_SCHEDULER_add_delayed (KILL_TIMEOUT, &timeout_kill, NULL); | ||
599 | GNUNET_SCHEDULER_add_now (&join_alice_task, NULL); | ||
600 | } | ||
601 | |||
602 | |||
603 | int | ||
604 | main (int argc, char *argv[]) | ||
605 | { | ||
606 | char *const argvx[] = { | ||
607 | "test-chat", | ||
608 | "-c", | ||
609 | "test_chat_data.conf", | ||
610 | NULL | ||
611 | }; | ||
612 | struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
613 | GNUNET_GETOPT_OPTION_END | ||
614 | }; | ||
615 | |||
616 | GNUNET_log_setup ("test_chat", | ||
617 | "WARNING", | ||
618 | NULL); | ||
619 | if (strstr (argv[0], "p2p") != NULL) | ||
620 | { | ||
621 | is_p2p = GNUNET_YES; | ||
622 | } | ||
623 | GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, | ||
624 | "test-chat", "nohelp", options, &run, NULL); | ||
625 | stop_arm (&p1); | ||
626 | GNUNET_CONTAINER_meta_data_destroy (alice_meta); | ||
627 | GNUNET_CONTAINER_meta_data_destroy (bob_meta); | ||
628 | GNUNET_CONTAINER_meta_data_destroy (carol_meta); | ||
629 | if (is_p2p) | ||
630 | { | ||
631 | GNUNET_DISK_directory_remove ("/tmp/gnunet-test-chat-peer-1/"); | ||
632 | GNUNET_DISK_directory_remove ("/tmp/gnunet-test-chat-peer-2/"); | ||
633 | GNUNET_DISK_directory_remove ("/tmp/gnunet-test-chat-peer-3/"); | ||
634 | } | ||
635 | else | ||
636 | GNUNET_DISK_directory_remove ("/tmp/gnunet-test-chat/"); | ||
637 | return err; | ||
638 | } | ||
639 | |||
640 | /* end of test_chat_private.c */ | ||