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,
269 ntohs (msg->header.size),
270 &transmit_message_notification_to_peer,
272 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
273 _("Failed to queue a message notification\n"));
279 * A client sent a chat message. Encrypt the message text if the message is
280 * private. Send the message to local room members and to all connected peers.
282 * @param cls closure, NULL
283 * @param client identification of the client
284 * @param message the actual message
287 handle_transmit_request (void *cls,
288 struct GNUNET_SERVER_Client *client,
289 const struct GNUNET_MessageHeader *message)
291 static GNUNET_HashCode all_zeros;
292 const struct TransmitRequestMessage *trmsg;
293 struct ReceiveNotificationMessage *rnmsg;
294 struct P2PReceiveNotificationMessage *p2p_rnmsg;
295 struct ChatClient *pos;
296 struct ChatClient *target;
297 struct GNUNET_CRYPTO_AesSessionKey key;
298 char encrypted_msg[MAX_MESSAGE_LENGTH];
305 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client sent a chat message\n");
306 if (ntohs (message->size) <= sizeof (struct TransmitRequestMessage))
308 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n");
310 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
313 trmsg = (const struct TransmitRequestMessage *) message;
314 msg_len = ntohs (trmsg->header.size) - sizeof (struct TransmitRequestMessage);
315 is_priv = (0 != (ntohl (trmsg->msg_options) & GNUNET_CHAT_MSG_PRIVATE));
318 #if DEBUG_CHAT_SERVICE
319 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypting the message text\n");
321 GNUNET_CRYPTO_aes_create_session_key (&key);
322 msg_len = GNUNET_CRYPTO_aes_encrypt (&trmsg[1],
325 (const struct GNUNET_CRYPTO_AesInitializationVector *) INITVALUE,
329 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
330 "Could not encrypt the message text\n");
332 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
336 rnmsg = GNUNET_malloc (sizeof (struct ReceiveNotificationMessage) + msg_len);
337 rnmsg->header.size = htons (sizeof (struct ReceiveNotificationMessage) +
339 rnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION);
340 rnmsg->msg_options = trmsg->msg_options;
341 rnmsg->timestamp = trmsg->timestamp;
342 pos = client_list_head;
343 while ((NULL != pos) && (pos->client != client))
347 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
348 "The client is not a member of a chat room. Client has to "
349 "join a chat room first\n");
351 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
356 pos->msg_sequence_number = ntohl (trmsg->sequence_number);
357 is_anon = (0 != (ntohl (trmsg->msg_options) & GNUNET_CHAT_MSG_ANONYMOUS));
360 memset (&rnmsg->sender, 0, sizeof (GNUNET_HashCode));
361 rnmsg->sequence_number = 0;
365 rnmsg->sender = pos->id;
366 rnmsg->sequence_number = trmsg->sequence_number;
370 #if DEBUG_CHAT_SERVICE
371 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
372 "Encrypting the session key using the public key of '%s'\n",
373 GNUNET_h2s (&trmsg->target));
375 if (0 == memcmp (&all_zeros, &trmsg->target, sizeof (GNUNET_HashCode)))
377 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
378 "Malformed message: private, but no target\n");
380 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
384 memcpy (&rnmsg[1], encrypted_msg, msg_len);
385 target = client_list_head;
386 while ((NULL != target) &&
387 (0 != memcmp (&target->id,
389 sizeof (GNUNET_HashCode))))
390 target = target->next;
393 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
394 "Unknown target of the private message\n");
396 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
400 if (GNUNET_SYSERR == GNUNET_CRYPTO_rsa_encrypt (&key,
401 sizeof (struct GNUNET_CRYPTO_AesSessionKey),
403 &rnmsg->encrypted_key))
405 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
406 "Could not encrypt the session key\n");
408 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
415 memcpy (&rnmsg[1], &trmsg[1], msg_len);
417 pos = client_list_head;
418 #if DEBUG_CHAT_SERVICE
419 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message to local room members\n");
423 if ((0 == strcmp (room, pos->room)) &&
424 (NULL != pos->client) &&
425 (pos->client != client))
428 (0 == memcmp (&trmsg->target,
430 sizeof (GNUNET_HashCode)))) &&
431 (0 == (ntohl (trmsg->msg_options) & (~pos->msg_options))))
433 GNUNET_SERVER_notification_context_unicast (nc,
441 #if DEBUG_CHAT_SERVICE
442 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
443 "Broadcasting message to neighbour peers\n");
447 room_len = strlen (room);
448 p2p_rnmsg = GNUNET_malloc (sizeof (struct P2PReceiveNotificationMessage) +
450 p2p_rnmsg->header.size =
451 htons (sizeof (struct P2PReceiveNotificationMessage) + msg_len +
453 p2p_rnmsg->room_name_len = htons (room_len);
454 memcpy ((char *) &p2p_rnmsg[1], room, room_len);
455 memcpy ((char *) &p2p_rnmsg[1] + room_len, &trmsg[1], msg_len);
459 p2p_rnmsg = GNUNET_malloc (sizeof (struct P2PReceiveNotificationMessage) +
461 p2p_rnmsg->header.size =
462 htons (sizeof (struct P2PReceiveNotificationMessage) + msg_len);
465 memcpy (&p2p_rnmsg[1], encrypted_msg, msg_len);
466 memcpy (&p2p_rnmsg->encrypted_key,
467 &rnmsg->encrypted_key,
468 sizeof (struct GNUNET_CRYPTO_RsaEncryptedData));
471 memcpy (&p2p_rnmsg[1], &trmsg[1], msg_len);
473 p2p_rnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_MESSAGE_NOTIFICATION);
474 p2p_rnmsg->msg_options = trmsg->msg_options;
475 p2p_rnmsg->sequence_number = trmsg->sequence_number;
476 p2p_rnmsg->timestamp = trmsg->timestamp;
477 p2p_rnmsg->reserved = 0;
478 p2p_rnmsg->sender = rnmsg->sender;
479 p2p_rnmsg->target = trmsg->target;
481 remember_anonymous_message (p2p_rnmsg);
482 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
483 &send_message_noficiation,
485 GNUNET_free (p2p_rnmsg);
486 GNUNET_SERVER_receive_done (client, GNUNET_OK);
492 * Transmit a join notification to the peer.
494 * @param cls closure, pointer to the 'struct ChatClient'
495 * @param size number of bytes available in buf
496 * @param buf where the callee should write the message
497 * @return number of bytes written to buf
500 transmit_join_notification_to_peer (void *cls,
504 struct ChatClient *entry = cls;
505 struct P2PJoinNotificationMessage *m = buf;
511 #if DEBUG_CHAT_SERVICE
512 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
513 "Transmitting P2P join notification\n");
515 room_len = strlen (entry->room);
516 meta_len = entry->meta_len;
517 msg_size = sizeof (struct P2PJoinNotificationMessage) + meta_len + room_len;
518 GNUNET_assert (size >= msg_size);
519 GNUNET_assert (NULL != buf);
521 m->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_JOIN_NOTIFICATION);
522 m->header.size = htons (msg_size);
523 m->msg_options = htonl (entry->msg_options);
524 m->room_name_len = htons (room_len);
525 m->reserved = htons (0);
526 m->public_key = entry->public_key;
527 roomptr = (char *) &m[1];
528 memcpy (roomptr, entry->room, room_len);
530 memcpy (&roomptr[room_len], entry->member_info, meta_len);
536 * Ask to send a join notification to the peer.
539 send_join_noficiation (void *cls,
540 const GNUNET_HashCode *key,
543 struct ChatClient *entry = cls;
544 struct ConnectedPeer *cp = value;
545 struct GNUNET_PeerIdentity pid;
548 GNUNET_PEER_resolve (cp->pid, &pid);
549 #if DEBUG_CHAT_SERVICE
550 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
551 "Sending join notification to `%s'\n", GNUNET_i2s (&pid));
553 msg_size = sizeof (struct P2PJoinNotificationMessage) +
554 strlen (entry->room) +
556 if (NULL == GNUNET_CORE_notify_transmit_ready (core,
562 &transmit_join_notification_to_peer,
564 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
565 _("Failed to queue a join notification\n"));
571 * A client asked for entering a chat room. Add the new member to the list of
572 * clients and notify remaining room members.
574 * @param cls closure, NULL
575 * @param client identification of the client
576 * @param message the actual message
579 handle_join_request (void *cls,
580 struct GNUNET_SERVER_Client *client,
581 const struct GNUNET_MessageHeader *message)
583 const struct JoinRequestMessage *jrmsg;
586 uint16_t header_size;
588 uint16_t room_name_len;
589 struct ChatClient *new_entry;
590 struct ChatClient *entry;
591 struct JoinNotificationMessage *jnmsg;
592 struct JoinNotificationMessage *entry_jnmsg;
594 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client sent a join request\n");
595 if (ntohs (message->size) <= sizeof (struct JoinRequestMessage))
597 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n");
599 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
602 jrmsg = (const struct JoinRequestMessage *) message;
603 header_size = ntohs (jrmsg->header.size);
604 room_name_len = ntohs (jrmsg->room_name_len);
605 if (header_size - sizeof (struct JoinRequestMessage) <=
608 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
609 "Malformed message: wrong length of the room name\n");
611 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
615 header_size - sizeof (struct JoinRequestMessage) - room_name_len;
616 roomptr = (const char *) &jrmsg[1];
617 room_name = GNUNET_malloc (room_name_len + 1);
618 memcpy (room_name, roomptr, room_name_len);
619 room_name[room_name_len] = '\0';
620 new_entry = GNUNET_malloc (sizeof (struct ChatClient));
621 memset (new_entry, 0, sizeof (struct ChatClient));
622 new_entry->client = client;
623 new_entry->room = room_name;
624 new_entry->public_key = jrmsg->public_key;
625 new_entry->meta_len = meta_len;
628 new_entry->member_info = GNUNET_malloc (meta_len);
629 memcpy (new_entry->member_info, &roomptr[room_name_len], meta_len);
632 new_entry->member_info = NULL;
633 GNUNET_CRYPTO_hash (&new_entry->public_key,
634 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
636 new_entry->msg_options = ntohl (jrmsg->msg_options);
637 new_entry->next = client_list_head;
638 client_list_head = new_entry;
639 #if DEBUG_CHAT_SERVICE
640 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
641 "Synchronizing room members between local clients\n");
643 jnmsg = GNUNET_malloc (sizeof (struct JoinNotificationMessage) + meta_len);
644 jnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION);
646 htons (sizeof (struct JoinNotificationMessage) + meta_len);
647 jnmsg->msg_options = jrmsg->msg_options;
648 jnmsg->public_key = new_entry->public_key;
649 memcpy (&jnmsg[1], &roomptr[room_name_len], meta_len);
650 GNUNET_SERVER_notification_context_add (nc, client);
651 entry = client_list_head;
652 while (NULL != entry)
654 if (0 == strcmp (room_name, entry->room))
656 if (NULL != entry->client)
657 GNUNET_SERVER_notification_context_unicast (nc,
661 if (entry->client != client)
664 GNUNET_malloc (sizeof (struct JoinNotificationMessage) +
666 entry_jnmsg->header.type =
667 htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION);
668 entry_jnmsg->header.size =
669 htons (sizeof (struct JoinNotificationMessage) +
671 entry_jnmsg->msg_options = entry->msg_options;
672 entry_jnmsg->public_key = entry->public_key;
673 memcpy (&entry_jnmsg[1], entry->member_info, entry->meta_len);
674 GNUNET_SERVER_notification_context_unicast (nc,
676 &entry_jnmsg->header,
678 GNUNET_free (entry_jnmsg);
683 #if DEBUG_CHAT_SERVICE
684 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
685 "Broadcasting join notification to neighbour peers\n");
687 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
688 &send_join_noficiation,
690 GNUNET_SERVER_receive_done (client, GNUNET_OK);
695 * Transmit a confirmation receipt to the peer.
697 * @param cls closure, pointer to the 'struct P2PConfirmationReceiptMessage'
698 * @param size number of bytes available in buf
699 * @param buf where the callee should write the message
700 * @return number of bytes written to buf
703 transmit_confirmation_receipt_to_peer (void *cls,
707 struct P2PConfirmationReceiptMessage *receipt = cls;
710 #if DEBUG_CHAT_SERVICE
711 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
712 "Transmitting P2P confirmation receipt to '%s'\n",
713 GNUNET_h2s (&receipt->target));
717 /* client disconnected */
718 #if DEBUG_CHAT_SERVICE
719 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
720 "Buffer is NULL, dropping the message\n");
724 msg_size = sizeof (struct P2PConfirmationReceiptMessage);
725 GNUNET_assert (size >= msg_size);
726 memcpy (buf, receipt, msg_size);
727 GNUNET_free (receipt);
733 * Ask to send a confirmation receipt to the peer.
736 send_confirmation_receipt (void *cls,
737 const GNUNET_HashCode *key,
740 struct P2PConfirmationReceiptMessage *receipt = cls;
741 struct ConnectedPeer *cp = value;
742 struct GNUNET_PeerIdentity pid;
743 struct P2PConfirmationReceiptMessage *my_receipt;
746 GNUNET_PEER_resolve (cp->pid, &pid);
747 #if DEBUG_CHAT_SERVICE
748 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
749 "Sending confirmation receipt to `%s'\n", GNUNET_i2s (&pid));
751 msg_size = sizeof (struct P2PConfirmationReceiptMessage);
752 my_receipt = GNUNET_memdup (receipt,
753 sizeof (struct P2PConfirmationReceiptMessage));
754 if (NULL == GNUNET_CORE_notify_transmit_ready (core,
760 &transmit_confirmation_receipt_to_peer,
762 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
763 _("Failed to queue a confirmation receipt\n"));
769 * A client sent a confirmation receipt. Broadcast the receipt to all connected
770 * peers if the author of the original message is a local client. Otherwise
771 * check the signature and notify the user if the signature is valid.
773 * @param cls closure, NULL
774 * @param client identification of the client
775 * @param message the actual message
778 handle_acknowledge_request (void *cls,
779 struct GNUNET_SERVER_Client *client,
780 const struct GNUNET_MessageHeader *message)
782 const struct ConfirmationReceiptMessage *receipt;
783 struct ConfirmationReceiptMessage *crmsg;
784 struct P2PConfirmationReceiptMessage *p2p_crmsg;
785 struct ChatClient *target;
786 struct ChatClient *author;
788 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client sent a confirmation receipt\n");
789 receipt = (const struct ConfirmationReceiptMessage *) message;
790 author = client_list_head;
791 while ((NULL != author) &&
792 (0 != memcmp (&receipt->author,
794 sizeof (GNUNET_HashCode))))
795 author = author->next;
798 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
799 "Unknown author of the original message\n");
801 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
804 target = client_list_head;
805 while ((NULL != target) &&
806 (0 != memcmp (&receipt->target,
808 sizeof (GNUNET_HashCode))))
809 target = target->next;
812 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
813 "Unknown target of the confirmation receipt\n");
815 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
818 if (NULL == author->client)
820 target->rcpt_sequence_number++;
821 #if DEBUG_CHAT_SERVICE
822 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
823 "Broadcasting %s's receipt #%u to neighbour peers\n",
824 GNUNET_h2s (&target->id), target->rcpt_sequence_number);
826 p2p_crmsg = GNUNET_malloc (sizeof (struct P2PConfirmationReceiptMessage));
827 p2p_crmsg->header.size = htons (sizeof (struct P2PConfirmationReceiptMessage));
828 p2p_crmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_CONFIRMATION_RECEIPT);
829 p2p_crmsg->signature = receipt->signature;
830 p2p_crmsg->purpose = receipt->purpose;
831 p2p_crmsg->msg_sequence_number = receipt->sequence_number;
832 p2p_crmsg->timestamp = receipt->timestamp;
833 p2p_crmsg->target = receipt->target;
834 p2p_crmsg->author = receipt->author;
835 p2p_crmsg->content = receipt->content;
836 p2p_crmsg->sequence_number = htonl (target->rcpt_sequence_number);
837 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
838 &send_confirmation_receipt,
840 GNUNET_free (p2p_crmsg);
844 #if DEBUG_CHAT_SERVICE
845 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
846 "Verifying signature of the receipt\n");
849 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_CHAT_RECEIPT,
852 &target->public_key))
854 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
855 "Invalid signature of the receipt\n");
857 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
860 #if DEBUG_CHAT_SERVICE
861 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
862 "Sending receipt to the client which sent the original message\n");
864 crmsg = GNUNET_memdup (receipt, sizeof (struct ConfirmationReceiptMessage));
865 crmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION);
866 GNUNET_SERVER_notification_context_unicast (nc,
872 GNUNET_SERVER_receive_done (client, GNUNET_OK);
877 * Transmit a leave notification to the peer.
879 * @param cls closure, pointer to the
880 * 'struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded'
881 * @param size number of bytes available in buf
882 * @param buf where the callee should write the message
883 * @return number of bytes written to buf
886 transmit_leave_notification_to_peer (void *cls,
890 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key = cls;
891 struct P2PLeaveNotificationMessage *m = buf;
894 #if DEBUG_CHAT_SERVICE
895 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
896 "Transmitting P2P leave notification\n");
900 /* client disconnected */
901 #if DEBUG_CHAT_SERVICE
902 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
903 "Buffer is NULL, dropping the message\n");
907 msg_size = sizeof (struct P2PLeaveNotificationMessage);
908 GNUNET_assert (size >= msg_size);
910 m->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_LEAVE_NOTIFICATION);
911 m->header.size = htons (msg_size);
912 m->reserved = htons (0);
913 m->user = *public_key;
914 GNUNET_free (public_key);
920 * Ask to send a leave notification to the peer.
923 send_leave_noficiation (void *cls,
924 const GNUNET_HashCode *key,
927 struct ChatClient *entry = cls;
928 struct ConnectedPeer *cp = value;
929 struct GNUNET_PeerIdentity pid;
930 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key;
933 GNUNET_PEER_resolve (cp->pid, &pid);
934 #if DEBUG_CHAT_SERVICE
935 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
936 "Sending leave notification to `%s'\n", GNUNET_i2s (&pid));
938 msg_size = sizeof (struct P2PLeaveNotificationMessage);
939 public_key = GNUNET_memdup (&entry->public_key,
940 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
941 if (NULL == GNUNET_CORE_notify_transmit_ready (core,
947 &transmit_leave_notification_to_peer,
949 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
950 _("Failed to queue a leave notification\n"));
956 * A client disconnected. Remove all of its data structure entries and notify
957 * remaining room members.
959 * @param cls closure, NULL
960 * @param client identification of the client
963 handle_client_disconnect (void *cls,
964 struct GNUNET_SERVER_Client *client)
966 struct ChatClient *entry;
967 struct ChatClient *pos;
968 struct ChatClient *prev;
969 struct LeaveNotificationMessage lnmsg;
971 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client disconnected\n");
972 pos = client_list_head;
974 while ((NULL != pos) && (pos->client != client))
981 #if DEBUG_CHAT_SERVICE
982 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
983 "No such client. There is nothing to do\n");
988 client_list_head = pos->next;
990 prev->next = pos->next;
991 entry = client_list_head;
992 #if DEBUG_CHAT_SERVICE
993 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
994 "Notifying local room members that the client has disconnected\n");
996 lnmsg.header.size = htons (sizeof (struct LeaveNotificationMessage));
997 lnmsg.header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION);
998 lnmsg.reserved = htonl (0);
999 lnmsg.user = pos->public_key;
1000 while (NULL != entry)
1002 if ((0 == strcmp (pos->room, entry->room)) &&
1003 (NULL != entry->client))
1005 GNUNET_SERVER_notification_context_unicast (nc,
1010 entry = entry->next;
1012 #if DEBUG_CHAT_SERVICE
1013 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1014 "Broadcasting leave notification to neighbour peers\n");
1016 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
1017 &send_leave_noficiation,
1019 GNUNET_free (pos->room);
1020 GNUNET_free_non_null (pos->member_info);
1026 * Handle P2P join notification.
1028 * @param cls closure, always NULL
1029 * @param other the other peer involved
1030 * @param message the actual message
1031 * @param atsi performance information
1032 * @return GNUNET_OK to keep the connection open,
1033 * GNUNET_SYSERR to close it (signal serious error)
1036 handle_p2p_join_notification (void *cls,
1037 const struct GNUNET_PeerIdentity *other,
1038 const struct GNUNET_MessageHeader *message,
1039 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1041 const struct P2PJoinNotificationMessage *p2p_jnmsg;
1043 const char *roomptr;
1044 uint16_t header_size;
1046 uint16_t room_name_len;
1047 struct ChatClient *new_entry;
1048 struct ChatClient *entry;
1049 struct JoinNotificationMessage *jnmsg;
1052 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P join notification\n");
1053 if (ntohs (message->size) <= sizeof (struct P2PJoinNotificationMessage))
1055 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n");
1056 GNUNET_break_op (0);
1057 return GNUNET_SYSERR;
1059 p2p_jnmsg = (const struct P2PJoinNotificationMessage *) message;
1060 header_size = ntohs (p2p_jnmsg->header.size);
1061 room_name_len = ntohs (p2p_jnmsg->room_name_len);
1062 if (header_size - sizeof (struct P2PJoinNotificationMessage) <=
1065 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1066 "Malformed message: wrong length of the room name\n");
1067 GNUNET_break_op (0);
1068 return GNUNET_SYSERR;
1070 GNUNET_CRYPTO_hash (&p2p_jnmsg->public_key,
1071 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1073 entry = client_list_head;
1074 while (NULL != entry)
1076 if (0 == memcmp (&entry->id, &id, sizeof (GNUNET_HashCode)))
1078 #if DEBUG_CHAT_SERVICE
1079 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1080 "The client has already joined. There is nothing to do\n");
1084 entry = entry->next;
1087 header_size - sizeof (struct P2PJoinNotificationMessage) - room_name_len;
1088 roomptr = (const char *) &p2p_jnmsg[1];
1089 room_name = GNUNET_malloc (room_name_len + 1);
1090 memcpy (room_name, roomptr, room_name_len);
1091 room_name[room_name_len] = '\0';
1092 new_entry = GNUNET_malloc (sizeof (struct ChatClient));
1093 memset (new_entry, 0, sizeof (struct ChatClient));
1095 new_entry->client = NULL;
1096 new_entry->room = room_name;
1097 new_entry->public_key = p2p_jnmsg->public_key;
1098 new_entry->meta_len = meta_len;
1101 new_entry->member_info = GNUNET_malloc (meta_len);
1102 memcpy (new_entry->member_info, &roomptr[room_name_len], meta_len);
1105 new_entry->member_info = NULL;
1106 new_entry->msg_options = ntohl (p2p_jnmsg->msg_options);
1107 new_entry->next = client_list_head;
1108 client_list_head = new_entry;
1109 #if DEBUG_CHAT_SERVICE
1110 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1111 "Notifying local room members that we have a new client\n");
1113 jnmsg = GNUNET_malloc (sizeof (struct JoinNotificationMessage) + meta_len);
1114 jnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION);
1115 jnmsg->header.size =
1116 htons (sizeof (struct JoinNotificationMessage) + meta_len);
1117 jnmsg->msg_options = p2p_jnmsg->msg_options;
1118 jnmsg->public_key = new_entry->public_key;
1119 memcpy (&jnmsg[1], &roomptr[room_name_len], meta_len);
1120 entry = client_list_head;
1121 while (NULL != entry)
1123 if ((0 == strcmp (room_name, entry->room)) &&
1124 (NULL != entry->client))
1126 GNUNET_SERVER_notification_context_unicast (nc,
1131 entry = entry->next;
1133 #if DEBUG_CHAT_SERVICE
1134 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1135 "Broadcasting join notification to neighbour peers\n");
1137 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
1138 &send_join_noficiation,
1140 GNUNET_free (jnmsg);
1146 * Handle P2P leave notification.
1148 * @param cls closure, always NULL
1149 * @param other the other peer involved
1150 * @param message the actual message
1151 * @param atsi performance information
1152 * @return GNUNET_OK to keep the connection open,
1153 * GNUNET_SYSERR to close it (signal serious error)
1156 handle_p2p_leave_notification (void *cls,
1157 const struct GNUNET_PeerIdentity *other,
1158 const struct GNUNET_MessageHeader *message,
1159 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1161 const struct P2PLeaveNotificationMessage *p2p_lnmsg;
1163 struct ChatClient *pos;
1164 struct ChatClient *prev;
1165 struct ChatClient *entry;
1166 struct LeaveNotificationMessage lnmsg;
1168 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P leave notification\n");
1169 p2p_lnmsg = (const struct P2PLeaveNotificationMessage *) message;
1170 GNUNET_CRYPTO_hash (&p2p_lnmsg->user,
1171 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1173 pos = client_list_head;
1177 if (0 == memcmp (&pos->id, &id, sizeof (GNUNET_HashCode)))
1184 #if DEBUG_CHAT_SERVICE
1185 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1186 "No such client. There is nothing to do\n");
1191 client_list_head = pos->next;
1193 prev->next = pos->next;
1194 #if DEBUG_CHAT_SERVICE
1195 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1196 "Notifying local room members that the client has gone away\n");
1198 lnmsg.header.size = htons (sizeof (struct LeaveNotificationMessage));
1199 lnmsg.header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION);
1200 lnmsg.reserved = htonl (0);
1201 lnmsg.user = pos->public_key;
1202 entry = client_list_head;
1203 while (NULL != entry)
1205 if (0 == strcmp (pos->room, entry->room) &&
1206 (NULL != entry->client))
1208 GNUNET_SERVER_notification_context_unicast (nc,
1213 entry = entry->next;
1215 #if DEBUG_CHAT_SERVICE
1216 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1217 "Broadcasting leave notification to neighbour peers\n");
1219 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
1220 &send_leave_noficiation,
1222 GNUNET_free (pos->room);
1223 GNUNET_free_non_null (pos->member_info);
1230 * Handle P2P message notification.
1232 * @param cls closure, always NULL
1233 * @param other the other peer involved
1234 * @param message the actual message
1235 * @param atsi performance information
1236 * @return GNUNET_OK to keep the connection open,
1237 * GNUNET_SYSERR to close it (signal serious error)
1240 handle_p2p_message_notification (void *cls,
1241 const struct GNUNET_PeerIdentity *other,
1242 const struct GNUNET_MessageHeader *message,
1243 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1245 const struct P2PReceiveNotificationMessage *p2p_rnmsg;
1246 struct P2PReceiveNotificationMessage *my_p2p_rnmsg;
1247 struct ReceiveNotificationMessage *rnmsg;
1248 struct ChatClient *sender;
1249 struct ChatClient *pos;
1250 static GNUNET_HashCode all_zeros;
1254 uint16_t room_name_len;
1255 char *room_name = NULL;
1258 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P message notification\n");
1259 if (ntohs (message->size) <= sizeof (struct P2PReceiveNotificationMessage))
1261 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n");
1262 GNUNET_break_op (0);
1263 return GNUNET_SYSERR;
1265 p2p_rnmsg = (const struct P2PReceiveNotificationMessage *) message;
1266 msg_len = ntohs (p2p_rnmsg->header.size) -
1267 sizeof (struct P2PReceiveNotificationMessage);
1269 is_anon = (0 != (ntohl (p2p_rnmsg->msg_options) & GNUNET_CHAT_MSG_ANONYMOUS));
1272 room_name_len = ntohs (p2p_rnmsg->room_name_len);
1273 if (msg_len <= room_name_len)
1275 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1276 "Malformed message: wrong length of the room name\n");
1277 GNUNET_break_op (0);
1278 return GNUNET_SYSERR;
1280 msg_len -= room_name_len;
1281 if (lookup_anonymous_message (p2p_rnmsg))
1283 #if DEBUG_CHAT_SERVICE
1284 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1285 "This anonymous message has already been handled.");
1289 remember_anonymous_message (p2p_rnmsg);
1290 room_name = GNUNET_malloc (room_name_len + 1);
1291 memcpy (room_name, (char *) &p2p_rnmsg[1], room_name_len);
1292 room_name[room_name_len] = '\0';
1293 text = (char *) &p2p_rnmsg[1] + room_name_len;
1297 sender = client_list_head;
1298 while ((NULL != sender) &&
1299 (0 != memcmp (&sender->id,
1301 sizeof (GNUNET_HashCode))))
1302 sender = sender->next;
1305 /* not an error since the sender may have left before we got the
1307 #if DEBUG_CHAT_SERVICE
1308 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1309 "Unknown source. Rejecting the message\n");
1313 if (sender->msg_sequence_number >= ntohl (p2p_rnmsg->sequence_number))
1315 #if DEBUG_CHAT_SERVICE
1316 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1317 "This message has already been handled."
1318 " Sequence numbers (msg/sender): %u/%u\n",
1319 ntohl (p2p_rnmsg->sequence_number),
1320 sender->msg_sequence_number);
1324 sender->msg_sequence_number = ntohl (p2p_rnmsg->sequence_number);
1325 room_name = sender->room;
1326 text = (char *) &p2p_rnmsg[1];
1329 #if DEBUG_CHAT_SERVICE
1330 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1331 "Sending message to local room members\n");
1333 rnmsg = GNUNET_malloc (sizeof (struct ReceiveNotificationMessage) + msg_len);
1334 rnmsg->header.size = htons (sizeof (struct ReceiveNotificationMessage) +
1336 rnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION);
1337 rnmsg->msg_options = p2p_rnmsg->msg_options;
1338 rnmsg->sequence_number = p2p_rnmsg->sequence_number;
1339 rnmsg->timestamp = p2p_rnmsg->timestamp;
1340 is_priv = (0 != memcmp (&all_zeros,
1341 &p2p_rnmsg->target, sizeof (GNUNET_HashCode)));
1343 memcpy (&rnmsg->encrypted_key,
1344 &p2p_rnmsg->encrypted_key,
1345 sizeof (struct GNUNET_CRYPTO_RsaEncryptedData));
1346 rnmsg->sender = p2p_rnmsg->sender;
1347 memcpy (&rnmsg[1], text, msg_len);
1348 pos = client_list_head;
1351 if ((0 == strcmp (room_name, pos->room)) &&
1352 (NULL != pos->client))
1355 (0 == memcmp (&p2p_rnmsg->target,
1357 sizeof (GNUNET_HashCode)))) &&
1358 (0 == (ntohl (p2p_rnmsg->msg_options) & (~pos->msg_options))))
1360 GNUNET_SERVER_notification_context_unicast (nc,
1369 GNUNET_free (room_name);
1370 #if DEBUG_CHAT_SERVICE
1371 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1372 "Broadcasting message notification to neighbour peers\n");
1374 my_p2p_rnmsg = GNUNET_memdup (p2p_rnmsg, ntohs (p2p_rnmsg->header.size));
1375 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
1376 &send_message_noficiation,
1378 GNUNET_free (rnmsg);
1384 * Handle P2P sync request.
1386 * @param cls closure, always NULL
1387 * @param other the other peer involved
1388 * @param message the actual message
1389 * @param atsi performance information
1390 * @return GNUNET_OK to keep the connection open,
1391 * GNUNET_SYSERR to close it (signal serious error)
1394 handle_p2p_sync_request (void *cls,
1395 const struct GNUNET_PeerIdentity *other,
1396 const struct GNUNET_MessageHeader *message,
1397 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1399 struct ChatClient *entry;
1400 struct GNUNET_CORE_TransmitHandle *th;
1403 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P sync request\n");
1404 #if DEBUG_CHAT_SERVICE
1405 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1406 "Notifying the requester of all known clients\n");
1408 entry = client_list_head;
1409 while (NULL != entry)
1411 msg_size = sizeof (struct P2PJoinNotificationMessage) +
1412 strlen (entry->room) +
1414 th = GNUNET_CORE_notify_transmit_ready (core,
1420 &transmit_join_notification_to_peer,
1422 GNUNET_assert (NULL != th);
1423 entry = entry->next;
1430 * Handle P2P confirmation receipt.
1432 * @param cls closure, always NULL
1433 * @param other the other peer involved
1434 * @param message the actual message
1435 * @param atsi performance information
1436 * @return GNUNET_OK to keep the connection open,
1437 * GNUNET_SYSERR to close it (signal serious error)
1440 handle_p2p_confirmation_receipt (void *cls,
1441 const struct GNUNET_PeerIdentity *other,
1442 const struct GNUNET_MessageHeader *message,
1443 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1445 const struct P2PConfirmationReceiptMessage *p2p_crmsg;
1446 struct P2PConfirmationReceiptMessage *my_p2p_crmsg;
1447 struct ConfirmationReceiptMessage *crmsg;
1448 struct ChatClient *target;
1449 struct ChatClient *author;
1451 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P confirmation receipt\n");
1452 p2p_crmsg = (const struct P2PConfirmationReceiptMessage *) message;
1453 target = client_list_head;
1454 while ((NULL != target) &&
1455 (0 != memcmp (&target->id,
1457 sizeof (GNUNET_HashCode))))
1458 target = target->next;
1461 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1462 "Unknown source of the receipt. Rejecting the message\n");
1463 GNUNET_break_op (0);
1464 return GNUNET_SYSERR;
1466 if (target->rcpt_sequence_number >= ntohl (p2p_crmsg->sequence_number))
1468 #if DEBUG_CHAT_SERVICE
1469 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1470 "This receipt has already been handled."
1471 " Sequence numbers (msg/sender): %u/%u\n",
1472 ntohl (p2p_crmsg->sequence_number), target->rcpt_sequence_number);
1476 target->rcpt_sequence_number = ntohl (p2p_crmsg->sequence_number);
1477 author = client_list_head;
1478 while ((NULL != author) &&
1479 (0 != memcmp (&author->id,
1481 sizeof (GNUNET_HashCode))))
1482 author = author->next;
1485 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1486 "Unknown addressee. Rejecting the receipt\n");
1487 GNUNET_break_op (0);
1488 return GNUNET_SYSERR;
1491 if (NULL == author->client)
1493 #if DEBUG_CHAT_SERVICE
1494 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1495 "The author of the original message is not a local client."
1496 " Broadcasting receipt to neighbour peers\n");
1498 my_p2p_crmsg = GNUNET_memdup (p2p_crmsg, sizeof (struct P2PConfirmationReceiptMessage));
1499 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
1500 &send_confirmation_receipt,
1502 GNUNET_free (my_p2p_crmsg);
1506 #if DEBUG_CHAT_SERVICE
1507 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1508 "The author of the original message is a local client."
1509 " Verifying signature of the receipt\n");
1511 crmsg = GNUNET_malloc (sizeof (struct ConfirmationReceiptMessage));
1512 crmsg->header.size = htons (sizeof (struct ConfirmationReceiptMessage));
1513 crmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION);
1514 crmsg->signature = p2p_crmsg->signature;
1515 crmsg->purpose = p2p_crmsg->purpose;
1516 crmsg->sequence_number = p2p_crmsg->msg_sequence_number;
1517 crmsg->reserved2 = 0;
1518 crmsg->timestamp = p2p_crmsg->timestamp;
1519 crmsg->target = p2p_crmsg->target;
1520 crmsg->author = p2p_crmsg->author;
1521 crmsg->content = p2p_crmsg->content;
1523 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_CHAT_RECEIPT,
1526 &target->public_key))
1528 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1529 "Invalid signature of the receipt\n");
1530 GNUNET_break_op (0);
1531 return GNUNET_SYSERR;
1533 #if DEBUG_CHAT_SERVICE
1534 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1535 "The author of the original message is a local client."
1536 " Sending receipt to the client\n");
1538 GNUNET_SERVER_notification_context_unicast (nc,
1542 GNUNET_free (crmsg);
1549 * Transmit a sync request to the peer.
1551 * @param cls closure, NULL
1552 * @param size number of bytes available in buf
1553 * @param buf where the callee should write the message
1554 * @return number of bytes written to buf
1557 transmit_sync_request_to_peer (void *cls,
1561 struct GNUNET_MessageHeader *m = buf;
1564 #if DEBUG_CHAT_SERVICE
1565 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting P2P sync request\n");
1567 msg_size = sizeof (struct GNUNET_MessageHeader);
1568 GNUNET_assert (size >= msg_size);
1569 GNUNET_assert (NULL != buf);
1571 m->type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_SYNC_REQUEST);
1572 m->size = htons (msg_size);
1578 * Method called whenever a peer connects.
1580 * @param cls closure
1581 * @param peer peer identity this notification is about
1582 * @param atsi performance data
1585 peer_connect_handler (void *cls,
1586 const struct GNUNET_PeerIdentity *peer,
1587 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1589 struct ConnectedPeer *cp;
1590 struct GNUNET_CORE_TransmitHandle *th;
1592 if (0 == memcmp (peer, me, sizeof (struct GNUNET_PeerIdentity)))
1594 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1595 "Peer connected: %s\n", GNUNET_i2s (peer));
1596 th = GNUNET_CORE_notify_transmit_ready (core,
1601 sizeof (struct GNUNET_MessageHeader),
1602 &transmit_sync_request_to_peer,
1604 GNUNET_assert (NULL != th);
1605 cp = GNUNET_CONTAINER_multihashmap_get (connected_peers,
1612 cp = GNUNET_malloc (sizeof (struct ConnectedPeer));
1613 cp->pid = GNUNET_PEER_intern (peer);
1614 GNUNET_break (GNUNET_OK ==
1615 GNUNET_CONTAINER_multihashmap_put (connected_peers,
1618 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1623 * Iterator to free peer entries.
1625 * @param cls closure, unused
1626 * @param key current key code
1627 * @param value value in the hash map (peer entry)
1628 * @return GNUNET_YES (we should continue to iterate)
1631 clean_peer (void *cls,
1632 const GNUNET_HashCode * key,
1635 struct ConnectedPeer *cp;
1636 const struct GNUNET_PeerIdentity *peer = (const struct GNUNET_PeerIdentity *) key;
1638 cp = GNUNET_CONTAINER_multihashmap_get (connected_peers,
1642 GNUNET_break (GNUNET_YES ==
1643 GNUNET_CONTAINER_multihashmap_remove (connected_peers,
1646 GNUNET_PEER_change_rc (cp->pid, -1);
1653 * Method called whenever a peer disconnects.
1655 * @param cls closure, not used
1656 * @param peer peer identity this notification is about
1659 peer_disconnect_handler (void *cls,
1660 const struct GNUNET_PeerIdentity *peer)
1663 if (0 == memcmp (peer, me, sizeof (struct GNUNET_PeerIdentity)))
1665 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1666 "Peer disconnected: %s\n", GNUNET_i2s (peer));
1667 clean_peer (NULL, (const GNUNET_HashCode *) peer, NULL);
1672 * Task run during shutdown.
1678 cleanup_task (void *cls,
1679 const struct GNUNET_SCHEDULER_TaskContext *tc)
1681 struct AnonymousMessage *next_msg;
1682 struct ChatClient *next_client;
1684 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Cleaning up\n");
1687 GNUNET_CORE_disconnect (core);
1692 GNUNET_SERVER_notification_context_destroy (nc);
1695 while (NULL != client_list_head)
1697 next_client = client_list_head->next;
1698 GNUNET_free (client_list_head->room);
1699 GNUNET_free_non_null (client_list_head->member_info);
1700 GNUNET_free (client_list_head);
1701 client_list_head = next_client;
1703 while (NULL != anonymous_list_head)
1705 next_msg = anonymous_list_head->next;
1706 GNUNET_free (anonymous_list_head);
1707 anonymous_list_head = next_msg;
1709 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
1712 GNUNET_CONTAINER_multihashmap_destroy (connected_peers);
1713 connected_peers = NULL;
1718 * To be called on core init/fail.
1720 * @param cls closure, NULL
1721 * @param server handle to the server for this service
1722 * @param my_identity the public identity of this peer
1723 * @param publicKey the public key of this peer
1726 core_init (void *cls,
1727 struct GNUNET_CORE_Handle *server,
1728 const struct GNUNET_PeerIdentity *my_identity,
1729 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey)
1731 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Core initialized\n");
1737 * Process chat requests.
1739 * @param cls closure, NULL
1740 * @param server the initialized server
1741 * @param c configuration to use
1745 struct GNUNET_SERVER_Handle *server,
1746 const struct GNUNET_CONFIGURATION_Handle *c)
1748 static const struct GNUNET_SERVER_MessageHandler handlers[] =
1750 { &handle_join_request, NULL,
1751 GNUNET_MESSAGE_TYPE_CHAT_JOIN_REQUEST, 0 },
1752 { &handle_transmit_request, NULL,
1753 GNUNET_MESSAGE_TYPE_CHAT_TRANSMIT_REQUEST, 0 },
1754 { &handle_acknowledge_request, NULL,
1755 GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_RECEIPT,
1756 sizeof (struct ConfirmationReceiptMessage) },
1757 { NULL, NULL, 0, 0 }
1759 static const struct GNUNET_CORE_MessageHandler p2p_handlers[] =
1761 { &handle_p2p_join_notification,
1762 GNUNET_MESSAGE_TYPE_CHAT_P2P_JOIN_NOTIFICATION, 0 },
1763 { &handle_p2p_leave_notification,
1764 GNUNET_MESSAGE_TYPE_CHAT_P2P_LEAVE_NOTIFICATION,
1765 sizeof (struct P2PLeaveNotificationMessage) },
1766 { &handle_p2p_message_notification,
1767 GNUNET_MESSAGE_TYPE_CHAT_P2P_MESSAGE_NOTIFICATION, 0 },
1768 { &handle_p2p_sync_request,
1769 GNUNET_MESSAGE_TYPE_CHAT_P2P_SYNC_REQUEST,
1770 sizeof (struct GNUNET_MessageHeader) },
1771 { &handle_p2p_confirmation_receipt,
1772 GNUNET_MESSAGE_TYPE_CHAT_P2P_CONFIRMATION_RECEIPT,
1773 sizeof (struct P2PConfirmationReceiptMessage) },
1777 GNUNET_log_setup ("gnunet-service-chat",
1778 #if DEBUG_CHAT_SERVICE
1785 nc = GNUNET_SERVER_notification_context_create (server, 16);
1786 connected_peers = GNUNET_CONTAINER_multihashmap_create (EXPECTED_NEIGHBOUR_COUNT);
1787 GNUNET_SERVER_add_handlers (server, handlers);
1788 core = GNUNET_CORE_connect (cfg,
1792 &peer_connect_handler,
1793 &peer_disconnect_handler,
1798 GNUNET_SERVER_disconnect_notify (server,
1799 &handle_client_disconnect,
1801 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1808 * The main function for the chat service.
1810 * @param argc number of arguments from the command line
1811 * @param argv command line arguments
1812 * @return 0 ok, 1 on error
1815 main (int argc, char *const *argv)
1817 return (GNUNET_OK ==
1818 GNUNET_SERVICE_run (argc,
1821 GNUNET_SERVICE_OPTION_NONE,
1822 &run, NULL)) ? 0 : 1;
1825 /* end of gnunet-service-chat.c */