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 = htons (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->reserved2 = htonl (0);
527 m->public_key = entry->public_key;
528 roomptr = (char *) &m[1];
529 memcpy (roomptr, entry->room, room_len);
531 memcpy (&roomptr[room_len], entry->member_info, meta_len);
537 * Ask to send a join notification to the peer.
540 send_join_noficiation (void *cls,
541 const GNUNET_HashCode *key,
544 struct ChatClient *entry = cls;
545 struct ConnectedPeer *cp = value;
546 struct GNUNET_PeerIdentity pid;
549 GNUNET_PEER_resolve (cp->pid, &pid);
550 #if DEBUG_CHAT_SERVICE
551 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
552 "Sending join notification to `%s'\n", GNUNET_i2s (&pid));
554 msg_size = sizeof (struct P2PJoinNotificationMessage) +
555 strlen (entry->room) +
557 if (NULL == GNUNET_CORE_notify_transmit_ready (core,
563 &transmit_join_notification_to_peer,
565 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
566 _("Failed to queue a join notification\n"));
572 * A client asked for entering a chat room. Add the new member to the list of
573 * clients and notify remaining room members.
575 * @param cls closure, NULL
576 * @param client identification of the client
577 * @param message the actual message
580 handle_join_request (void *cls,
581 struct GNUNET_SERVER_Client *client,
582 const struct GNUNET_MessageHeader *message)
584 const struct JoinRequestMessage *jrmsg;
587 uint16_t header_size;
589 uint16_t room_name_len;
590 struct ChatClient *new_entry;
591 struct ChatClient *entry;
592 struct JoinNotificationMessage *jnmsg;
593 struct JoinNotificationMessage *entry_jnmsg;
595 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client sent a join request\n");
596 if (ntohs (message->size) <= sizeof (struct JoinRequestMessage))
598 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n");
600 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
603 jrmsg = (const struct JoinRequestMessage *) message;
604 header_size = ntohs (jrmsg->header.size);
605 room_name_len = ntohs (jrmsg->room_name_len);
606 if (header_size - sizeof (struct JoinRequestMessage) <=
609 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
610 "Malformed message: wrong length of the room name\n");
612 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
616 header_size - sizeof (struct JoinRequestMessage) - room_name_len;
617 roomptr = (const char *) &jrmsg[1];
618 room_name = GNUNET_malloc (room_name_len + 1);
619 memcpy (room_name, roomptr, room_name_len);
620 room_name[room_name_len] = '\0';
621 new_entry = GNUNET_malloc (sizeof (struct ChatClient));
622 memset (new_entry, 0, sizeof (struct ChatClient));
623 new_entry->client = client;
624 new_entry->room = room_name;
625 new_entry->public_key = jrmsg->public_key;
626 new_entry->meta_len = meta_len;
629 new_entry->member_info = GNUNET_malloc (meta_len);
630 memcpy (new_entry->member_info, &roomptr[room_name_len], meta_len);
633 new_entry->member_info = NULL;
634 GNUNET_CRYPTO_hash (&new_entry->public_key,
635 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
637 new_entry->msg_options = ntohl (jrmsg->msg_options);
638 new_entry->next = client_list_head;
639 client_list_head = new_entry;
640 #if DEBUG_CHAT_SERVICE
641 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
642 "Synchronizing room members between local clients\n");
644 jnmsg = GNUNET_malloc (sizeof (struct JoinNotificationMessage) + meta_len);
645 jnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION);
647 htons (sizeof (struct JoinNotificationMessage) + meta_len);
648 jnmsg->msg_options = jrmsg->msg_options;
649 jnmsg->public_key = new_entry->public_key;
650 memcpy (&jnmsg[1], &roomptr[room_name_len], meta_len);
651 GNUNET_SERVER_notification_context_add (nc, client);
652 entry = client_list_head;
653 while (NULL != entry)
655 if (0 == strcmp (room_name, entry->room))
657 if (NULL != entry->client)
658 GNUNET_SERVER_notification_context_unicast (nc,
662 if (entry->client != client)
665 GNUNET_malloc (sizeof (struct JoinNotificationMessage) +
667 entry_jnmsg->header.type =
668 htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION);
669 entry_jnmsg->header.size =
670 htons (sizeof (struct JoinNotificationMessage) +
672 entry_jnmsg->msg_options = entry->msg_options;
673 entry_jnmsg->public_key = entry->public_key;
674 memcpy (&entry_jnmsg[1], entry->member_info, entry->meta_len);
675 GNUNET_SERVER_notification_context_unicast (nc,
677 &entry_jnmsg->header,
679 GNUNET_free (entry_jnmsg);
684 #if DEBUG_CHAT_SERVICE
685 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
686 "Broadcasting join notification to neighbour peers\n");
688 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
689 &send_join_noficiation,
691 GNUNET_SERVER_receive_done (client, GNUNET_OK);
696 * Transmit a confirmation receipt to the peer.
698 * @param cls closure, pointer to the 'struct P2PConfirmationReceiptMessage'
699 * @param size number of bytes available in buf
700 * @param buf where the callee should write the message
701 * @return number of bytes written to buf
704 transmit_confirmation_receipt_to_peer (void *cls,
708 struct P2PConfirmationReceiptMessage *receipt = cls;
711 #if DEBUG_CHAT_SERVICE
712 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
713 "Transmitting P2P confirmation receipt to '%s'\n",
714 GNUNET_h2s (&receipt->target));
718 /* client disconnected */
719 #if DEBUG_CHAT_SERVICE
720 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
721 "Buffer is NULL, dropping the message\n");
725 msg_size = sizeof (struct P2PConfirmationReceiptMessage);
726 GNUNET_assert (size >= msg_size);
727 memcpy (buf, receipt, msg_size);
728 GNUNET_free (receipt);
734 * Ask to send a confirmation receipt to the peer.
737 send_confirmation_receipt (void *cls,
738 const GNUNET_HashCode *key,
741 struct P2PConfirmationReceiptMessage *receipt = cls;
742 struct ConnectedPeer *cp = value;
743 struct GNUNET_PeerIdentity pid;
744 struct P2PConfirmationReceiptMessage *my_receipt;
747 GNUNET_PEER_resolve (cp->pid, &pid);
748 #if DEBUG_CHAT_SERVICE
749 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
750 "Sending confirmation receipt to `%s'\n", GNUNET_i2s (&pid));
752 msg_size = sizeof (struct P2PConfirmationReceiptMessage);
753 my_receipt = GNUNET_memdup (receipt,
754 sizeof (struct P2PConfirmationReceiptMessage));
755 if (NULL == GNUNET_CORE_notify_transmit_ready (core,
761 &transmit_confirmation_receipt_to_peer,
763 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
764 _("Failed to queue a confirmation receipt\n"));
770 * A client sent a confirmation receipt. Broadcast the receipt to all connected
771 * peers if the author of the original message is a local client. Otherwise
772 * check the signature and notify the user if the signature is valid.
774 * @param cls closure, NULL
775 * @param client identification of the client
776 * @param message the actual message
779 handle_acknowledge_request (void *cls,
780 struct GNUNET_SERVER_Client *client,
781 const struct GNUNET_MessageHeader *message)
783 const struct ConfirmationReceiptMessage *receipt;
784 struct ConfirmationReceiptMessage *crmsg;
785 struct P2PConfirmationReceiptMessage *p2p_crmsg;
786 struct ChatClient *target;
787 struct ChatClient *author;
789 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client sent a confirmation receipt\n");
790 receipt = (const struct ConfirmationReceiptMessage *) message;
791 author = client_list_head;
792 while ((NULL != author) &&
793 (0 != memcmp (&receipt->author,
795 sizeof (GNUNET_HashCode))))
796 author = author->next;
799 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
800 "Unknown author of the original message\n");
802 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
805 target = client_list_head;
806 while ((NULL != target) &&
807 (0 != memcmp (&receipt->target,
809 sizeof (GNUNET_HashCode))))
810 target = target->next;
813 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
814 "Unknown target of the confirmation receipt\n");
816 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
819 if (NULL == author->client)
821 target->rcpt_sequence_number++;
822 #if DEBUG_CHAT_SERVICE
823 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
824 "Broadcasting %s's receipt #%u to neighbour peers\n",
825 GNUNET_h2s (&target->id), target->rcpt_sequence_number);
827 p2p_crmsg = GNUNET_malloc (sizeof (struct P2PConfirmationReceiptMessage));
828 p2p_crmsg->header.size = htons (sizeof (struct P2PConfirmationReceiptMessage));
829 p2p_crmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_CONFIRMATION_RECEIPT);
830 p2p_crmsg->reserved = htonl (0);
831 p2p_crmsg->signature = receipt->signature;
832 p2p_crmsg->purpose = receipt->purpose;
833 p2p_crmsg->msg_sequence_number = receipt->sequence_number;
834 p2p_crmsg->timestamp = receipt->timestamp;
835 p2p_crmsg->target = receipt->target;
836 p2p_crmsg->author = receipt->author;
837 p2p_crmsg->content = receipt->content;
838 p2p_crmsg->sequence_number = htonl (target->rcpt_sequence_number);
839 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
840 &send_confirmation_receipt,
842 GNUNET_free (p2p_crmsg);
846 #if DEBUG_CHAT_SERVICE
847 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
848 "Verifying signature of the receipt\n");
851 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_CHAT_RECEIPT,
854 &target->public_key))
856 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
857 "Invalid signature of the receipt\n");
859 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
862 #if DEBUG_CHAT_SERVICE
863 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
864 "Sending receipt to the client which sent the original message\n");
866 crmsg = GNUNET_memdup (receipt, sizeof (struct ConfirmationReceiptMessage));
867 crmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION);
868 GNUNET_SERVER_notification_context_unicast (nc,
874 GNUNET_SERVER_receive_done (client, GNUNET_OK);
879 * Transmit a leave notification to the peer.
881 * @param cls closure, pointer to the
882 * 'struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded'
883 * @param size number of bytes available in buf
884 * @param buf where the callee should write the message
885 * @return number of bytes written to buf
888 transmit_leave_notification_to_peer (void *cls,
892 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key = cls;
893 struct P2PLeaveNotificationMessage *m = buf;
896 #if DEBUG_CHAT_SERVICE
897 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
898 "Transmitting P2P leave notification\n");
902 /* client disconnected */
903 #if DEBUG_CHAT_SERVICE
904 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
905 "Buffer is NULL, dropping the message\n");
909 msg_size = sizeof (struct P2PLeaveNotificationMessage);
910 GNUNET_assert (size >= msg_size);
912 m->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_LEAVE_NOTIFICATION);
913 m->header.size = htons (msg_size);
914 m->reserved = htonl (0);
915 m->user = *public_key;
916 GNUNET_free (public_key);
922 * Ask to send a leave notification to the peer.
925 send_leave_noficiation (void *cls,
926 const GNUNET_HashCode *key,
929 struct ChatClient *entry = cls;
930 struct ConnectedPeer *cp = value;
931 struct GNUNET_PeerIdentity pid;
932 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key;
935 GNUNET_PEER_resolve (cp->pid, &pid);
936 #if DEBUG_CHAT_SERVICE
937 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
938 "Sending leave notification to `%s'\n", GNUNET_i2s (&pid));
940 msg_size = sizeof (struct P2PLeaveNotificationMessage);
941 public_key = GNUNET_memdup (&entry->public_key,
942 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
943 if (NULL == GNUNET_CORE_notify_transmit_ready (core,
949 &transmit_leave_notification_to_peer,
951 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
952 _("Failed to queue a leave notification\n"));
958 * A client disconnected. Remove all of its data structure entries and notify
959 * remaining room members.
961 * @param cls closure, NULL
962 * @param client identification of the client
965 handle_client_disconnect (void *cls,
966 struct GNUNET_SERVER_Client *client)
968 struct ChatClient *entry;
969 struct ChatClient *pos;
970 struct ChatClient *prev;
971 struct LeaveNotificationMessage lnmsg;
973 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client disconnected\n");
974 pos = client_list_head;
976 while ((NULL != pos) && (pos->client != client))
983 #if DEBUG_CHAT_SERVICE
984 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
985 "No such client. There is nothing to do\n");
990 client_list_head = pos->next;
992 prev->next = pos->next;
993 entry = client_list_head;
994 #if DEBUG_CHAT_SERVICE
995 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
996 "Notifying local room members that the client has disconnected\n");
998 lnmsg.header.size = htons (sizeof (struct LeaveNotificationMessage));
999 lnmsg.header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION);
1000 lnmsg.reserved = htonl (0);
1001 lnmsg.user = pos->public_key;
1002 while (NULL != entry)
1004 if ((0 == strcmp (pos->room, entry->room)) &&
1005 (NULL != entry->client))
1007 GNUNET_SERVER_notification_context_unicast (nc,
1012 entry = entry->next;
1014 #if DEBUG_CHAT_SERVICE
1015 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1016 "Broadcasting leave notification to neighbour peers\n");
1018 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
1019 &send_leave_noficiation,
1021 GNUNET_free (pos->room);
1022 GNUNET_free_non_null (pos->member_info);
1028 * Handle P2P join notification.
1030 * @param cls closure, always NULL
1031 * @param other the other peer involved
1032 * @param message the actual message
1033 * @param atsi performance information
1034 * @return GNUNET_OK to keep the connection open,
1035 * GNUNET_SYSERR to close it (signal serious error)
1038 handle_p2p_join_notification (void *cls,
1039 const struct GNUNET_PeerIdentity *other,
1040 const struct GNUNET_MessageHeader *message,
1041 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1043 const struct P2PJoinNotificationMessage *p2p_jnmsg;
1045 const char *roomptr;
1046 uint16_t header_size;
1048 uint16_t room_name_len;
1049 struct ChatClient *new_entry;
1050 struct ChatClient *entry;
1051 struct JoinNotificationMessage *jnmsg;
1054 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P join notification\n");
1055 if (ntohs (message->size) <= sizeof (struct P2PJoinNotificationMessage))
1057 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n");
1058 GNUNET_break_op (0);
1059 return GNUNET_SYSERR;
1061 p2p_jnmsg = (const struct P2PJoinNotificationMessage *) message;
1062 header_size = ntohs (p2p_jnmsg->header.size);
1063 room_name_len = ntohs (p2p_jnmsg->room_name_len);
1064 if (header_size - sizeof (struct P2PJoinNotificationMessage) <=
1067 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1068 "Malformed message: wrong length of the room name\n");
1069 GNUNET_break_op (0);
1070 return GNUNET_SYSERR;
1072 GNUNET_CRYPTO_hash (&p2p_jnmsg->public_key,
1073 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1075 entry = client_list_head;
1076 while (NULL != entry)
1078 if (0 == memcmp (&entry->id, &id, sizeof (GNUNET_HashCode)))
1080 #if DEBUG_CHAT_SERVICE
1081 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1082 "The client has already joined. There is nothing to do\n");
1086 entry = entry->next;
1089 header_size - sizeof (struct P2PJoinNotificationMessage) - room_name_len;
1090 roomptr = (const char *) &p2p_jnmsg[1];
1091 room_name = GNUNET_malloc (room_name_len + 1);
1092 memcpy (room_name, roomptr, room_name_len);
1093 room_name[room_name_len] = '\0';
1094 new_entry = GNUNET_malloc (sizeof (struct ChatClient));
1095 memset (new_entry, 0, sizeof (struct ChatClient));
1097 new_entry->client = NULL;
1098 new_entry->room = room_name;
1099 new_entry->public_key = p2p_jnmsg->public_key;
1100 new_entry->meta_len = meta_len;
1103 new_entry->member_info = GNUNET_malloc (meta_len);
1104 memcpy (new_entry->member_info, &roomptr[room_name_len], meta_len);
1107 new_entry->member_info = NULL;
1108 new_entry->msg_options = ntohl (p2p_jnmsg->msg_options);
1109 new_entry->next = client_list_head;
1110 client_list_head = new_entry;
1111 #if DEBUG_CHAT_SERVICE
1112 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1113 "Notifying local room members that we have a new client\n");
1115 jnmsg = GNUNET_malloc (sizeof (struct JoinNotificationMessage) + meta_len);
1116 jnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION);
1117 jnmsg->header.size =
1118 htons (sizeof (struct JoinNotificationMessage) + meta_len);
1119 jnmsg->msg_options = p2p_jnmsg->msg_options;
1120 jnmsg->public_key = new_entry->public_key;
1121 memcpy (&jnmsg[1], &roomptr[room_name_len], meta_len);
1122 entry = client_list_head;
1123 while (NULL != entry)
1125 if ((0 == strcmp (room_name, entry->room)) &&
1126 (NULL != entry->client))
1128 GNUNET_SERVER_notification_context_unicast (nc,
1133 entry = entry->next;
1135 #if DEBUG_CHAT_SERVICE
1136 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1137 "Broadcasting join notification to neighbour peers\n");
1139 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
1140 &send_join_noficiation,
1142 GNUNET_free (jnmsg);
1148 * Handle P2P leave notification.
1150 * @param cls closure, always NULL
1151 * @param other the other peer involved
1152 * @param message the actual message
1153 * @param atsi performance information
1154 * @return GNUNET_OK to keep the connection open,
1155 * GNUNET_SYSERR to close it (signal serious error)
1158 handle_p2p_leave_notification (void *cls,
1159 const struct GNUNET_PeerIdentity *other,
1160 const struct GNUNET_MessageHeader *message,
1161 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1163 const struct P2PLeaveNotificationMessage *p2p_lnmsg;
1165 struct ChatClient *pos;
1166 struct ChatClient *prev;
1167 struct ChatClient *entry;
1168 struct LeaveNotificationMessage lnmsg;
1170 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P leave notification\n");
1171 p2p_lnmsg = (const struct P2PLeaveNotificationMessage *) message;
1172 GNUNET_CRYPTO_hash (&p2p_lnmsg->user,
1173 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1175 pos = client_list_head;
1179 if (0 == memcmp (&pos->id, &id, sizeof (GNUNET_HashCode)))
1186 #if DEBUG_CHAT_SERVICE
1187 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1188 "No such client. There is nothing to do\n");
1193 client_list_head = pos->next;
1195 prev->next = pos->next;
1196 #if DEBUG_CHAT_SERVICE
1197 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1198 "Notifying local room members that the client has gone away\n");
1200 lnmsg.header.size = htons (sizeof (struct LeaveNotificationMessage));
1201 lnmsg.header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION);
1202 lnmsg.reserved = htonl (0);
1203 lnmsg.user = pos->public_key;
1204 entry = client_list_head;
1205 while (NULL != entry)
1207 if (0 == strcmp (pos->room, entry->room) &&
1208 (NULL != entry->client))
1210 GNUNET_SERVER_notification_context_unicast (nc,
1215 entry = entry->next;
1217 #if DEBUG_CHAT_SERVICE
1218 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1219 "Broadcasting leave notification to neighbour peers\n");
1221 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
1222 &send_leave_noficiation,
1224 GNUNET_free (pos->room);
1225 GNUNET_free_non_null (pos->member_info);
1232 * Handle P2P message notification.
1234 * @param cls closure, always NULL
1235 * @param other the other peer involved
1236 * @param message the actual message
1237 * @param atsi performance information
1238 * @return GNUNET_OK to keep the connection open,
1239 * GNUNET_SYSERR to close it (signal serious error)
1242 handle_p2p_message_notification (void *cls,
1243 const struct GNUNET_PeerIdentity *other,
1244 const struct GNUNET_MessageHeader *message,
1245 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1247 const struct P2PReceiveNotificationMessage *p2p_rnmsg;
1248 struct P2PReceiveNotificationMessage *my_p2p_rnmsg;
1249 struct ReceiveNotificationMessage *rnmsg;
1250 struct ChatClient *sender;
1251 struct ChatClient *pos;
1252 static GNUNET_HashCode all_zeros;
1256 uint16_t room_name_len;
1257 char *room_name = NULL;
1260 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P message notification\n");
1261 if (ntohs (message->size) <= sizeof (struct P2PReceiveNotificationMessage))
1263 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n");
1264 GNUNET_break_op (0);
1265 return GNUNET_SYSERR;
1267 p2p_rnmsg = (const struct P2PReceiveNotificationMessage *) message;
1268 msg_len = ntohs (p2p_rnmsg->header.size) -
1269 sizeof (struct P2PReceiveNotificationMessage);
1271 is_anon = (0 != (ntohl (p2p_rnmsg->msg_options) & GNUNET_CHAT_MSG_ANONYMOUS));
1274 room_name_len = ntohs (p2p_rnmsg->room_name_len);
1275 if (msg_len <= room_name_len)
1277 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1278 "Malformed message: wrong length of the room name\n");
1279 GNUNET_break_op (0);
1280 return GNUNET_SYSERR;
1282 msg_len -= room_name_len;
1283 if (lookup_anonymous_message (p2p_rnmsg))
1285 #if DEBUG_CHAT_SERVICE
1286 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1287 "This anonymous message has already been handled.");
1291 remember_anonymous_message (p2p_rnmsg);
1292 room_name = GNUNET_malloc (room_name_len + 1);
1293 memcpy (room_name, (char *) &p2p_rnmsg[1], room_name_len);
1294 room_name[room_name_len] = '\0';
1295 text = (char *) &p2p_rnmsg[1] + room_name_len;
1299 sender = client_list_head;
1300 while ((NULL != sender) &&
1301 (0 != memcmp (&sender->id,
1303 sizeof (GNUNET_HashCode))))
1304 sender = sender->next;
1307 /* not an error since the sender may have left before we got the
1309 #if DEBUG_CHAT_SERVICE
1310 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1311 "Unknown source. Rejecting the message\n");
1315 if (sender->msg_sequence_number >= ntohl (p2p_rnmsg->sequence_number))
1317 #if DEBUG_CHAT_SERVICE
1318 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1319 "This message has already been handled."
1320 " Sequence numbers (msg/sender): %u/%u\n",
1321 ntohl (p2p_rnmsg->sequence_number),
1322 sender->msg_sequence_number);
1326 sender->msg_sequence_number = ntohl (p2p_rnmsg->sequence_number);
1327 room_name = sender->room;
1328 text = (char *) &p2p_rnmsg[1];
1331 #if DEBUG_CHAT_SERVICE
1332 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1333 "Sending message to local room members\n");
1335 rnmsg = GNUNET_malloc (sizeof (struct ReceiveNotificationMessage) + msg_len);
1336 rnmsg->header.size = htons (sizeof (struct ReceiveNotificationMessage) +
1338 rnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION);
1339 rnmsg->msg_options = p2p_rnmsg->msg_options;
1340 rnmsg->sequence_number = p2p_rnmsg->sequence_number;
1341 rnmsg->reserved = htonl (0);
1342 rnmsg->timestamp = p2p_rnmsg->timestamp;
1343 is_priv = (0 != memcmp (&all_zeros,
1344 &p2p_rnmsg->target, sizeof (GNUNET_HashCode)));
1346 memcpy (&rnmsg->encrypted_key,
1347 &p2p_rnmsg->encrypted_key,
1348 sizeof (struct GNUNET_CRYPTO_RsaEncryptedData));
1349 rnmsg->sender = p2p_rnmsg->sender;
1350 memcpy (&rnmsg[1], text, msg_len);
1351 pos = client_list_head;
1354 if ((0 == strcmp (room_name, pos->room)) &&
1355 (NULL != pos->client))
1358 (0 == memcmp (&p2p_rnmsg->target,
1360 sizeof (GNUNET_HashCode)))) &&
1361 (0 == (ntohl (p2p_rnmsg->msg_options) & (~pos->msg_options))))
1363 GNUNET_SERVER_notification_context_unicast (nc,
1372 GNUNET_free (room_name);
1373 #if DEBUG_CHAT_SERVICE
1374 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1375 "Broadcasting message notification to neighbour peers\n");
1377 my_p2p_rnmsg = GNUNET_memdup (p2p_rnmsg, ntohs (p2p_rnmsg->header.size));
1378 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
1379 &send_message_noficiation,
1381 GNUNET_free (rnmsg);
1387 * Handle P2P sync request.
1389 * @param cls closure, always NULL
1390 * @param other the other peer involved
1391 * @param message the actual message
1392 * @param atsi performance information
1393 * @return GNUNET_OK to keep the connection open,
1394 * GNUNET_SYSERR to close it (signal serious error)
1397 handle_p2p_sync_request (void *cls,
1398 const struct GNUNET_PeerIdentity *other,
1399 const struct GNUNET_MessageHeader *message,
1400 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1402 struct ChatClient *entry;
1403 struct GNUNET_CORE_TransmitHandle *th;
1406 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P sync request\n");
1407 #if DEBUG_CHAT_SERVICE
1408 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1409 "Notifying the requester of all known clients\n");
1411 entry = client_list_head;
1412 while (NULL != entry)
1414 msg_size = sizeof (struct P2PJoinNotificationMessage) +
1415 strlen (entry->room) +
1417 th = GNUNET_CORE_notify_transmit_ready (core,
1423 &transmit_join_notification_to_peer,
1425 GNUNET_assert (NULL != th);
1426 entry = entry->next;
1433 * Handle P2P confirmation receipt.
1435 * @param cls closure, always NULL
1436 * @param other the other peer involved
1437 * @param message the actual message
1438 * @param atsi performance information
1439 * @return GNUNET_OK to keep the connection open,
1440 * GNUNET_SYSERR to close it (signal serious error)
1443 handle_p2p_confirmation_receipt (void *cls,
1444 const struct GNUNET_PeerIdentity *other,
1445 const struct GNUNET_MessageHeader *message,
1446 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1448 const struct P2PConfirmationReceiptMessage *p2p_crmsg;
1449 struct P2PConfirmationReceiptMessage *my_p2p_crmsg;
1450 struct ConfirmationReceiptMessage *crmsg;
1451 struct ChatClient *target;
1452 struct ChatClient *author;
1454 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P confirmation receipt\n");
1455 p2p_crmsg = (const struct P2PConfirmationReceiptMessage *) message;
1456 target = client_list_head;
1457 while ((NULL != target) &&
1458 (0 != memcmp (&target->id,
1460 sizeof (GNUNET_HashCode))))
1461 target = target->next;
1464 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1465 "Unknown source of the receipt. Rejecting the message\n");
1466 GNUNET_break_op (0);
1467 return GNUNET_SYSERR;
1469 if (target->rcpt_sequence_number >= ntohl (p2p_crmsg->sequence_number))
1471 #if DEBUG_CHAT_SERVICE
1472 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1473 "This receipt has already been handled."
1474 " Sequence numbers (msg/sender): %u/%u\n",
1475 ntohl (p2p_crmsg->sequence_number), target->rcpt_sequence_number);
1479 target->rcpt_sequence_number = ntohl (p2p_crmsg->sequence_number);
1480 author = client_list_head;
1481 while ((NULL != author) &&
1482 (0 != memcmp (&author->id,
1484 sizeof (GNUNET_HashCode))))
1485 author = author->next;
1488 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1489 "Unknown addressee. Rejecting the receipt\n");
1490 GNUNET_break_op (0);
1491 return GNUNET_SYSERR;
1494 if (NULL == author->client)
1496 #if DEBUG_CHAT_SERVICE
1497 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1498 "The author of the original message is not a local client."
1499 " Broadcasting receipt to neighbour peers\n");
1501 my_p2p_crmsg = GNUNET_memdup (p2p_crmsg, sizeof (struct P2PConfirmationReceiptMessage));
1502 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
1503 &send_confirmation_receipt,
1505 GNUNET_free (my_p2p_crmsg);
1509 #if DEBUG_CHAT_SERVICE
1510 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1511 "The author of the original message is a local client."
1512 " Verifying signature of the receipt\n");
1514 crmsg = GNUNET_malloc (sizeof (struct ConfirmationReceiptMessage));
1515 crmsg->header.size = htons (sizeof (struct ConfirmationReceiptMessage));
1516 crmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION);
1517 crmsg->signature = p2p_crmsg->signature;
1518 crmsg->purpose = p2p_crmsg->purpose;
1519 crmsg->sequence_number = p2p_crmsg->msg_sequence_number;
1520 crmsg->reserved2 = 0;
1521 crmsg->timestamp = p2p_crmsg->timestamp;
1522 crmsg->target = p2p_crmsg->target;
1523 crmsg->author = p2p_crmsg->author;
1524 crmsg->content = p2p_crmsg->content;
1526 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_CHAT_RECEIPT,
1529 &target->public_key))
1531 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1532 "Invalid signature of the receipt\n");
1533 GNUNET_break_op (0);
1534 return GNUNET_SYSERR;
1536 #if DEBUG_CHAT_SERVICE
1537 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1538 "The author of the original message is a local client."
1539 " Sending receipt to the client\n");
1541 GNUNET_SERVER_notification_context_unicast (nc,
1545 GNUNET_free (crmsg);
1552 * Transmit a sync request to the peer.
1554 * @param cls closure, NULL
1555 * @param size number of bytes available in buf
1556 * @param buf where the callee should write the message
1557 * @return number of bytes written to buf
1560 transmit_sync_request_to_peer (void *cls,
1564 struct GNUNET_MessageHeader *m = buf;
1567 #if DEBUG_CHAT_SERVICE
1568 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting P2P sync request\n");
1570 msg_size = sizeof (struct GNUNET_MessageHeader);
1571 GNUNET_assert (size >= msg_size);
1572 GNUNET_assert (NULL != buf);
1574 m->type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_SYNC_REQUEST);
1575 m->size = htons (msg_size);
1581 * Method called whenever a peer connects.
1583 * @param cls closure
1584 * @param peer peer identity this notification is about
1585 * @param atsi performance data
1588 peer_connect_handler (void *cls,
1589 const struct GNUNET_PeerIdentity *peer,
1590 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1592 struct ConnectedPeer *cp;
1593 struct GNUNET_CORE_TransmitHandle *th;
1595 if (0 == memcmp (peer, me, sizeof (struct GNUNET_PeerIdentity)))
1597 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1598 "Peer connected: %s\n", GNUNET_i2s (peer));
1599 th = GNUNET_CORE_notify_transmit_ready (core,
1604 sizeof (struct GNUNET_MessageHeader),
1605 &transmit_sync_request_to_peer,
1607 GNUNET_assert (NULL != th);
1608 cp = GNUNET_CONTAINER_multihashmap_get (connected_peers,
1615 cp = GNUNET_malloc (sizeof (struct ConnectedPeer));
1616 cp->pid = GNUNET_PEER_intern (peer);
1617 GNUNET_break (GNUNET_OK ==
1618 GNUNET_CONTAINER_multihashmap_put (connected_peers,
1621 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1626 * Iterator to free peer entries.
1628 * @param cls closure, unused
1629 * @param key current key code
1630 * @param value value in the hash map (peer entry)
1631 * @return GNUNET_YES (we should continue to iterate)
1634 clean_peer (void *cls,
1635 const GNUNET_HashCode * key,
1638 struct ConnectedPeer *cp;
1639 const struct GNUNET_PeerIdentity *peer = (const struct GNUNET_PeerIdentity *) key;
1641 cp = GNUNET_CONTAINER_multihashmap_get (connected_peers,
1645 GNUNET_break (GNUNET_YES ==
1646 GNUNET_CONTAINER_multihashmap_remove (connected_peers,
1649 GNUNET_PEER_change_rc (cp->pid, -1);
1656 * Method called whenever a peer disconnects.
1658 * @param cls closure, not used
1659 * @param peer peer identity this notification is about
1662 peer_disconnect_handler (void *cls,
1663 const struct GNUNET_PeerIdentity *peer)
1666 if (0 == memcmp (peer, me, sizeof (struct GNUNET_PeerIdentity)))
1668 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1669 "Peer disconnected: %s\n", GNUNET_i2s (peer));
1670 clean_peer (NULL, (const GNUNET_HashCode *) peer, NULL);
1675 * Task run during shutdown.
1681 cleanup_task (void *cls,
1682 const struct GNUNET_SCHEDULER_TaskContext *tc)
1684 struct AnonymousMessage *next_msg;
1685 struct ChatClient *next_client;
1687 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Cleaning up\n");
1690 GNUNET_CORE_disconnect (core);
1695 GNUNET_SERVER_notification_context_destroy (nc);
1698 while (NULL != client_list_head)
1700 next_client = client_list_head->next;
1701 GNUNET_free (client_list_head->room);
1702 GNUNET_free_non_null (client_list_head->member_info);
1703 GNUNET_free (client_list_head);
1704 client_list_head = next_client;
1706 while (NULL != anonymous_list_head)
1708 next_msg = anonymous_list_head->next;
1709 GNUNET_free (anonymous_list_head);
1710 anonymous_list_head = next_msg;
1712 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
1715 GNUNET_CONTAINER_multihashmap_destroy (connected_peers);
1716 connected_peers = NULL;
1721 * To be called on core init/fail.
1723 * @param cls closure, NULL
1724 * @param server handle to the server for this service
1725 * @param my_identity the public identity of this peer
1726 * @param publicKey the public key of this peer
1729 core_init (void *cls,
1730 struct GNUNET_CORE_Handle *server,
1731 const struct GNUNET_PeerIdentity *my_identity,
1732 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey)
1734 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Core initialized\n");
1740 * Process chat requests.
1742 * @param cls closure, NULL
1743 * @param server the initialized server
1744 * @param c configuration to use
1748 struct GNUNET_SERVER_Handle *server,
1749 const struct GNUNET_CONFIGURATION_Handle *c)
1751 static const struct GNUNET_SERVER_MessageHandler handlers[] =
1753 { &handle_join_request, NULL,
1754 GNUNET_MESSAGE_TYPE_CHAT_JOIN_REQUEST, 0 },
1755 { &handle_transmit_request, NULL,
1756 GNUNET_MESSAGE_TYPE_CHAT_TRANSMIT_REQUEST, 0 },
1757 { &handle_acknowledge_request, NULL,
1758 GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_RECEIPT,
1759 sizeof (struct ConfirmationReceiptMessage) },
1760 { NULL, NULL, 0, 0 }
1762 static const struct GNUNET_CORE_MessageHandler p2p_handlers[] =
1764 { &handle_p2p_join_notification,
1765 GNUNET_MESSAGE_TYPE_CHAT_P2P_JOIN_NOTIFICATION, 0 },
1766 { &handle_p2p_leave_notification,
1767 GNUNET_MESSAGE_TYPE_CHAT_P2P_LEAVE_NOTIFICATION,
1768 sizeof (struct P2PLeaveNotificationMessage) },
1769 { &handle_p2p_message_notification,
1770 GNUNET_MESSAGE_TYPE_CHAT_P2P_MESSAGE_NOTIFICATION, 0 },
1771 { &handle_p2p_sync_request,
1772 GNUNET_MESSAGE_TYPE_CHAT_P2P_SYNC_REQUEST,
1773 sizeof (struct GNUNET_MessageHeader) },
1774 { &handle_p2p_confirmation_receipt,
1775 GNUNET_MESSAGE_TYPE_CHAT_P2P_CONFIRMATION_RECEIPT,
1776 sizeof (struct P2PConfirmationReceiptMessage) },
1780 GNUNET_log_setup ("gnunet-service-chat",
1781 #if DEBUG_CHAT_SERVICE
1788 nc = GNUNET_SERVER_notification_context_create (server, 16);
1789 connected_peers = GNUNET_CONTAINER_multihashmap_create (EXPECTED_NEIGHBOUR_COUNT);
1790 GNUNET_SERVER_add_handlers (server, handlers);
1791 core = GNUNET_CORE_connect (cfg,
1795 &peer_connect_handler,
1796 &peer_disconnect_handler,
1801 GNUNET_SERVER_disconnect_notify (server,
1802 &handle_client_disconnect,
1804 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1811 * The main function for the chat service.
1813 * @param argc number of arguments from the command line
1814 * @param argv command line arguments
1815 * @return 0 ok, 1 on error
1818 main (int argc, char *const *argv)
1820 return (GNUNET_OK ==
1821 GNUNET_SERVICE_run (argc,
1824 GNUNET_SERVICE_OPTION_NONE,
1825 &run, NULL)) ? 0 : 1;
1828 /* end of gnunet-service-chat.c */