2 This file is part of GNUnet.
3 (C) 2009, 2011 Christian Grothoff (and other contributing authors)
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.
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.
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.
22 * @file chat/gnunet-service-chat.c
23 * @brief service providing chat functionality
24 * @author Christian Grothoff
25 * @author Vitaly Minko
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"
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
40 #define MAX_ANONYMOUS_MSG_LIST_LENGTH 16
44 * Linked list of our current clients.
48 struct ChatClient *next;
51 * Handle for a chat client (NULL for external clients).
53 struct GNUNET_SERVER_Client *client;
56 * Public key of the client.
58 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key;
61 * Name of the room which the client is in.
66 * Serialized metadata of the client.
71 * Hash of the public key (for convenience).
76 * Options which the client is willing to receive.
81 * Length of serialized metadata in member_info.
86 * Sequence number of the last message sent by the client.
88 uint32_t msg_sequence_number;
91 * Sequence number of the last receipt sent by the client.
92 * Used to discard already processed receipts.
94 uint32_t rcpt_sequence_number;
99 * Information about a peer that we are connected to.
100 * We track data that is useful for determining which
101 * peers should receive our requests.
106 * The peer's identity.
112 * Linked list of recent anonymous messages.
114 struct AnonymousMessage
116 struct AnonymousMessage *next;
119 * Hash of the message.
121 GNUNET_HashCode hash;
127 * Handle to the core service (NULL until we've connected to it).
129 static struct GNUNET_CORE_Handle *core;
134 static const struct GNUNET_CONFIGURATION_Handle *cfg;
137 * The identity of this host.
139 static const struct GNUNET_PeerIdentity *me;
142 * Head of the list of current clients.
144 static struct ChatClient *client_list_head = NULL;
147 * Notification context containing all connected clients.
149 struct GNUNET_SERVER_NotificationContext *nc = NULL;
152 * Head of the list of recent anonymous messages.
154 static struct AnonymousMessage *anonymous_list_head = NULL;
157 * Map of peer identifiers to "struct ConnectedPeer" (for that peer).
159 static struct GNUNET_CONTAINER_MultiHashMap *connected_peers;
163 remember_anonymous_message (const struct P2PReceiveNotificationMessage
166 static GNUNET_HashCode hash;
167 struct AnonymousMessage *anon_msg;
168 struct AnonymousMessage *prev;
171 GNUNET_CRYPTO_hash (p2p_rnmsg, ntohs (p2p_rnmsg->header.size), &hash);
172 anon_msg = GNUNET_malloc (sizeof (struct AnonymousMessage));
173 anon_msg->hash = hash;
174 anon_msg->next = anonymous_list_head;
175 anonymous_list_head = anon_msg;
178 while ((NULL != anon_msg->next))
181 anon_msg = anon_msg->next;
184 if (anon_list_len == MAX_ANONYMOUS_MSG_LIST_LENGTH)
186 GNUNET_free (anon_msg);
194 lookup_anonymous_message (const struct P2PReceiveNotificationMessage *p2p_rnmsg)
196 static GNUNET_HashCode hash;
197 struct AnonymousMessage *anon_msg;
199 GNUNET_CRYPTO_hash (p2p_rnmsg, ntohs (p2p_rnmsg->header.size), &hash);
200 anon_msg = anonymous_list_head;
201 while ((NULL != anon_msg) &&
202 (0 != memcmp (&anon_msg->hash, &hash, sizeof (GNUNET_HashCode))))
203 anon_msg = anon_msg->next;
204 return (NULL != anon_msg);
209 * Transmit a message notification to the peer.
211 * @param cls closure, pointer to the 'struct P2PReceiveNotificationMessage'
212 * @param size number of bytes available in buf
213 * @param buf where the callee should write the message
214 * @return number of bytes written to buf
217 transmit_message_notification_to_peer (void *cls, size_t size, void *buf)
219 struct P2PReceiveNotificationMessage *my_msg = cls;
220 struct P2PReceiveNotificationMessage *m = buf;
223 #if DEBUG_CHAT_SERVICE
224 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
225 "Transmitting P2P message notification\n");
229 /* client disconnected */
230 #if DEBUG_CHAT_SERVICE
231 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
232 "Buffer is NULL, dropping the message\n");
236 msg_size = ntohs (my_msg->header.size);
237 GNUNET_assert (size >= msg_size);
238 memcpy (m, my_msg, msg_size);
239 GNUNET_free (my_msg);
245 * Ask to send a message notification to the peer.
248 send_message_noficiation (void *cls, const GNUNET_HashCode * key, void *value)
250 struct P2PReceiveNotificationMessage *msg = cls;
251 struct ConnectedPeer *cp = value;
252 struct GNUNET_PeerIdentity pid;
253 struct P2PReceiveNotificationMessage *my_msg;
255 GNUNET_PEER_resolve (cp->pid, &pid);
256 #if DEBUG_CHAT_SERVICE
257 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message notification to `%s'\n",
260 my_msg = GNUNET_memdup (msg, ntohs (msg->header.size));
262 GNUNET_CORE_notify_transmit_ready (core, GNUNET_NO, 1, MAX_TRANSMIT_DELAY,
263 &pid, ntohs (msg->header.size),
264 &transmit_message_notification_to_peer,
266 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
267 _("Failed to queue a message notification\n"));
273 * A client sent a chat message. Encrypt the message text if the message is
274 * private. Send the message to local room members and to all connected peers.
276 * @param cls closure, NULL
277 * @param client identification of the client
278 * @param message the actual message
281 handle_transmit_request (void *cls, struct GNUNET_SERVER_Client *client,
282 const struct GNUNET_MessageHeader *message)
284 static GNUNET_HashCode all_zeros;
285 const struct TransmitRequestMessage *trmsg;
286 struct ReceiveNotificationMessage *rnmsg;
287 struct P2PReceiveNotificationMessage *p2p_rnmsg;
288 struct ChatClient *pos;
289 struct ChatClient *target;
290 struct GNUNET_CRYPTO_AesSessionKey key;
291 char encrypted_msg[MAX_MESSAGE_LENGTH];
298 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client sent a chat message\n");
299 if (ntohs (message->size) <= sizeof (struct TransmitRequestMessage))
301 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n");
303 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
306 trmsg = (const struct TransmitRequestMessage *) message;
307 msg_len = ntohs (trmsg->header.size) - sizeof (struct TransmitRequestMessage);
308 is_priv = (0 != (ntohl (trmsg->msg_options) & GNUNET_CHAT_MSG_PRIVATE));
311 #if DEBUG_CHAT_SERVICE
312 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypting the message text\n");
314 GNUNET_CRYPTO_aes_create_session_key (&key);
316 GNUNET_CRYPTO_aes_encrypt (&trmsg[1], msg_len, &key,
318 GNUNET_CRYPTO_AesInitializationVector *)
319 INITVALUE, encrypted_msg);
322 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
323 "Could not encrypt the message text\n");
325 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
329 rnmsg = GNUNET_malloc (sizeof (struct ReceiveNotificationMessage) + msg_len);
331 htons (sizeof (struct ReceiveNotificationMessage) + msg_len);
332 rnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION);
333 rnmsg->msg_options = trmsg->msg_options;
334 rnmsg->timestamp = trmsg->timestamp;
335 pos = client_list_head;
336 while ((NULL != pos) && (pos->client != client))
340 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
341 "The client is not a member of a chat room. Client has to "
342 "join a chat room first\n");
344 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
349 pos->msg_sequence_number = ntohl (trmsg->sequence_number);
350 is_anon = (0 != (ntohl (trmsg->msg_options) & GNUNET_CHAT_MSG_ANONYMOUS));
353 memset (&rnmsg->sender, 0, sizeof (GNUNET_HashCode));
354 rnmsg->sequence_number = 0;
358 rnmsg->sender = pos->id;
359 rnmsg->sequence_number = trmsg->sequence_number;
363 #if DEBUG_CHAT_SERVICE
364 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
365 "Encrypting the session key using the public key of '%s'\n",
366 GNUNET_h2s (&trmsg->target));
368 if (0 == memcmp (&all_zeros, &trmsg->target, sizeof (GNUNET_HashCode)))
370 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
371 "Malformed message: private, but no target\n");
373 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
377 memcpy (&rnmsg[1], encrypted_msg, msg_len);
378 target = client_list_head;
379 while ((NULL != target) &&
381 memcmp (&target->id, &trmsg->target, sizeof (GNUNET_HashCode))))
382 target = target->next;
385 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
386 "Unknown target of the private message\n");
388 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
393 GNUNET_CRYPTO_rsa_encrypt (&key,
394 sizeof (struct GNUNET_CRYPTO_AesSessionKey),
395 &target->public_key, &rnmsg->encrypted_key))
397 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
398 "Could not encrypt the session key\n");
400 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
407 memcpy (&rnmsg[1], &trmsg[1], msg_len);
409 pos = client_list_head;
410 #if DEBUG_CHAT_SERVICE
411 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
412 "Sending message to local room members\n");
416 if ((0 == strcmp (room, pos->room)) && (NULL != pos->client) &&
417 (pos->client != client))
420 (0 == memcmp (&trmsg->target, &pos->id, sizeof (GNUNET_HashCode))))
421 && (0 == (ntohl (trmsg->msg_options) & (~pos->msg_options))))
423 GNUNET_SERVER_notification_context_unicast (nc, pos->client,
424 &rnmsg->header, GNUNET_NO);
429 #if DEBUG_CHAT_SERVICE
430 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
431 "Broadcasting message to neighbour peers\n");
435 room_len = strlen (room);
437 GNUNET_malloc (sizeof (struct P2PReceiveNotificationMessage) + msg_len +
439 p2p_rnmsg->header.size =
440 htons (sizeof (struct P2PReceiveNotificationMessage) + msg_len +
442 p2p_rnmsg->room_name_len = htons (room_len);
443 memcpy ((char *) &p2p_rnmsg[1], room, room_len);
444 memcpy ((char *) &p2p_rnmsg[1] + room_len, &trmsg[1], msg_len);
449 GNUNET_malloc (sizeof (struct P2PReceiveNotificationMessage) + msg_len);
450 p2p_rnmsg->header.size =
451 htons (sizeof (struct P2PReceiveNotificationMessage) + msg_len);
454 memcpy (&p2p_rnmsg[1], encrypted_msg, msg_len);
455 memcpy (&p2p_rnmsg->encrypted_key, &rnmsg->encrypted_key,
456 sizeof (struct GNUNET_CRYPTO_RsaEncryptedData));
459 memcpy (&p2p_rnmsg[1], &trmsg[1], msg_len);
461 p2p_rnmsg->header.type =
462 htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_MESSAGE_NOTIFICATION);
463 p2p_rnmsg->msg_options = trmsg->msg_options;
464 p2p_rnmsg->sequence_number = trmsg->sequence_number;
465 p2p_rnmsg->timestamp = trmsg->timestamp;
466 p2p_rnmsg->reserved = htons (0);
467 p2p_rnmsg->sender = rnmsg->sender;
468 p2p_rnmsg->target = trmsg->target;
470 remember_anonymous_message (p2p_rnmsg);
471 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
472 &send_message_noficiation, p2p_rnmsg);
473 GNUNET_free (p2p_rnmsg);
474 GNUNET_SERVER_receive_done (client, GNUNET_OK);
480 * Transmit a join notification to the peer.
482 * @param cls closure, pointer to the 'struct ChatClient'
483 * @param size number of bytes available in buf
484 * @param buf where the callee should write the message
485 * @return number of bytes written to buf
488 transmit_join_notification_to_peer (void *cls, size_t size, void *buf)
490 struct ChatClient *entry = cls;
491 struct P2PJoinNotificationMessage *m = buf;
497 #if DEBUG_CHAT_SERVICE
498 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting P2P join notification\n");
500 room_len = strlen (entry->room);
501 meta_len = entry->meta_len;
502 msg_size = sizeof (struct P2PJoinNotificationMessage) + meta_len + room_len;
503 GNUNET_assert (size >= msg_size);
504 GNUNET_assert (NULL != buf);
506 m->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_JOIN_NOTIFICATION);
507 m->header.size = htons (msg_size);
508 m->msg_options = htonl (entry->msg_options);
509 m->room_name_len = htons (room_len);
510 m->reserved = htons (0);
511 m->reserved2 = htonl (0);
512 m->public_key = entry->public_key;
513 roomptr = (char *) &m[1];
514 memcpy (roomptr, entry->room, room_len);
516 memcpy (&roomptr[room_len], entry->member_info, meta_len);
522 * Ask to send a join notification to the peer.
525 send_join_noficiation (void *cls, const GNUNET_HashCode * key, void *value)
527 struct ChatClient *entry = cls;
528 struct ConnectedPeer *cp = value;
529 struct GNUNET_PeerIdentity pid;
532 GNUNET_PEER_resolve (cp->pid, &pid);
533 #if DEBUG_CHAT_SERVICE
534 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending join notification to `%s'\n",
538 sizeof (struct P2PJoinNotificationMessage) + strlen (entry->room) +
541 GNUNET_CORE_notify_transmit_ready (core, GNUNET_NO, 1, MAX_TRANSMIT_DELAY,
543 &transmit_join_notification_to_peer,
545 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
546 _("Failed to queue a join notification\n"));
552 * A client asked for entering a chat room. Add the new member to the list of
553 * clients and notify remaining room members.
555 * @param cls closure, NULL
556 * @param client identification of the client
557 * @param message the actual message
560 handle_join_request (void *cls, struct GNUNET_SERVER_Client *client,
561 const struct GNUNET_MessageHeader *message)
563 const struct JoinRequestMessage *jrmsg;
566 uint16_t header_size;
568 uint16_t room_name_len;
569 struct ChatClient *new_entry;
570 struct ChatClient *entry;
571 struct JoinNotificationMessage *jnmsg;
572 struct JoinNotificationMessage *entry_jnmsg;
574 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client sent a join request\n");
575 if (ntohs (message->size) <= sizeof (struct JoinRequestMessage))
577 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n");
579 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
582 jrmsg = (const struct JoinRequestMessage *) message;
583 header_size = ntohs (jrmsg->header.size);
584 room_name_len = ntohs (jrmsg->room_name_len);
585 if (header_size - sizeof (struct JoinRequestMessage) <= room_name_len)
587 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
588 "Malformed message: wrong length of the room name\n");
590 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
593 meta_len = header_size - sizeof (struct JoinRequestMessage) - room_name_len;
594 roomptr = (const char *) &jrmsg[1];
595 room_name = GNUNET_malloc (room_name_len + 1);
596 memcpy (room_name, roomptr, room_name_len);
597 room_name[room_name_len] = '\0';
598 new_entry = GNUNET_malloc (sizeof (struct ChatClient));
599 memset (new_entry, 0, sizeof (struct ChatClient));
600 new_entry->client = client;
601 new_entry->room = room_name;
602 new_entry->public_key = jrmsg->public_key;
603 new_entry->meta_len = meta_len;
606 new_entry->member_info = GNUNET_malloc (meta_len);
607 memcpy (new_entry->member_info, &roomptr[room_name_len], meta_len);
610 new_entry->member_info = NULL;
611 GNUNET_CRYPTO_hash (&new_entry->public_key,
612 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
614 new_entry->msg_options = ntohl (jrmsg->msg_options);
615 new_entry->next = client_list_head;
616 client_list_head = new_entry;
617 #if DEBUG_CHAT_SERVICE
618 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
619 "Synchronizing room members between local clients\n");
621 jnmsg = GNUNET_malloc (sizeof (struct JoinNotificationMessage) + meta_len);
622 jnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION);
624 htons (sizeof (struct JoinNotificationMessage) + meta_len);
625 jnmsg->msg_options = jrmsg->msg_options;
626 jnmsg->public_key = new_entry->public_key;
627 memcpy (&jnmsg[1], &roomptr[room_name_len], meta_len);
628 GNUNET_SERVER_notification_context_add (nc, client);
629 entry = client_list_head;
630 while (NULL != entry)
632 if (0 == strcmp (room_name, entry->room))
634 if (NULL != entry->client)
635 GNUNET_SERVER_notification_context_unicast (nc, entry->client,
636 &jnmsg->header, GNUNET_NO);
637 if (entry->client != client)
640 GNUNET_malloc (sizeof (struct JoinNotificationMessage) +
642 entry_jnmsg->header.type =
643 htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION);
644 entry_jnmsg->header.size =
645 htons (sizeof (struct JoinNotificationMessage) + entry->meta_len);
646 entry_jnmsg->msg_options = entry->msg_options;
647 entry_jnmsg->public_key = entry->public_key;
648 memcpy (&entry_jnmsg[1], entry->member_info, entry->meta_len);
649 GNUNET_SERVER_notification_context_unicast (nc, client,
650 &entry_jnmsg->header,
652 GNUNET_free (entry_jnmsg);
657 #if DEBUG_CHAT_SERVICE
658 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
659 "Broadcasting join notification to neighbour peers\n");
661 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
662 &send_join_noficiation, new_entry);
663 GNUNET_SERVER_receive_done (client, GNUNET_OK);
668 * Transmit a confirmation receipt to the peer.
670 * @param cls closure, pointer to the 'struct P2PConfirmationReceiptMessage'
671 * @param size number of bytes available in buf
672 * @param buf where the callee should write the message
673 * @return number of bytes written to buf
676 transmit_confirmation_receipt_to_peer (void *cls, size_t size, void *buf)
678 struct P2PConfirmationReceiptMessage *receipt = cls;
681 #if DEBUG_CHAT_SERVICE
682 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
683 "Transmitting P2P confirmation receipt to '%s'\n",
684 GNUNET_h2s (&receipt->target));
688 /* client disconnected */
689 #if DEBUG_CHAT_SERVICE
690 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
691 "Buffer is NULL, dropping the message\n");
695 msg_size = sizeof (struct P2PConfirmationReceiptMessage);
696 GNUNET_assert (size >= msg_size);
697 memcpy (buf, receipt, msg_size);
698 GNUNET_free (receipt);
704 * Ask to send a confirmation receipt to the peer.
707 send_confirmation_receipt (void *cls, const GNUNET_HashCode * key, void *value)
709 struct P2PConfirmationReceiptMessage *receipt = cls;
710 struct ConnectedPeer *cp = value;
711 struct GNUNET_PeerIdentity pid;
712 struct P2PConfirmationReceiptMessage *my_receipt;
715 GNUNET_PEER_resolve (cp->pid, &pid);
716 #if DEBUG_CHAT_SERVICE
717 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending confirmation receipt to `%s'\n",
720 msg_size = sizeof (struct P2PConfirmationReceiptMessage);
722 GNUNET_memdup (receipt, sizeof (struct P2PConfirmationReceiptMessage));
724 GNUNET_CORE_notify_transmit_ready (core, GNUNET_YES, 1,
725 MAX_TRANSMIT_DELAY, &pid, msg_size,
726 &transmit_confirmation_receipt_to_peer,
728 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
729 _("Failed to queue a confirmation receipt\n"));
735 * A client sent a confirmation receipt. Broadcast the receipt to all connected
736 * peers if the author of the original message is a local client. Otherwise
737 * check the signature and notify the user if the signature is valid.
739 * @param cls closure, NULL
740 * @param client identification of the client
741 * @param message the actual message
744 handle_acknowledge_request (void *cls, struct GNUNET_SERVER_Client *client,
745 const struct GNUNET_MessageHeader *message)
747 const struct ConfirmationReceiptMessage *receipt;
748 struct ConfirmationReceiptMessage *crmsg;
749 struct P2PConfirmationReceiptMessage *p2p_crmsg;
750 struct ChatClient *target;
751 struct ChatClient *author;
753 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client sent a confirmation receipt\n");
754 receipt = (const struct ConfirmationReceiptMessage *) message;
755 author = client_list_head;
756 while ((NULL != author) &&
758 memcmp (&receipt->author, &author->id, sizeof (GNUNET_HashCode))))
759 author = author->next;
762 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
763 "Unknown author of the original message\n");
765 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
768 target = client_list_head;
769 while ((NULL != target) &&
771 memcmp (&receipt->target, &target->id, sizeof (GNUNET_HashCode))))
772 target = target->next;
775 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
776 "Unknown target of the confirmation receipt\n");
778 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
781 if (NULL == author->client)
783 target->rcpt_sequence_number++;
784 #if DEBUG_CHAT_SERVICE
785 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
786 "Broadcasting %s's receipt #%u to neighbour peers\n",
787 GNUNET_h2s (&target->id), target->rcpt_sequence_number);
789 p2p_crmsg = GNUNET_malloc (sizeof (struct P2PConfirmationReceiptMessage));
790 p2p_crmsg->header.size =
791 htons (sizeof (struct P2PConfirmationReceiptMessage));
792 p2p_crmsg->header.type =
793 htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_CONFIRMATION_RECEIPT);
794 p2p_crmsg->reserved = htonl (0);
795 p2p_crmsg->signature = receipt->signature;
796 p2p_crmsg->purpose = receipt->purpose;
797 p2p_crmsg->msg_sequence_number = receipt->sequence_number;
798 p2p_crmsg->timestamp = receipt->timestamp;
799 p2p_crmsg->target = receipt->target;
800 p2p_crmsg->author = receipt->author;
801 p2p_crmsg->content = receipt->content;
802 p2p_crmsg->sequence_number = htonl (target->rcpt_sequence_number);
803 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
804 &send_confirmation_receipt,
806 GNUNET_free (p2p_crmsg);
810 #if DEBUG_CHAT_SERVICE
811 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
812 "Verifying signature of the receipt\n");
815 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_CHAT_RECEIPT,
816 &receipt->purpose, &receipt->signature,
817 &target->public_key))
819 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
820 "Invalid signature of the receipt\n");
822 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
825 #if DEBUG_CHAT_SERVICE
826 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
827 "Sending receipt to the client which sent the original message\n");
829 crmsg = GNUNET_memdup (receipt, sizeof (struct ConfirmationReceiptMessage));
831 htons (GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION);
832 GNUNET_SERVER_notification_context_unicast (nc, author->client,
833 &crmsg->header, GNUNET_NO);
836 GNUNET_SERVER_receive_done (client, GNUNET_OK);
841 * Transmit a leave notification to the peer.
843 * @param cls closure, pointer to the
844 * 'struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded'
845 * @param size number of bytes available in buf
846 * @param buf where the callee should write the message
847 * @return number of bytes written to buf
850 transmit_leave_notification_to_peer (void *cls, size_t size, void *buf)
852 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key = cls;
853 struct P2PLeaveNotificationMessage *m = buf;
856 #if DEBUG_CHAT_SERVICE
857 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting P2P leave notification\n");
861 /* client disconnected */
862 #if DEBUG_CHAT_SERVICE
863 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
864 "Buffer is NULL, dropping the message\n");
868 msg_size = sizeof (struct P2PLeaveNotificationMessage);
869 GNUNET_assert (size >= msg_size);
871 m->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_LEAVE_NOTIFICATION);
872 m->header.size = htons (msg_size);
873 m->reserved = htonl (0);
874 m->user = *public_key;
875 GNUNET_free (public_key);
881 * Ask to send a leave notification to the peer.
884 send_leave_noficiation (void *cls, const GNUNET_HashCode * key, void *value)
886 struct ChatClient *entry = cls;
887 struct ConnectedPeer *cp = value;
888 struct GNUNET_PeerIdentity pid;
889 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key;
892 GNUNET_PEER_resolve (cp->pid, &pid);
893 #if DEBUG_CHAT_SERVICE
894 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending leave notification to `%s'\n",
897 msg_size = sizeof (struct P2PLeaveNotificationMessage);
899 GNUNET_memdup (&entry->public_key,
900 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
902 GNUNET_CORE_notify_transmit_ready (core, GNUNET_YES, 1,
903 MAX_TRANSMIT_DELAY, &pid, msg_size,
904 &transmit_leave_notification_to_peer,
906 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
907 _("Failed to queue a leave notification\n"));
913 * A client disconnected. Remove all of its data structure entries and notify
914 * remaining room members.
916 * @param cls closure, NULL
917 * @param client identification of the client
920 handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
922 struct ChatClient *entry;
923 struct ChatClient *pos;
924 struct ChatClient *prev;
925 struct LeaveNotificationMessage lnmsg;
927 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client disconnected\n");
928 pos = client_list_head;
930 while ((NULL != pos) && (pos->client != client))
937 #if DEBUG_CHAT_SERVICE
938 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
939 "No such client. There is nothing to do\n");
944 client_list_head = pos->next;
946 prev->next = pos->next;
947 entry = client_list_head;
948 #if DEBUG_CHAT_SERVICE
949 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
950 "Notifying local room members that the client has disconnected\n");
952 lnmsg.header.size = htons (sizeof (struct LeaveNotificationMessage));
953 lnmsg.header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION);
954 lnmsg.reserved = htonl (0);
955 lnmsg.user = pos->public_key;
956 while (NULL != entry)
958 if ((0 == strcmp (pos->room, entry->room)) && (NULL != entry->client))
960 GNUNET_SERVER_notification_context_unicast (nc, entry->client,
961 &lnmsg.header, GNUNET_NO);
965 #if DEBUG_CHAT_SERVICE
966 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
967 "Broadcasting leave notification to neighbour peers\n");
969 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
970 &send_leave_noficiation, pos);
971 GNUNET_free (pos->room);
972 GNUNET_free_non_null (pos->member_info);
978 * Handle P2P join notification.
980 * @param cls closure, always NULL
981 * @param other the other peer involved
982 * @param message the actual message
983 * @param atsi performance information
984 * @param atsi_count number of entries in atsi
985 * @return GNUNET_OK to keep the connection open,
986 * GNUNET_SYSERR to close it (signal serious error)
989 handle_p2p_join_notification (void *cls,
990 const struct GNUNET_PeerIdentity *other,
991 const struct GNUNET_MessageHeader *message,
992 const struct GNUNET_ATS_Information
994 unsigned int atsi_count)
996 const struct P2PJoinNotificationMessage *p2p_jnmsg;
999 uint16_t header_size;
1001 uint16_t room_name_len;
1002 struct ChatClient *new_entry;
1003 struct ChatClient *entry;
1004 struct JoinNotificationMessage *jnmsg;
1007 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P join notification\n");
1008 if (ntohs (message->size) <= sizeof (struct P2PJoinNotificationMessage))
1010 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n");
1011 GNUNET_break_op (0);
1012 return GNUNET_SYSERR;
1014 p2p_jnmsg = (const struct P2PJoinNotificationMessage *) message;
1015 header_size = ntohs (p2p_jnmsg->header.size);
1016 room_name_len = ntohs (p2p_jnmsg->room_name_len);
1017 if (header_size - sizeof (struct P2PJoinNotificationMessage) <= room_name_len)
1019 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1020 "Malformed message: wrong length of the room name\n");
1021 GNUNET_break_op (0);
1022 return GNUNET_SYSERR;
1024 GNUNET_CRYPTO_hash (&p2p_jnmsg->public_key,
1025 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1027 entry = client_list_head;
1028 while (NULL != entry)
1030 if (0 == memcmp (&entry->id, &id, sizeof (GNUNET_HashCode)))
1032 #if DEBUG_CHAT_SERVICE
1033 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1034 "The client has already joined. There is nothing to do\n");
1038 entry = entry->next;
1041 header_size - sizeof (struct P2PJoinNotificationMessage) - room_name_len;
1042 roomptr = (const char *) &p2p_jnmsg[1];
1043 room_name = GNUNET_malloc (room_name_len + 1);
1044 memcpy (room_name, roomptr, room_name_len);
1045 room_name[room_name_len] = '\0';
1046 new_entry = GNUNET_malloc (sizeof (struct ChatClient));
1047 memset (new_entry, 0, sizeof (struct ChatClient));
1049 new_entry->client = NULL;
1050 new_entry->room = room_name;
1051 new_entry->public_key = p2p_jnmsg->public_key;
1052 new_entry->meta_len = meta_len;
1055 new_entry->member_info = GNUNET_malloc (meta_len);
1056 memcpy (new_entry->member_info, &roomptr[room_name_len], meta_len);
1059 new_entry->member_info = NULL;
1060 new_entry->msg_options = ntohl (p2p_jnmsg->msg_options);
1061 new_entry->next = client_list_head;
1062 client_list_head = new_entry;
1063 #if DEBUG_CHAT_SERVICE
1064 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1065 "Notifying local room members that we have a new client\n");
1067 jnmsg = GNUNET_malloc (sizeof (struct JoinNotificationMessage) + meta_len);
1068 jnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION);
1069 jnmsg->header.size =
1070 htons (sizeof (struct JoinNotificationMessage) + meta_len);
1071 jnmsg->msg_options = p2p_jnmsg->msg_options;
1072 jnmsg->public_key = new_entry->public_key;
1073 memcpy (&jnmsg[1], &roomptr[room_name_len], meta_len);
1074 entry = client_list_head;
1075 while (NULL != entry)
1077 if ((0 == strcmp (room_name, entry->room)) && (NULL != entry->client))
1079 GNUNET_SERVER_notification_context_unicast (nc, entry->client,
1080 &jnmsg->header, GNUNET_NO);
1082 entry = entry->next;
1084 #if DEBUG_CHAT_SERVICE
1085 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1086 "Broadcasting join notification to neighbour peers\n");
1088 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
1089 &send_join_noficiation, new_entry);
1090 GNUNET_free (jnmsg);
1096 * Handle P2P leave notification.
1098 * @param cls closure, always NULL
1099 * @param other the other peer involved
1100 * @param message the actual message
1101 * @param atsi performance information
1102 * @param atsi_count number of entries in atsi
1103 * @return GNUNET_OK to keep the connection open,
1104 * GNUNET_SYSERR to close it (signal serious error)
1107 handle_p2p_leave_notification (void *cls,
1108 const struct GNUNET_PeerIdentity *other,
1109 const struct GNUNET_MessageHeader *message,
1110 const struct GNUNET_ATS_Information
1112 unsigned int atsi_count)
1114 const struct P2PLeaveNotificationMessage *p2p_lnmsg;
1116 struct ChatClient *pos;
1117 struct ChatClient *prev;
1118 struct ChatClient *entry;
1119 struct LeaveNotificationMessage lnmsg;
1121 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P leave notification\n");
1122 p2p_lnmsg = (const struct P2PLeaveNotificationMessage *) message;
1123 GNUNET_CRYPTO_hash (&p2p_lnmsg->user,
1124 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1126 pos = client_list_head;
1130 if (0 == memcmp (&pos->id, &id, sizeof (GNUNET_HashCode)))
1137 #if DEBUG_CHAT_SERVICE
1138 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1139 "No such client. There is nothing to do\n");
1144 client_list_head = pos->next;
1146 prev->next = pos->next;
1147 #if DEBUG_CHAT_SERVICE
1148 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1149 "Notifying local room members that the client has gone away\n");
1151 lnmsg.header.size = htons (sizeof (struct LeaveNotificationMessage));
1152 lnmsg.header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION);
1153 lnmsg.reserved = htonl (0);
1154 lnmsg.user = pos->public_key;
1155 entry = client_list_head;
1156 while (NULL != entry)
1158 if (0 == strcmp (pos->room, entry->room) && (NULL != entry->client))
1160 GNUNET_SERVER_notification_context_unicast (nc, entry->client,
1161 &lnmsg.header, GNUNET_NO);
1163 entry = entry->next;
1165 #if DEBUG_CHAT_SERVICE
1166 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1167 "Broadcasting leave notification to neighbour peers\n");
1169 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
1170 &send_leave_noficiation, pos);
1171 GNUNET_free (pos->room);
1172 GNUNET_free_non_null (pos->member_info);
1179 * Handle P2P message notification.
1181 * @param cls closure, always NULL
1182 * @param other the other peer involved
1183 * @param message the actual message
1184 * @param atsi performance information
1185 * @param atsi_count number of entries in atsi
1186 * @return GNUNET_OK to keep the connection open,
1187 * GNUNET_SYSERR to close it (signal serious error)
1190 handle_p2p_message_notification (void *cls,
1191 const struct GNUNET_PeerIdentity *other,
1192 const struct GNUNET_MessageHeader *message,
1193 const struct GNUNET_ATS_Information
1195 unsigned int atsi_count)
1197 const struct P2PReceiveNotificationMessage *p2p_rnmsg;
1198 struct P2PReceiveNotificationMessage *my_p2p_rnmsg;
1199 struct ReceiveNotificationMessage *rnmsg;
1200 struct ChatClient *sender;
1201 struct ChatClient *pos;
1202 static GNUNET_HashCode all_zeros;
1206 uint16_t room_name_len;
1207 char *room_name = NULL;
1210 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P message notification\n");
1211 if (ntohs (message->size) <= sizeof (struct P2PReceiveNotificationMessage))
1213 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n");
1214 GNUNET_break_op (0);
1215 return GNUNET_SYSERR;
1217 p2p_rnmsg = (const struct P2PReceiveNotificationMessage *) message;
1219 ntohs (p2p_rnmsg->header.size) -
1220 sizeof (struct P2PReceiveNotificationMessage);
1222 is_anon = (0 != (ntohl (p2p_rnmsg->msg_options) & GNUNET_CHAT_MSG_ANONYMOUS));
1225 room_name_len = ntohs (p2p_rnmsg->room_name_len);
1226 if (msg_len <= room_name_len)
1228 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1229 "Malformed message: wrong length of the room name\n");
1230 GNUNET_break_op (0);
1231 return GNUNET_SYSERR;
1233 msg_len -= room_name_len;
1234 if (lookup_anonymous_message (p2p_rnmsg))
1236 #if DEBUG_CHAT_SERVICE
1237 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1238 "This anonymous message has already been handled.");
1242 remember_anonymous_message (p2p_rnmsg);
1243 room_name = GNUNET_malloc (room_name_len + 1);
1244 memcpy (room_name, (char *) &p2p_rnmsg[1], room_name_len);
1245 room_name[room_name_len] = '\0';
1246 text = (char *) &p2p_rnmsg[1] + room_name_len;
1250 sender = client_list_head;
1251 while ((NULL != sender) &&
1253 memcmp (&sender->id, &p2p_rnmsg->sender, sizeof (GNUNET_HashCode))))
1254 sender = sender->next;
1257 /* not an error since the sender may have left before we got the
1259 #if DEBUG_CHAT_SERVICE
1260 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1261 "Unknown source. Rejecting the message\n");
1265 if (sender->msg_sequence_number >= ntohl (p2p_rnmsg->sequence_number))
1267 #if DEBUG_CHAT_SERVICE
1268 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1269 "This message has already been handled."
1270 " Sequence numbers (msg/sender): %u/%u\n",
1271 ntohl (p2p_rnmsg->sequence_number),
1272 sender->msg_sequence_number);
1276 sender->msg_sequence_number = ntohl (p2p_rnmsg->sequence_number);
1277 room_name = sender->room;
1278 text = (char *) &p2p_rnmsg[1];
1281 #if DEBUG_CHAT_SERVICE
1282 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1283 "Sending message to local room members\n");
1285 rnmsg = GNUNET_malloc (sizeof (struct ReceiveNotificationMessage) + msg_len);
1286 rnmsg->header.size =
1287 htons (sizeof (struct ReceiveNotificationMessage) + msg_len);
1288 rnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION);
1289 rnmsg->msg_options = p2p_rnmsg->msg_options;
1290 rnmsg->sequence_number = p2p_rnmsg->sequence_number;
1291 rnmsg->reserved = htonl (0);
1292 rnmsg->timestamp = p2p_rnmsg->timestamp;
1294 (0 != memcmp (&all_zeros, &p2p_rnmsg->target, sizeof (GNUNET_HashCode)));
1296 memcpy (&rnmsg->encrypted_key, &p2p_rnmsg->encrypted_key,
1297 sizeof (struct GNUNET_CRYPTO_RsaEncryptedData));
1298 rnmsg->sender = p2p_rnmsg->sender;
1299 memcpy (&rnmsg[1], text, msg_len);
1300 pos = client_list_head;
1303 if ((0 == strcmp (room_name, pos->room)) && (NULL != pos->client))
1307 memcmp (&p2p_rnmsg->target, &pos->id, sizeof (GNUNET_HashCode)))) &&
1308 (0 == (ntohl (p2p_rnmsg->msg_options) & (~pos->msg_options))))
1310 GNUNET_SERVER_notification_context_unicast (nc, pos->client,
1311 &rnmsg->header, GNUNET_NO);
1317 GNUNET_free (room_name);
1318 #if DEBUG_CHAT_SERVICE
1319 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1320 "Broadcasting message notification to neighbour peers\n");
1322 my_p2p_rnmsg = GNUNET_memdup (p2p_rnmsg, ntohs (p2p_rnmsg->header.size));
1323 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
1324 &send_message_noficiation,
1326 GNUNET_free (rnmsg);
1332 * Handle P2P sync request.
1334 * @param cls closure, always NULL
1335 * @param other the other peer involved
1336 * @param message the actual message
1337 * @param atsi performance information
1338 * @param atsi_count number of entries in atsi
1339 * @return GNUNET_OK to keep the connection open,
1340 * GNUNET_SYSERR to close it (signal serious error)
1343 handle_p2p_sync_request (void *cls, const struct GNUNET_PeerIdentity *other,
1344 const struct GNUNET_MessageHeader *message,
1345 const struct GNUNET_ATS_Information *atsi,
1346 unsigned int atsi_count)
1348 struct ChatClient *entry;
1349 struct GNUNET_CORE_TransmitHandle *th;
1352 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P sync request\n");
1353 #if DEBUG_CHAT_SERVICE
1354 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1355 "Notifying the requester of all known clients\n");
1357 entry = client_list_head;
1358 while (NULL != entry)
1361 sizeof (struct P2PJoinNotificationMessage) + strlen (entry->room) +
1363 th = GNUNET_CORE_notify_transmit_ready (core, GNUNET_NO, 1,
1364 MAX_TRANSMIT_DELAY, other, msg_size,
1365 &transmit_join_notification_to_peer,
1367 GNUNET_assert (NULL != th);
1368 entry = entry->next;
1375 * Handle P2P confirmation receipt.
1377 * @param cls closure, always NULL
1378 * @param other the other peer involved
1379 * @param message the actual message
1380 * @param atsi performance information
1381 * @param atsi_count number of entries in atsi
1382 * @return GNUNET_OK to keep the connection open,
1383 * GNUNET_SYSERR to close it (signal serious error)
1386 handle_p2p_confirmation_receipt (void *cls,
1387 const struct GNUNET_PeerIdentity *other,
1388 const struct GNUNET_MessageHeader *message,
1389 const struct GNUNET_ATS_Information
1391 unsigned int atsi_count)
1393 const struct P2PConfirmationReceiptMessage *p2p_crmsg;
1394 struct P2PConfirmationReceiptMessage *my_p2p_crmsg;
1395 struct ConfirmationReceiptMessage *crmsg;
1396 struct ChatClient *target;
1397 struct ChatClient *author;
1399 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P confirmation receipt\n");
1400 p2p_crmsg = (const struct P2PConfirmationReceiptMessage *) message;
1401 target = client_list_head;
1402 while ((NULL != target) &&
1404 memcmp (&target->id, &p2p_crmsg->target, sizeof (GNUNET_HashCode))))
1405 target = target->next;
1408 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1409 "Unknown source of the receipt. Rejecting the message\n");
1410 GNUNET_break_op (0);
1411 return GNUNET_SYSERR;
1413 if (target->rcpt_sequence_number >= ntohl (p2p_crmsg->sequence_number))
1415 #if DEBUG_CHAT_SERVICE
1416 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1417 "This receipt has already been handled."
1418 " Sequence numbers (msg/sender): %u/%u\n",
1419 ntohl (p2p_crmsg->sequence_number),
1420 target->rcpt_sequence_number);
1424 target->rcpt_sequence_number = ntohl (p2p_crmsg->sequence_number);
1425 author = client_list_head;
1426 while ((NULL != author) &&
1428 memcmp (&author->id, &p2p_crmsg->author, sizeof (GNUNET_HashCode))))
1429 author = author->next;
1432 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1433 "Unknown addressee. Rejecting the receipt\n");
1434 GNUNET_break_op (0);
1435 return GNUNET_SYSERR;
1438 if (NULL == author->client)
1440 #if DEBUG_CHAT_SERVICE
1441 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1442 "The author of the original message is not a local client."
1443 " Broadcasting receipt to neighbour peers\n");
1446 GNUNET_memdup (p2p_crmsg,
1447 sizeof (struct P2PConfirmationReceiptMessage));
1448 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
1449 &send_confirmation_receipt,
1451 GNUNET_free (my_p2p_crmsg);
1455 #if DEBUG_CHAT_SERVICE
1456 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1457 "The author of the original message is a local client."
1458 " Verifying signature of the receipt\n");
1460 crmsg = GNUNET_malloc (sizeof (struct ConfirmationReceiptMessage));
1461 crmsg->header.size = htons (sizeof (struct ConfirmationReceiptMessage));
1462 crmsg->header.type =
1463 htons (GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION);
1464 crmsg->signature = p2p_crmsg->signature;
1465 crmsg->purpose = p2p_crmsg->purpose;
1466 crmsg->sequence_number = p2p_crmsg->msg_sequence_number;
1467 crmsg->reserved2 = 0;
1468 crmsg->timestamp = p2p_crmsg->timestamp;
1469 crmsg->target = p2p_crmsg->target;
1470 crmsg->author = p2p_crmsg->author;
1471 crmsg->content = p2p_crmsg->content;
1473 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_CHAT_RECEIPT,
1474 &crmsg->purpose, &crmsg->signature,
1475 &target->public_key))
1477 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1478 "Invalid signature of the receipt\n");
1479 GNUNET_break_op (0);
1480 return GNUNET_SYSERR;
1482 #if DEBUG_CHAT_SERVICE
1483 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1484 "The author of the original message is a local client."
1485 " Sending receipt to the client\n");
1487 GNUNET_SERVER_notification_context_unicast (nc, author->client,
1488 &crmsg->header, GNUNET_NO);
1489 GNUNET_free (crmsg);
1496 * Transmit a sync request to the peer.
1498 * @param cls closure, NULL
1499 * @param size number of bytes available in buf
1500 * @param buf where the callee should write the message
1501 * @return number of bytes written to buf
1504 transmit_sync_request_to_peer (void *cls, size_t size, void *buf)
1506 struct GNUNET_MessageHeader *m = buf;
1509 #if DEBUG_CHAT_SERVICE
1510 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting P2P sync request\n");
1512 msg_size = sizeof (struct GNUNET_MessageHeader);
1513 GNUNET_assert (size >= msg_size);
1514 GNUNET_assert (NULL != buf);
1516 m->type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_SYNC_REQUEST);
1517 m->size = htons (msg_size);
1523 * Method called whenever a peer connects.
1525 * @param cls closure
1526 * @param peer peer identity this notification is about
1527 * @param atsi performance data
1528 * @param atsi_count number of entries in atsi
1531 peer_connect_handler (void *cls, const struct GNUNET_PeerIdentity *peer,
1532 const struct GNUNET_ATS_Information *atsi,
1533 unsigned int atsi_count)
1535 struct ConnectedPeer *cp;
1536 struct GNUNET_CORE_TransmitHandle *th;
1538 if (0 == memcmp (peer, me, sizeof (struct GNUNET_PeerIdentity)))
1540 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Peer connected: %s\n",
1542 th = GNUNET_CORE_notify_transmit_ready (core, GNUNET_YES, 1,
1543 MAX_TRANSMIT_DELAY, peer,
1544 sizeof (struct GNUNET_MessageHeader),
1545 &transmit_sync_request_to_peer, NULL);
1546 GNUNET_assert (NULL != th);
1547 cp = GNUNET_CONTAINER_multihashmap_get (connected_peers, &peer->hashPubKey);
1553 cp = GNUNET_malloc (sizeof (struct ConnectedPeer));
1554 cp->pid = GNUNET_PEER_intern (peer);
1555 GNUNET_break (GNUNET_OK ==
1556 GNUNET_CONTAINER_multihashmap_put (connected_peers,
1557 &peer->hashPubKey, cp,
1558 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1563 * Iterator to free peer entries.
1565 * @param cls closure, unused
1566 * @param key current key code
1567 * @param value value in the hash map (peer entry)
1568 * @return GNUNET_YES (we should continue to iterate)
1571 clean_peer (void *cls, const GNUNET_HashCode * key, void *value)
1573 struct ConnectedPeer *cp;
1574 const struct GNUNET_PeerIdentity *peer =
1575 (const struct GNUNET_PeerIdentity *) key;
1577 cp = GNUNET_CONTAINER_multihashmap_get (connected_peers, &peer->hashPubKey);
1580 GNUNET_break (GNUNET_YES ==
1581 GNUNET_CONTAINER_multihashmap_remove (connected_peers,
1582 &peer->hashPubKey, cp));
1583 GNUNET_PEER_change_rc (cp->pid, -1);
1590 * Method called whenever a peer disconnects.
1592 * @param cls closure, not used
1593 * @param peer peer identity this notification is about
1596 peer_disconnect_handler (void *cls, const struct GNUNET_PeerIdentity *peer)
1599 if (0 == memcmp (peer, me, sizeof (struct GNUNET_PeerIdentity)))
1601 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Peer disconnected: %s\n",
1603 clean_peer (NULL, (const GNUNET_HashCode *) peer, NULL);
1608 * Task run during shutdown.
1614 cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1616 struct AnonymousMessage *next_msg;
1617 struct ChatClient *next_client;
1619 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Cleaning up\n");
1622 GNUNET_CORE_disconnect (core);
1627 GNUNET_SERVER_notification_context_destroy (nc);
1630 while (NULL != client_list_head)
1632 next_client = client_list_head->next;
1633 GNUNET_free (client_list_head->room);
1634 GNUNET_free_non_null (client_list_head->member_info);
1635 GNUNET_free (client_list_head);
1636 client_list_head = next_client;
1638 while (NULL != anonymous_list_head)
1640 next_msg = anonymous_list_head->next;
1641 GNUNET_free (anonymous_list_head);
1642 anonymous_list_head = next_msg;
1644 GNUNET_CONTAINER_multihashmap_iterate (connected_peers, &clean_peer, NULL);
1645 GNUNET_CONTAINER_multihashmap_destroy (connected_peers);
1646 connected_peers = NULL;
1651 * To be called on core init/fail.
1653 * @param cls closure, NULL
1654 * @param server handle to the server for this service
1655 * @param my_identity the public identity of this peer
1658 core_init (void *cls, struct GNUNET_CORE_Handle *server,
1659 const struct GNUNET_PeerIdentity *my_identity)
1661 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Core initialized\n");
1667 * Process chat requests.
1669 * @param cls closure, NULL
1670 * @param server the initialized server
1671 * @param c configuration to use
1674 run (void *cls, struct GNUNET_SERVER_Handle *server,
1675 const struct GNUNET_CONFIGURATION_Handle *c)
1677 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1678 {&handle_join_request, NULL,
1679 GNUNET_MESSAGE_TYPE_CHAT_JOIN_REQUEST, 0},
1680 {&handle_transmit_request, NULL,
1681 GNUNET_MESSAGE_TYPE_CHAT_TRANSMIT_REQUEST, 0},
1682 {&handle_acknowledge_request, NULL,
1683 GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_RECEIPT,
1684 sizeof (struct ConfirmationReceiptMessage)},
1687 static const struct GNUNET_CORE_MessageHandler p2p_handlers[] = {
1688 {&handle_p2p_join_notification,
1689 GNUNET_MESSAGE_TYPE_CHAT_P2P_JOIN_NOTIFICATION, 0},
1690 {&handle_p2p_leave_notification,
1691 GNUNET_MESSAGE_TYPE_CHAT_P2P_LEAVE_NOTIFICATION,
1692 sizeof (struct P2PLeaveNotificationMessage)},
1693 {&handle_p2p_message_notification,
1694 GNUNET_MESSAGE_TYPE_CHAT_P2P_MESSAGE_NOTIFICATION, 0},
1695 {&handle_p2p_sync_request,
1696 GNUNET_MESSAGE_TYPE_CHAT_P2P_SYNC_REQUEST,
1697 sizeof (struct GNUNET_MessageHeader)},
1698 {&handle_p2p_confirmation_receipt,
1699 GNUNET_MESSAGE_TYPE_CHAT_P2P_CONFIRMATION_RECEIPT,
1700 sizeof (struct P2PConfirmationReceiptMessage)},
1704 GNUNET_log_setup ("gnunet-service-chat",
1705 #if DEBUG_CHAT_SERVICE
1712 nc = GNUNET_SERVER_notification_context_create (server, 16);
1714 GNUNET_CONTAINER_multihashmap_create (EXPECTED_NEIGHBOUR_COUNT);
1715 GNUNET_SERVER_add_handlers (server, handlers);
1717 GNUNET_CORE_connect (cfg, QUEUE_SIZE, NULL, &core_init,
1718 &peer_connect_handler, &peer_disconnect_handler,
1719 NULL, GNUNET_NO, NULL, GNUNET_NO,
1721 GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
1722 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
1728 * The main function for the chat service.
1730 * @param argc number of arguments from the command line
1731 * @param argv command line arguments
1732 * @return 0 ok, 1 on error
1735 main (int argc, char *const *argv)
1737 return (GNUNET_OK ==
1738 GNUNET_SERVICE_run (argc, argv, "chat", GNUNET_SERVICE_OPTION_NONE,
1739 &run, NULL)) ? 0 : 1;
1742 /* end of gnunet-service-chat.c */