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_NO
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 *p2p_rnmsg)
165 static GNUNET_HashCode hash;
166 struct AnonymousMessage *anon_msg;
167 struct AnonymousMessage *prev;
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;
177 while ((NULL != anon_msg->next))
180 anon_msg = anon_msg->next;
183 if (anon_list_len == MAX_ANONYMOUS_MSG_LIST_LENGTH)
185 GNUNET_free (anon_msg);
193 lookup_anonymous_message (const struct P2PReceiveNotificationMessage *p2p_rnmsg)
195 static GNUNET_HashCode hash;
196 struct AnonymousMessage *anon_msg;
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 (GNUNET_HashCode))))
202 anon_msg = anon_msg->next;
203 return (NULL != anon_msg);
208 * Transmit a message notification to the peer.
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
216 transmit_message_notification_to_peer (void *cls,
220 struct P2PReceiveNotificationMessage *my_msg = cls;
221 struct P2PReceiveNotificationMessage *m = buf;
224 #if DEBUG_CHAT_SERVICE
225 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
226 "Transmitting P2P message notification\n");
230 /* client disconnected */
231 #if DEBUG_CHAT_SERVICE
232 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
233 "Buffer is NULL, dropping the message\n");
237 msg_size = ntohs (my_msg->header.size);
238 GNUNET_assert (size >= msg_size);
239 memcpy (m, my_msg, msg_size);
240 GNUNET_free (my_msg);
246 * Ask to send a message notification to the peer.
249 send_message_noficiation (void *cls,
250 const GNUNET_HashCode *key,
253 struct P2PReceiveNotificationMessage *msg = cls;
254 struct ConnectedPeer *cp = value;
255 struct GNUNET_PeerIdentity pid;
256 struct P2PReceiveNotificationMessage *my_msg;
258 GNUNET_PEER_resolve (cp->pid, &pid);
259 #if DEBUG_CHAT_SERVICE
260 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
261 "Sending message notification to `%s'\n", GNUNET_i2s (&pid));
263 my_msg = GNUNET_memdup (msg, ntohs (msg->header.size));
264 if (NULL == GNUNET_CORE_notify_transmit_ready (core,
268 ntohs (msg->header.size),
269 &transmit_message_notification_to_peer,
271 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
272 _("Failed to queue a message notification\n"));
278 * A client sent a chat message. Encrypt the message text if the message is
279 * private. Send the message to local room members and to all connected peers.
281 * @param cls closure, NULL
282 * @param client identification of the client
283 * @param message the actual message
286 handle_transmit_request (void *cls,
287 struct GNUNET_SERVER_Client *client,
288 const struct GNUNET_MessageHeader *message)
290 static GNUNET_HashCode all_zeros;
291 const struct TransmitRequestMessage *trmsg;
292 struct ReceiveNotificationMessage *rnmsg;
293 struct P2PReceiveNotificationMessage *p2p_rnmsg;
294 struct ChatClient *pos;
295 struct ChatClient *target;
296 struct GNUNET_CRYPTO_AesSessionKey key;
297 char encrypted_msg[MAX_MESSAGE_LENGTH];
304 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client sent a chat message\n");
305 if (ntohs (message->size) <= sizeof (struct TransmitRequestMessage))
307 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n");
309 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
312 trmsg = (const struct TransmitRequestMessage *) message;
313 msg_len = ntohs (trmsg->header.size) - sizeof (struct TransmitRequestMessage);
314 is_priv = (0 != (ntohl (trmsg->msg_options) & GNUNET_CHAT_MSG_PRIVATE));
317 #if DEBUG_CHAT_SERVICE
318 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypting the message text\n");
320 GNUNET_CRYPTO_aes_create_session_key (&key);
321 msg_len = GNUNET_CRYPTO_aes_encrypt (&trmsg[1],
324 (const struct GNUNET_CRYPTO_AesInitializationVector *) INITVALUE,
328 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
329 "Could not encrypt the message text\n");
331 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
335 rnmsg = GNUNET_malloc (sizeof (struct ReceiveNotificationMessage) + msg_len);
336 rnmsg->header.size = htons (sizeof (struct ReceiveNotificationMessage) +
338 rnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION);
339 rnmsg->msg_options = trmsg->msg_options;
340 rnmsg->timestamp = trmsg->timestamp;
341 pos = client_list_head;
342 while ((NULL != pos) && (pos->client != client))
346 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
347 "The client is not a member of a chat room. Client has to "
348 "join a chat room first\n");
350 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
355 pos->msg_sequence_number = ntohl (trmsg->sequence_number);
356 is_anon = (0 != (ntohl (trmsg->msg_options) & GNUNET_CHAT_MSG_ANONYMOUS));
359 memset (&rnmsg->sender, 0, sizeof (GNUNET_HashCode));
360 rnmsg->sequence_number = 0;
364 rnmsg->sender = pos->id;
365 rnmsg->sequence_number = trmsg->sequence_number;
369 #if DEBUG_CHAT_SERVICE
370 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
371 "Encrypting the session key using the public key of '%s'\n",
372 GNUNET_h2s (&trmsg->target));
374 if (0 == memcmp (&all_zeros, &trmsg->target, sizeof (GNUNET_HashCode)))
376 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
377 "Malformed message: private, but no target\n");
379 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
383 memcpy (&rnmsg[1], encrypted_msg, msg_len);
384 target = client_list_head;
385 while ((NULL != target) &&
386 (0 != memcmp (&target->id,
388 sizeof (GNUNET_HashCode))))
389 target = target->next;
392 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
393 "Unknown target of the private message\n");
395 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
399 if (GNUNET_SYSERR == GNUNET_CRYPTO_rsa_encrypt (&key,
400 sizeof (struct GNUNET_CRYPTO_AesSessionKey),
402 &rnmsg->encrypted_key))
404 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
405 "Could not encrypt the session key\n");
407 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
414 memcpy (&rnmsg[1], &trmsg[1], msg_len);
416 pos = client_list_head;
417 #if DEBUG_CHAT_SERVICE
418 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message to local room members\n");
422 if ((0 == strcmp (room, pos->room)) &&
423 (NULL != pos->client) &&
424 (pos->client != client))
427 (0 == memcmp (&trmsg->target,
429 sizeof (GNUNET_HashCode)))) &&
430 (0 == (ntohl (trmsg->msg_options) & (~pos->msg_options))))
432 GNUNET_SERVER_notification_context_unicast (nc,
440 #if DEBUG_CHAT_SERVICE
441 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
442 "Broadcasting message to neighbour peers\n");
446 room_len = strlen (room);
447 p2p_rnmsg = GNUNET_malloc (sizeof (struct P2PReceiveNotificationMessage) +
449 p2p_rnmsg->header.size =
450 htons (sizeof (struct P2PReceiveNotificationMessage) + msg_len +
452 p2p_rnmsg->room_name_len = htons (room_len);
453 memcpy ((char *) &p2p_rnmsg[1], room, room_len);
454 memcpy ((char *) &p2p_rnmsg[1] + room_len, &trmsg[1], msg_len);
458 p2p_rnmsg = GNUNET_malloc (sizeof (struct P2PReceiveNotificationMessage) +
460 p2p_rnmsg->header.size =
461 htons (sizeof (struct P2PReceiveNotificationMessage) + msg_len);
464 memcpy (&p2p_rnmsg[1], encrypted_msg, msg_len);
465 memcpy (&p2p_rnmsg->encrypted_key,
466 &rnmsg->encrypted_key,
467 sizeof (struct GNUNET_CRYPTO_RsaEncryptedData));
470 memcpy (&p2p_rnmsg[1], &trmsg[1], msg_len);
472 p2p_rnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_MESSAGE_NOTIFICATION);
473 p2p_rnmsg->msg_options = trmsg->msg_options;
474 p2p_rnmsg->sequence_number = trmsg->sequence_number;
475 p2p_rnmsg->timestamp = trmsg->timestamp;
476 p2p_rnmsg->reserved = 0;
477 p2p_rnmsg->sender = rnmsg->sender;
478 p2p_rnmsg->target = trmsg->target;
480 remember_anonymous_message (p2p_rnmsg);
481 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
482 &send_message_noficiation,
484 GNUNET_free (p2p_rnmsg);
485 GNUNET_SERVER_receive_done (client, GNUNET_OK);
491 * Transmit a join notification to the peer.
493 * @param cls closure, pointer to the 'struct ChatClient'
494 * @param size number of bytes available in buf
495 * @param buf where the callee should write the message
496 * @return number of bytes written to buf
499 transmit_join_notification_to_peer (void *cls,
503 struct ChatClient *entry = cls;
504 struct P2PJoinNotificationMessage *m = buf;
510 #if DEBUG_CHAT_SERVICE
511 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
512 "Transmitting P2P join notification\n");
514 room_len = strlen (entry->room);
515 meta_len = entry->meta_len;
516 msg_size = sizeof (struct P2PJoinNotificationMessage) + meta_len + room_len;
517 GNUNET_assert (size >= msg_size);
518 GNUNET_assert (NULL != buf);
520 m->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_JOIN_NOTIFICATION);
521 m->header.size = htons (msg_size);
522 m->msg_options = htonl (entry->msg_options);
523 m->room_name_len = htons (room_len);
524 m->reserved = htons (0);
525 m->public_key = entry->public_key;
526 roomptr = (char *) &m[1];
527 memcpy (roomptr, entry->room, room_len);
529 memcpy (&roomptr[room_len], entry->member_info, meta_len);
535 * Ask to send a join notification to the peer.
538 send_join_noficiation (void *cls,
539 const GNUNET_HashCode *key,
542 struct ChatClient *entry = cls;
543 struct ConnectedPeer *cp = value;
544 struct GNUNET_PeerIdentity pid;
547 GNUNET_PEER_resolve (cp->pid, &pid);
548 #if DEBUG_CHAT_SERVICE
549 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
550 "Sending join notification to `%s'\n", GNUNET_i2s (&pid));
552 msg_size = sizeof (struct P2PJoinNotificationMessage) +
553 strlen (entry->room) +
555 if (NULL == GNUNET_CORE_notify_transmit_ready (core,
560 &transmit_join_notification_to_peer,
562 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
563 _("Failed to queue a join notification\n"));
569 * A client asked for entering a chat room. Add the new member to the list of
570 * clients and notify remaining room members.
572 * @param cls closure, NULL
573 * @param client identification of the client
574 * @param message the actual message
577 handle_join_request (void *cls,
578 struct GNUNET_SERVER_Client *client,
579 const struct GNUNET_MessageHeader *message)
581 const struct JoinRequestMessage *jrmsg;
584 uint16_t header_size;
586 uint16_t room_name_len;
587 struct ChatClient *new_entry;
588 struct ChatClient *entry;
589 struct JoinNotificationMessage *jnmsg;
590 struct JoinNotificationMessage *entry_jnmsg;
592 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client sent a join request\n");
593 if (ntohs (message->size) <= sizeof (struct JoinRequestMessage))
595 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n");
597 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
600 jrmsg = (const struct JoinRequestMessage *) message;
601 header_size = ntohs (jrmsg->header.size);
602 room_name_len = ntohs (jrmsg->room_name_len);
603 if (header_size - sizeof (struct JoinRequestMessage) <=
606 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
607 "Malformed message: wrong length of the room name\n");
609 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
613 header_size - sizeof (struct JoinRequestMessage) - room_name_len;
614 roomptr = (const char *) &jrmsg[1];
615 room_name = GNUNET_malloc (room_name_len + 1);
616 memcpy (room_name, roomptr, room_name_len);
617 room_name[room_name_len] = '\0';
618 new_entry = GNUNET_malloc (sizeof (struct ChatClient));
619 memset (new_entry, 0, sizeof (struct ChatClient));
620 new_entry->client = client;
621 new_entry->room = room_name;
622 new_entry->public_key = jrmsg->public_key;
623 new_entry->meta_len = meta_len;
626 new_entry->member_info = GNUNET_malloc (meta_len);
627 memcpy (new_entry->member_info, &roomptr[room_name_len], meta_len);
630 new_entry->member_info = NULL;
631 GNUNET_CRYPTO_hash (&new_entry->public_key,
632 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
634 new_entry->msg_options = ntohl (jrmsg->msg_options);
635 new_entry->next = client_list_head;
636 client_list_head = new_entry;
637 #if DEBUG_CHAT_SERVICE
638 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
639 "Synchronizing room members between local clients\n");
641 jnmsg = GNUNET_malloc (sizeof (struct JoinNotificationMessage) + meta_len);
642 jnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION);
644 htons (sizeof (struct JoinNotificationMessage) + meta_len);
645 jnmsg->msg_options = jrmsg->msg_options;
646 jnmsg->public_key = new_entry->public_key;
647 memcpy (&jnmsg[1], &roomptr[room_name_len], meta_len);
648 GNUNET_SERVER_notification_context_add (nc, client);
649 entry = client_list_head;
650 while (NULL != entry)
652 if (0 == strcmp (room_name, entry->room))
654 if (NULL != entry->client)
655 GNUNET_SERVER_notification_context_unicast (nc,
659 if (entry->client != client)
662 GNUNET_malloc (sizeof (struct JoinNotificationMessage) +
664 entry_jnmsg->header.type =
665 htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION);
666 entry_jnmsg->header.size =
667 htons (sizeof (struct JoinNotificationMessage) +
669 entry_jnmsg->msg_options = entry->msg_options;
670 entry_jnmsg->public_key = entry->public_key;
671 memcpy (&entry_jnmsg[1], entry->member_info, entry->meta_len);
672 GNUNET_SERVER_notification_context_unicast (nc,
674 &entry_jnmsg->header,
676 GNUNET_free (entry_jnmsg);
681 #if DEBUG_CHAT_SERVICE
682 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
683 "Broadcasting join notification to neighbour peers\n");
685 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
686 &send_join_noficiation,
688 GNUNET_SERVER_receive_done (client, GNUNET_OK);
693 * Transmit a confirmation receipt to the peer.
695 * @param cls closure, pointer to the 'struct P2PConfirmationReceiptMessage'
696 * @param size number of bytes available in buf
697 * @param buf where the callee should write the message
698 * @return number of bytes written to buf
701 transmit_confirmation_receipt_to_peer (void *cls,
705 struct P2PConfirmationReceiptMessage *receipt = cls;
708 #if DEBUG_CHAT_SERVICE
709 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
710 "Transmitting P2P confirmation receipt to '%s'\n",
711 GNUNET_h2s (&receipt->target));
715 /* client disconnected */
716 #if DEBUG_CHAT_SERVICE
717 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
718 "Buffer is NULL, dropping the message\n");
722 msg_size = sizeof (struct P2PConfirmationReceiptMessage);
723 GNUNET_assert (size >= msg_size);
724 memcpy (buf, receipt, msg_size);
725 GNUNET_free (receipt);
731 * Ask to send a confirmation receipt to the peer.
734 send_confirmation_receipt (void *cls,
735 const GNUNET_HashCode *key,
738 struct P2PConfirmationReceiptMessage *receipt = cls;
739 struct ConnectedPeer *cp = value;
740 struct GNUNET_PeerIdentity pid;
741 struct P2PConfirmationReceiptMessage *my_receipt;
744 GNUNET_PEER_resolve (cp->pid, &pid);
745 #if DEBUG_CHAT_SERVICE
746 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
747 "Sending confirmation receipt to `%s'\n", GNUNET_i2s (&pid));
749 msg_size = sizeof (struct P2PConfirmationReceiptMessage);
750 my_receipt = GNUNET_memdup (receipt,
751 sizeof (struct P2PConfirmationReceiptMessage));
752 if (NULL == GNUNET_CORE_notify_transmit_ready (core,
757 &transmit_confirmation_receipt_to_peer,
759 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
760 _("Failed to queue a confirmation receipt\n"));
766 * A client sent a confirmation receipt. Broadcast the receipt to all connected
767 * peers if the author of the original message is a local client. Otherwise
768 * check the signature and notify the user if the signature is valid.
770 * @param cls closure, NULL
771 * @param client identification of the client
772 * @param message the actual message
775 handle_acknowledge_request (void *cls,
776 struct GNUNET_SERVER_Client *client,
777 const struct GNUNET_MessageHeader *message)
779 const struct ConfirmationReceiptMessage *receipt;
780 struct ConfirmationReceiptMessage *crmsg;
781 struct P2PConfirmationReceiptMessage *p2p_crmsg;
782 struct ChatClient *target;
783 struct ChatClient *author;
785 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client sent a confirmation receipt\n");
786 receipt = (const struct ConfirmationReceiptMessage *) message;
787 author = client_list_head;
788 while ((NULL != author) &&
789 (0 != memcmp (&receipt->author,
791 sizeof (GNUNET_HashCode))))
792 author = author->next;
795 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
796 "Unknown author of the original message\n");
798 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
801 target = client_list_head;
802 while ((NULL != target) &&
803 (0 != memcmp (&receipt->target,
805 sizeof (GNUNET_HashCode))))
806 target = target->next;
809 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
810 "Unknown target of the confirmation receipt\n");
812 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
815 if (NULL == author->client)
817 target->rcpt_sequence_number++;
818 #if DEBUG_CHAT_SERVICE
819 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
820 "Broadcasting %s's receipt #%u to neighbour peers\n",
821 GNUNET_h2s (&target->id), target->rcpt_sequence_number);
823 p2p_crmsg = GNUNET_malloc (sizeof (struct P2PConfirmationReceiptMessage));
824 p2p_crmsg->header.size = htons (sizeof (struct P2PConfirmationReceiptMessage));
825 p2p_crmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_CONFIRMATION_RECEIPT);
826 p2p_crmsg->signature = receipt->signature;
827 p2p_crmsg->purpose = receipt->purpose;
828 p2p_crmsg->msg_sequence_number = receipt->sequence_number;
829 p2p_crmsg->timestamp = receipt->timestamp;
830 p2p_crmsg->target = receipt->target;
831 p2p_crmsg->author = receipt->author;
832 p2p_crmsg->content = receipt->content;
833 p2p_crmsg->sequence_number = htonl (target->rcpt_sequence_number);
834 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
835 &send_confirmation_receipt,
837 GNUNET_free (p2p_crmsg);
841 #if DEBUG_CHAT_SERVICE
842 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
843 "Verifying signature of the receipt\n");
846 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_CHAT_RECEIPT,
849 &target->public_key))
851 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
852 "Invalid signature of the receipt\n");
854 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
857 #if DEBUG_CHAT_SERVICE
858 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
859 "Sending receipt to the client which sent the original message\n");
861 crmsg = GNUNET_memdup (receipt, sizeof (struct ConfirmationReceiptMessage));
862 crmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION);
863 GNUNET_SERVER_notification_context_unicast (nc,
869 GNUNET_SERVER_receive_done (client, GNUNET_OK);
874 * Transmit a leave notification to the peer.
876 * @param cls closure, pointer to the
877 * 'struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded'
878 * @param size number of bytes available in buf
879 * @param buf where the callee should write the message
880 * @return number of bytes written to buf
883 transmit_leave_notification_to_peer (void *cls,
887 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key = cls;
888 struct P2PLeaveNotificationMessage *m = buf;
891 #if DEBUG_CHAT_SERVICE
892 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
893 "Transmitting P2P leave notification\n");
897 /* client disconnected */
898 #if DEBUG_CHAT_SERVICE
899 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
900 "Buffer is NULL, dropping the message\n");
904 msg_size = sizeof (struct P2PLeaveNotificationMessage);
905 GNUNET_assert (size >= msg_size);
907 m->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_LEAVE_NOTIFICATION);
908 m->header.size = htons (msg_size);
909 m->reserved = htons (0);
910 m->user = *public_key;
911 GNUNET_free (public_key);
917 * Ask to send a leave notification to the peer.
920 send_leave_noficiation (void *cls,
921 const GNUNET_HashCode *key,
924 struct ChatClient *entry = cls;
925 struct ConnectedPeer *cp = value;
926 struct GNUNET_PeerIdentity pid;
927 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key;
930 GNUNET_PEER_resolve (cp->pid, &pid);
931 #if DEBUG_CHAT_SERVICE
932 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
933 "Sending leave notification to `%s'\n", GNUNET_i2s (&pid));
935 msg_size = sizeof (struct P2PLeaveNotificationMessage);
936 public_key = GNUNET_memdup (&entry->public_key,
937 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
938 if (NULL == GNUNET_CORE_notify_transmit_ready (core,
943 &transmit_leave_notification_to_peer,
945 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
946 _("Failed to queue a leave notification\n"));
952 * A client disconnected. Remove all of its data structure entries and notify
953 * remaining room members.
955 * @param cls closure, NULL
956 * @param client identification of the client
959 handle_client_disconnect (void *cls,
960 struct GNUNET_SERVER_Client *client)
962 struct ChatClient *entry;
963 struct ChatClient *pos;
964 struct ChatClient *prev;
965 struct LeaveNotificationMessage lnmsg;
967 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client disconnected\n");
968 pos = client_list_head;
970 while ((NULL != pos) && (pos->client != client))
977 #if DEBUG_CHAT_SERVICE
978 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
979 "No such client. There is nothing to do\n");
984 client_list_head = pos->next;
986 prev->next = pos->next;
987 entry = client_list_head;
988 #if DEBUG_CHAT_SERVICE
989 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
990 "Notifying local room members that the client has disconnected\n");
992 lnmsg.header.size = htons (sizeof (struct LeaveNotificationMessage));
993 lnmsg.header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION);
994 lnmsg.reserved = htonl (0);
995 lnmsg.user = pos->public_key;
996 while (NULL != entry)
998 if ((0 == strcmp (pos->room, entry->room)) &&
999 (NULL != entry->client))
1001 GNUNET_SERVER_notification_context_unicast (nc,
1006 entry = entry->next;
1008 #if DEBUG_CHAT_SERVICE
1009 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1010 "Broadcasting leave notification to neighbour peers\n");
1012 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
1013 &send_leave_noficiation,
1015 GNUNET_free (pos->room);
1016 GNUNET_free_non_null (pos->member_info);
1022 * Handle P2P join notification.
1024 * @param cls closure, always NULL
1025 * @param other the other peer involved
1026 * @param message the actual message
1027 * @param atsi performance information
1028 * @return GNUNET_OK to keep the connection open,
1029 * GNUNET_SYSERR to close it (signal serious error)
1032 handle_p2p_join_notification (void *cls,
1033 const struct GNUNET_PeerIdentity *other,
1034 const struct GNUNET_MessageHeader *message,
1035 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1037 const struct P2PJoinNotificationMessage *p2p_jnmsg;
1039 const char *roomptr;
1040 uint16_t header_size;
1042 uint16_t room_name_len;
1043 struct ChatClient *new_entry;
1044 struct ChatClient *entry;
1045 struct JoinNotificationMessage *jnmsg;
1048 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P join notification\n");
1049 if (ntohs (message->size) <= sizeof (struct P2PJoinNotificationMessage))
1051 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n");
1052 GNUNET_break_op (0);
1053 return GNUNET_SYSERR;
1055 p2p_jnmsg = (const struct P2PJoinNotificationMessage *) message;
1056 header_size = ntohs (p2p_jnmsg->header.size);
1057 room_name_len = ntohs (p2p_jnmsg->room_name_len);
1058 if (header_size - sizeof (struct P2PJoinNotificationMessage) <=
1061 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1062 "Malformed message: wrong length of the room name\n");
1063 GNUNET_break_op (0);
1064 return GNUNET_SYSERR;
1066 GNUNET_CRYPTO_hash (&p2p_jnmsg->public_key,
1067 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1069 entry = client_list_head;
1070 while (NULL != entry)
1072 if (0 == memcmp (&entry->id, &id, sizeof (GNUNET_HashCode)))
1074 #if DEBUG_CHAT_SERVICE
1075 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1076 "The client has already joined. There is nothing to do\n");
1080 entry = entry->next;
1083 header_size - sizeof (struct P2PJoinNotificationMessage) - room_name_len;
1084 roomptr = (const char *) &p2p_jnmsg[1];
1085 room_name = GNUNET_malloc (room_name_len + 1);
1086 memcpy (room_name, roomptr, room_name_len);
1087 room_name[room_name_len] = '\0';
1088 new_entry = GNUNET_malloc (sizeof (struct ChatClient));
1089 memset (new_entry, 0, sizeof (struct ChatClient));
1091 new_entry->client = NULL;
1092 new_entry->room = room_name;
1093 new_entry->public_key = p2p_jnmsg->public_key;
1094 new_entry->meta_len = meta_len;
1097 new_entry->member_info = GNUNET_malloc (meta_len);
1098 memcpy (new_entry->member_info, &roomptr[room_name_len], meta_len);
1101 new_entry->member_info = NULL;
1102 new_entry->msg_options = ntohl (p2p_jnmsg->msg_options);
1103 new_entry->next = client_list_head;
1104 client_list_head = new_entry;
1105 #if DEBUG_CHAT_SERVICE
1106 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1107 "Notifying local room members that we have a new client\n");
1109 jnmsg = GNUNET_malloc (sizeof (struct JoinNotificationMessage) + meta_len);
1110 jnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION);
1111 jnmsg->header.size =
1112 htons (sizeof (struct JoinNotificationMessage) + meta_len);
1113 jnmsg->msg_options = p2p_jnmsg->msg_options;
1114 jnmsg->public_key = new_entry->public_key;
1115 memcpy (&jnmsg[1], &roomptr[room_name_len], meta_len);
1116 entry = client_list_head;
1117 while (NULL != entry)
1119 if ((0 == strcmp (room_name, entry->room)) &&
1120 (NULL != entry->client))
1122 GNUNET_SERVER_notification_context_unicast (nc,
1127 entry = entry->next;
1129 #if DEBUG_CHAT_SERVICE
1130 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1131 "Broadcasting join notification to neighbour peers\n");
1133 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
1134 &send_join_noficiation,
1136 GNUNET_free (jnmsg);
1142 * Handle P2P leave notification.
1144 * @param cls closure, always NULL
1145 * @param other the other peer involved
1146 * @param message the actual message
1147 * @param atsi performance information
1148 * @return GNUNET_OK to keep the connection open,
1149 * GNUNET_SYSERR to close it (signal serious error)
1152 handle_p2p_leave_notification (void *cls,
1153 const struct GNUNET_PeerIdentity *other,
1154 const struct GNUNET_MessageHeader *message,
1155 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1157 const struct P2PLeaveNotificationMessage *p2p_lnmsg;
1159 struct ChatClient *pos;
1160 struct ChatClient *prev;
1161 struct ChatClient *entry;
1162 struct LeaveNotificationMessage lnmsg;
1164 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P leave notification\n");
1165 p2p_lnmsg = (const struct P2PLeaveNotificationMessage *) message;
1166 GNUNET_CRYPTO_hash (&p2p_lnmsg->user,
1167 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1169 pos = client_list_head;
1173 if (0 == memcmp (&pos->id, &id, sizeof (GNUNET_HashCode)))
1180 #if DEBUG_CHAT_SERVICE
1181 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1182 "No such client. There is nothing to do\n");
1187 client_list_head = pos->next;
1189 prev->next = pos->next;
1190 #if DEBUG_CHAT_SERVICE
1191 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1192 "Notifying local room members that the client has gone away\n");
1194 lnmsg.header.size = htons (sizeof (struct LeaveNotificationMessage));
1195 lnmsg.header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION);
1196 lnmsg.reserved = htonl (0);
1197 lnmsg.user = pos->public_key;
1198 entry = client_list_head;
1199 while (NULL != entry)
1201 if (0 == strcmp (pos->room, entry->room) &&
1202 (NULL != entry->client))
1204 GNUNET_SERVER_notification_context_unicast (nc,
1209 entry = entry->next;
1211 #if DEBUG_CHAT_SERVICE
1212 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1213 "Broadcasting leave notification to neighbour peers\n");
1215 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
1216 &send_leave_noficiation,
1218 GNUNET_free (pos->room);
1219 GNUNET_free_non_null (pos->member_info);
1226 * Handle P2P message notification.
1228 * @param cls closure, always NULL
1229 * @param other the other peer involved
1230 * @param message the actual message
1231 * @param atsi performance information
1232 * @return GNUNET_OK to keep the connection open,
1233 * GNUNET_SYSERR to close it (signal serious error)
1236 handle_p2p_message_notification (void *cls,
1237 const struct GNUNET_PeerIdentity *other,
1238 const struct GNUNET_MessageHeader *message,
1239 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1241 const struct P2PReceiveNotificationMessage *p2p_rnmsg;
1242 struct P2PReceiveNotificationMessage *my_p2p_rnmsg;
1243 struct ReceiveNotificationMessage *rnmsg;
1244 struct ChatClient *sender;
1245 struct ChatClient *pos;
1246 static GNUNET_HashCode all_zeros;
1250 uint16_t room_name_len;
1251 char *room_name = NULL;
1254 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P message notification\n");
1255 if (ntohs (message->size) <= sizeof (struct P2PReceiveNotificationMessage))
1257 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n");
1258 GNUNET_break_op (0);
1259 return GNUNET_SYSERR;
1261 p2p_rnmsg = (const struct P2PReceiveNotificationMessage *) message;
1262 msg_len = ntohs (p2p_rnmsg->header.size) -
1263 sizeof (struct P2PReceiveNotificationMessage);
1265 is_anon = (0 != (ntohl (p2p_rnmsg->msg_options) & GNUNET_CHAT_MSG_ANONYMOUS));
1268 room_name_len = ntohs (p2p_rnmsg->room_name_len);
1269 if (msg_len <= room_name_len)
1271 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1272 "Malformed message: wrong length of the room name\n");
1273 GNUNET_break_op (0);
1274 return GNUNET_SYSERR;
1276 msg_len -= room_name_len;
1277 if (lookup_anonymous_message (p2p_rnmsg))
1279 #if DEBUG_CHAT_SERVICE
1280 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1281 "This anonymous message has already been handled.");
1285 remember_anonymous_message (p2p_rnmsg);
1286 room_name = GNUNET_malloc (room_name_len + 1);
1287 memcpy (room_name, (char *) &p2p_rnmsg[1], room_name_len);
1288 room_name[room_name_len] = '\0';
1289 text = (char *) &p2p_rnmsg[1] + room_name_len;
1293 sender = client_list_head;
1294 while ((NULL != sender) &&
1295 (0 != memcmp (&sender->id,
1297 sizeof (GNUNET_HashCode))))
1298 sender = sender->next;
1301 /* not an error since the sender may have left before we got the
1303 #if DEBUG_CHAT_SERVICE
1304 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1305 "Unknown source. Rejecting the message\n");
1309 if (sender->msg_sequence_number >= ntohl (p2p_rnmsg->sequence_number))
1311 #if DEBUG_CHAT_SERVICE
1312 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1313 "This message has already been handled."
1314 " Sequence numbers (msg/sender): %u/%u\n",
1315 ntohl (p2p_rnmsg->sequence_number),
1316 sender->msg_sequence_number);
1320 sender->msg_sequence_number = ntohl (p2p_rnmsg->sequence_number);
1321 room_name = sender->room;
1322 text = (char *) &p2p_rnmsg[1];
1325 #if DEBUG_CHAT_SERVICE
1326 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1327 "Sending message to local room members\n");
1329 rnmsg = GNUNET_malloc (sizeof (struct ReceiveNotificationMessage) + msg_len);
1330 rnmsg->header.size = htons (sizeof (struct ReceiveNotificationMessage) +
1332 rnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION);
1333 rnmsg->msg_options = p2p_rnmsg->msg_options;
1334 rnmsg->sequence_number = p2p_rnmsg->sequence_number;
1335 rnmsg->timestamp = p2p_rnmsg->timestamp;
1336 is_priv = (0 != memcmp (&all_zeros,
1337 &p2p_rnmsg->target, sizeof (GNUNET_HashCode)));
1339 memcpy (&rnmsg->encrypted_key,
1340 &p2p_rnmsg->encrypted_key,
1341 sizeof (struct GNUNET_CRYPTO_RsaEncryptedData));
1342 rnmsg->sender = p2p_rnmsg->sender;
1343 memcpy (&rnmsg[1], text, msg_len);
1344 pos = client_list_head;
1347 if ((0 == strcmp (room_name, pos->room)) &&
1348 (NULL != pos->client))
1351 (0 == memcmp (&p2p_rnmsg->target,
1353 sizeof (GNUNET_HashCode)))) &&
1354 (0 == (ntohl (p2p_rnmsg->msg_options) & (~pos->msg_options))))
1356 GNUNET_SERVER_notification_context_unicast (nc,
1365 GNUNET_free (room_name);
1366 #if DEBUG_CHAT_SERVICE
1367 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1368 "Broadcasting message notification to neighbour peers\n");
1370 my_p2p_rnmsg = GNUNET_memdup (p2p_rnmsg, ntohs (p2p_rnmsg->header.size));
1371 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
1372 &send_message_noficiation,
1374 GNUNET_free (rnmsg);
1380 * Handle P2P sync request.
1382 * @param cls closure, always NULL
1383 * @param other the other peer involved
1384 * @param message the actual message
1385 * @param atsi performance information
1386 * @return GNUNET_OK to keep the connection open,
1387 * GNUNET_SYSERR to close it (signal serious error)
1390 handle_p2p_sync_request (void *cls,
1391 const struct GNUNET_PeerIdentity *other,
1392 const struct GNUNET_MessageHeader *message,
1393 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1395 struct ChatClient *entry;
1396 struct GNUNET_CORE_TransmitHandle *th;
1399 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P sync request\n");
1400 #if DEBUG_CHAT_SERVICE
1401 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1402 "Notifying the requester of all known clients\n");
1404 entry = client_list_head;
1405 while (NULL != entry)
1407 msg_size = sizeof (struct P2PJoinNotificationMessage) +
1408 strlen (entry->room) +
1410 th = GNUNET_CORE_notify_transmit_ready (core,
1415 &transmit_join_notification_to_peer,
1417 GNUNET_assert (NULL != th);
1418 entry = entry->next;
1425 * Handle P2P confirmation receipt.
1427 * @param cls closure, always NULL
1428 * @param other the other peer involved
1429 * @param message the actual message
1430 * @param atsi performance information
1431 * @return GNUNET_OK to keep the connection open,
1432 * GNUNET_SYSERR to close it (signal serious error)
1435 handle_p2p_confirmation_receipt (void *cls,
1436 const struct GNUNET_PeerIdentity *other,
1437 const struct GNUNET_MessageHeader *message,
1438 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1440 const struct P2PConfirmationReceiptMessage *p2p_crmsg;
1441 struct P2PConfirmationReceiptMessage *my_p2p_crmsg;
1442 struct ConfirmationReceiptMessage *crmsg;
1443 struct ChatClient *target;
1444 struct ChatClient *author;
1446 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P confirmation receipt\n");
1447 p2p_crmsg = (const struct P2PConfirmationReceiptMessage *) message;
1448 target = client_list_head;
1449 while ((NULL != target) &&
1450 (0 != memcmp (&target->id,
1452 sizeof (GNUNET_HashCode))))
1453 target = target->next;
1456 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1457 "Unknown source of the receipt. Rejecting the message\n");
1458 GNUNET_break_op (0);
1459 return GNUNET_SYSERR;
1461 if (target->rcpt_sequence_number >= ntohl (p2p_crmsg->sequence_number))
1463 #if DEBUG_CHAT_SERVICE
1464 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1465 "This receipt has already been handled."
1466 " Sequence numbers (msg/sender): %u/%u\n",
1467 ntohl (p2p_crmsg->sequence_number), target->rcpt_sequence_number);
1471 target->rcpt_sequence_number = ntohl (p2p_crmsg->sequence_number);
1472 author = client_list_head;
1473 while ((NULL != author) &&
1474 (0 != memcmp (&author->id,
1476 sizeof (GNUNET_HashCode))))
1477 author = author->next;
1480 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1481 "Unknown addressee. Rejecting the receipt\n");
1482 GNUNET_break_op (0);
1483 return GNUNET_SYSERR;
1486 if (NULL == author->client)
1488 #if DEBUG_CHAT_SERVICE
1489 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1490 "The author of the original message is not a local client."
1491 " Broadcasting receipt to neighbour peers\n");
1493 my_p2p_crmsg = GNUNET_memdup (p2p_crmsg, sizeof (struct P2PConfirmationReceiptMessage));
1494 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
1495 &send_confirmation_receipt,
1497 GNUNET_free (my_p2p_crmsg);
1501 #if DEBUG_CHAT_SERVICE
1502 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1503 "The author of the original message is a local client."
1504 " Verifying signature of the receipt\n");
1506 crmsg = GNUNET_malloc (sizeof (struct ConfirmationReceiptMessage));
1507 crmsg->header.size = htons (sizeof (struct ConfirmationReceiptMessage));
1508 crmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION);
1509 crmsg->signature = p2p_crmsg->signature;
1510 crmsg->purpose = p2p_crmsg->purpose;
1511 crmsg->sequence_number = p2p_crmsg->msg_sequence_number;
1512 crmsg->reserved2 = 0;
1513 crmsg->timestamp = p2p_crmsg->timestamp;
1514 crmsg->target = p2p_crmsg->target;
1515 crmsg->author = p2p_crmsg->author;
1516 crmsg->content = p2p_crmsg->content;
1518 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_CHAT_RECEIPT,
1521 &target->public_key))
1523 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1524 "Invalid signature of the receipt\n");
1525 GNUNET_break_op (0);
1526 return GNUNET_SYSERR;
1528 #if DEBUG_CHAT_SERVICE
1529 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1530 "The author of the original message is a local client."
1531 " Sending receipt to the client\n");
1533 GNUNET_SERVER_notification_context_unicast (nc,
1537 GNUNET_free (crmsg);
1544 * Transmit a sync request to the peer.
1546 * @param cls closure, NULL
1547 * @param size number of bytes available in buf
1548 * @param buf where the callee should write the message
1549 * @return number of bytes written to buf
1552 transmit_sync_request_to_peer (void *cls,
1556 struct GNUNET_MessageHeader *m = buf;
1559 #if DEBUG_CHAT_SERVICE
1560 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting P2P sync request\n");
1562 msg_size = sizeof (struct GNUNET_MessageHeader);
1563 GNUNET_assert (size >= msg_size);
1564 GNUNET_assert (NULL != buf);
1566 m->type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_SYNC_REQUEST);
1567 m->size = htons (msg_size);
1573 * Method called whenever a peer connects.
1575 * @param cls closure
1576 * @param peer peer identity this notification is about
1577 * @param atsi performance data
1580 peer_connect_handler (void *cls,
1581 const struct GNUNET_PeerIdentity *peer,
1582 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1584 struct ConnectedPeer *cp;
1585 struct GNUNET_CORE_TransmitHandle *th;
1587 if (0 == memcmp (peer, me, sizeof (struct GNUNET_PeerIdentity)))
1589 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1590 "Peer connected: %s\n", GNUNET_i2s (peer));
1591 th = GNUNET_CORE_notify_transmit_ready (core,
1595 sizeof (struct GNUNET_MessageHeader),
1596 &transmit_sync_request_to_peer,
1598 GNUNET_assert (NULL != th);
1599 cp = GNUNET_CONTAINER_multihashmap_get (connected_peers,
1606 cp = GNUNET_malloc (sizeof (struct ConnectedPeer));
1607 cp->pid = GNUNET_PEER_intern (peer);
1608 GNUNET_break (GNUNET_OK ==
1609 GNUNET_CONTAINER_multihashmap_put (connected_peers,
1612 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1617 * Iterator to free peer entries.
1619 * @param cls closure, unused
1620 * @param key current key code
1621 * @param value value in the hash map (peer entry)
1622 * @return GNUNET_YES (we should continue to iterate)
1625 clean_peer (void *cls,
1626 const GNUNET_HashCode * key,
1629 struct ConnectedPeer *cp;
1630 const struct GNUNET_PeerIdentity *peer = (const struct GNUNET_PeerIdentity *) key;
1632 cp = GNUNET_CONTAINER_multihashmap_get (connected_peers,
1636 GNUNET_break (GNUNET_YES ==
1637 GNUNET_CONTAINER_multihashmap_remove (connected_peers,
1640 GNUNET_PEER_change_rc (cp->pid, -1);
1647 * Method called whenever a peer disconnects.
1649 * @param cls closure, not used
1650 * @param peer peer identity this notification is about
1653 peer_disconnect_handler (void *cls,
1654 const struct GNUNET_PeerIdentity *peer)
1657 if (0 == memcmp (peer, me, sizeof (struct GNUNET_PeerIdentity)))
1659 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1660 "Peer disconnected: %s\n", GNUNET_i2s (peer));
1661 clean_peer (NULL, (const GNUNET_HashCode *) peer, NULL);
1666 * Task run during shutdown.
1672 cleanup_task (void *cls,
1673 const struct GNUNET_SCHEDULER_TaskContext *tc)
1675 struct AnonymousMessage *next_msg;
1676 struct ChatClient *next_client;
1678 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Cleaning up\n");
1681 GNUNET_CORE_disconnect (core);
1686 GNUNET_SERVER_notification_context_destroy (nc);
1689 while (NULL != client_list_head)
1691 next_client = client_list_head->next;
1692 GNUNET_free (client_list_head->room);
1693 GNUNET_free_non_null (client_list_head->member_info);
1694 GNUNET_free (client_list_head);
1695 client_list_head = next_client;
1697 while (NULL != anonymous_list_head)
1699 next_msg = anonymous_list_head->next;
1700 GNUNET_free (anonymous_list_head);
1701 anonymous_list_head = next_msg;
1703 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
1706 GNUNET_CONTAINER_multihashmap_destroy (connected_peers);
1707 connected_peers = NULL;
1712 * To be called on core init/fail.
1714 * @param cls closure, NULL
1715 * @param server handle to the server for this service
1716 * @param my_identity the public identity of this peer
1717 * @param publicKey the public key of this peer
1720 core_init (void *cls,
1721 struct GNUNET_CORE_Handle *server,
1722 const struct GNUNET_PeerIdentity *my_identity,
1723 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey)
1725 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Core initialized\n");
1731 * Process chat requests.
1733 * @param cls closure, NULL
1734 * @param server the initialized server
1735 * @param c configuration to use
1739 struct GNUNET_SERVER_Handle *server,
1740 const struct GNUNET_CONFIGURATION_Handle *c)
1742 static const struct GNUNET_SERVER_MessageHandler handlers[] =
1744 { &handle_join_request, NULL,
1745 GNUNET_MESSAGE_TYPE_CHAT_JOIN_REQUEST, 0 },
1746 { &handle_transmit_request, NULL,
1747 GNUNET_MESSAGE_TYPE_CHAT_TRANSMIT_REQUEST, 0 },
1748 { &handle_acknowledge_request, NULL,
1749 GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_RECEIPT,
1750 sizeof (struct ConfirmationReceiptMessage) },
1751 { NULL, NULL, 0, 0 }
1753 static const struct GNUNET_CORE_MessageHandler p2p_handlers[] =
1755 { &handle_p2p_join_notification,
1756 GNUNET_MESSAGE_TYPE_CHAT_P2P_JOIN_NOTIFICATION, 0 },
1757 { &handle_p2p_leave_notification,
1758 GNUNET_MESSAGE_TYPE_CHAT_P2P_LEAVE_NOTIFICATION,
1759 sizeof (struct P2PLeaveNotificationMessage) },
1760 { &handle_p2p_message_notification,
1761 GNUNET_MESSAGE_TYPE_CHAT_P2P_MESSAGE_NOTIFICATION, 0 },
1762 { &handle_p2p_sync_request,
1763 GNUNET_MESSAGE_TYPE_CHAT_P2P_SYNC_REQUEST,
1764 sizeof (struct GNUNET_MessageHeader) },
1765 { &handle_p2p_confirmation_receipt,
1766 GNUNET_MESSAGE_TYPE_CHAT_P2P_CONFIRMATION_RECEIPT,
1767 sizeof (struct P2PConfirmationReceiptMessage) },
1771 GNUNET_log_setup ("gnunet-service-chat",
1772 #if DEBUG_CHAT_SERVICE
1779 nc = GNUNET_SERVER_notification_context_create (server, 16);
1780 connected_peers = GNUNET_CONTAINER_multihashmap_create (EXPECTED_NEIGHBOUR_COUNT);
1781 GNUNET_SERVER_add_handlers (server, handlers);
1782 core = GNUNET_CORE_connect (cfg,
1786 &peer_connect_handler,
1787 &peer_disconnect_handler,
1792 GNUNET_SERVER_disconnect_notify (server,
1793 &handle_client_disconnect,
1795 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1802 * The main function for the chat service.
1804 * @param argc number of arguments from the command line
1805 * @param argv command line arguments
1806 * @return 0 ok, 1 on error
1809 main (int argc, char *const *argv)
1811 return (GNUNET_OK ==
1812 GNUNET_SERVICE_run (argc,
1815 GNUNET_SERVICE_OPTION_NONE,
1816 &run, NULL)) ? 0 : 1;
1819 /* end of gnunet-service-chat.c */