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
166 static GNUNET_HashCode hash;
167 struct AnonymousMessage *anon_msg;
168 struct AnonymousMessage *prev;
171 GNUNET_CRYPTO_hash (p2p_rnmsg, ntohs (p2p_rnmsg->header.size), &hash);
172 anon_msg = GNUNET_malloc (sizeof (struct AnonymousMessage));
173 anon_msg->hash = hash;
174 anon_msg->next = anonymous_list_head;
175 anonymous_list_head = anon_msg;
178 while ((NULL != anon_msg->next))
181 anon_msg = anon_msg->next;
184 if (anon_list_len == MAX_ANONYMOUS_MSG_LIST_LENGTH)
186 GNUNET_free (anon_msg);
194 lookup_anonymous_message (const struct P2PReceiveNotificationMessage *p2p_rnmsg)
196 static GNUNET_HashCode hash;
197 struct AnonymousMessage *anon_msg;
199 GNUNET_CRYPTO_hash (p2p_rnmsg, ntohs (p2p_rnmsg->header.size), &hash);
200 anon_msg = anonymous_list_head;
201 while ((NULL != anon_msg) &&
202 (0 != memcmp (&anon_msg->hash, &hash, sizeof (GNUNET_HashCode))))
203 anon_msg = anon_msg->next;
204 return (NULL != anon_msg);
209 * Transmit a message notification to the peer.
211 * @param cls closure, pointer to the 'struct P2PReceiveNotificationMessage'
212 * @param size number of bytes available in buf
213 * @param buf where the callee should write the message
214 * @return number of bytes written to buf
217 transmit_message_notification_to_peer (void *cls, size_t size, void *buf)
219 struct P2PReceiveNotificationMessage *my_msg = cls;
220 struct P2PReceiveNotificationMessage *m = buf;
223 #if DEBUG_CHAT_SERVICE
224 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
225 "Transmitting P2P message notification\n");
229 /* client disconnected */
230 #if DEBUG_CHAT_SERVICE
231 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
232 "Buffer is NULL, dropping the message\n");
236 msg_size = ntohs (my_msg->header.size);
237 GNUNET_assert (size >= msg_size);
238 memcpy (m, my_msg, msg_size);
239 GNUNET_free (my_msg);
245 * Ask to send a message notification to the peer.
248 send_message_noficiation (void *cls, const GNUNET_HashCode * key, void *value)
250 struct P2PReceiveNotificationMessage *msg = cls;
251 struct ConnectedPeer *cp = value;
252 struct GNUNET_PeerIdentity pid;
253 struct P2PReceiveNotificationMessage *my_msg;
255 GNUNET_PEER_resolve (cp->pid, &pid);
256 #if DEBUG_CHAT_SERVICE
257 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
258 "Sending message notification to `%s'\n", GNUNET_i2s (&pid));
260 my_msg = GNUNET_memdup (msg, ntohs (msg->header.size));
261 if (NULL == GNUNET_CORE_notify_transmit_ready (core,
266 ntohs (msg->header.size),
267 &transmit_message_notification_to_peer,
269 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
270 _("Failed to queue a message notification\n"));
276 * A client sent a chat message. Encrypt the message text if the message is
277 * private. Send the message to local room members and to all connected peers.
279 * @param cls closure, NULL
280 * @param client identification of the client
281 * @param message the actual message
284 handle_transmit_request (void *cls,
285 struct GNUNET_SERVER_Client *client,
286 const struct GNUNET_MessageHeader *message)
288 static GNUNET_HashCode all_zeros;
289 const struct TransmitRequestMessage *trmsg;
290 struct ReceiveNotificationMessage *rnmsg;
291 struct P2PReceiveNotificationMessage *p2p_rnmsg;
292 struct ChatClient *pos;
293 struct ChatClient *target;
294 struct GNUNET_CRYPTO_AesSessionKey key;
295 char encrypted_msg[MAX_MESSAGE_LENGTH];
302 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client sent a chat message\n");
303 if (ntohs (message->size) <= sizeof (struct TransmitRequestMessage))
305 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n");
307 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
310 trmsg = (const struct TransmitRequestMessage *) message;
311 msg_len = ntohs (trmsg->header.size) - sizeof (struct TransmitRequestMessage);
312 is_priv = (0 != (ntohl (trmsg->msg_options) & GNUNET_CHAT_MSG_PRIVATE));
315 #if DEBUG_CHAT_SERVICE
316 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypting the message text\n");
318 GNUNET_CRYPTO_aes_create_session_key (&key);
319 msg_len = GNUNET_CRYPTO_aes_encrypt (&trmsg[1],
323 GNUNET_CRYPTO_AesInitializationVector
324 *) INITVALUE, encrypted_msg);
327 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
328 "Could not encrypt the message text\n");
330 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
334 rnmsg = GNUNET_malloc (sizeof (struct ReceiveNotificationMessage) + msg_len);
335 rnmsg->header.size = htons (sizeof (struct ReceiveNotificationMessage) +
337 rnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION);
338 rnmsg->msg_options = trmsg->msg_options;
339 rnmsg->timestamp = trmsg->timestamp;
340 pos = client_list_head;
341 while ((NULL != pos) && (pos->client != client))
345 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
346 "The client is not a member of a chat room. Client has to "
347 "join a chat room first\n");
349 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
354 pos->msg_sequence_number = ntohl (trmsg->sequence_number);
355 is_anon = (0 != (ntohl (trmsg->msg_options) & GNUNET_CHAT_MSG_ANONYMOUS));
358 memset (&rnmsg->sender, 0, sizeof (GNUNET_HashCode));
359 rnmsg->sequence_number = 0;
363 rnmsg->sender = pos->id;
364 rnmsg->sequence_number = trmsg->sequence_number;
368 #if DEBUG_CHAT_SERVICE
369 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
370 "Encrypting the session key using the public key of '%s'\n",
371 GNUNET_h2s (&trmsg->target));
373 if (0 == memcmp (&all_zeros, &trmsg->target, sizeof (GNUNET_HashCode)))
375 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
376 "Malformed message: private, but no target\n");
378 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
382 memcpy (&rnmsg[1], encrypted_msg, msg_len);
383 target = client_list_head;
384 while ((NULL != target) &&
385 (0 != memcmp (&target->id,
386 &trmsg->target, sizeof (GNUNET_HashCode))))
387 target = target->next;
390 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
391 "Unknown target of the private message\n");
393 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
397 if (GNUNET_SYSERR == GNUNET_CRYPTO_rsa_encrypt (&key,
399 GNUNET_CRYPTO_AesSessionKey),
401 &rnmsg->encrypted_key))
403 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
404 "Could not encrypt the session key\n");
406 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
413 memcpy (&rnmsg[1], &trmsg[1], msg_len);
415 pos = client_list_head;
416 #if DEBUG_CHAT_SERVICE
417 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
418 "Sending message to local room members\n");
422 if ((0 == strcmp (room, pos->room)) &&
423 (NULL != pos->client) && (pos->client != client))
426 (0 == memcmp (&trmsg->target,
428 sizeof (GNUNET_HashCode)))) &&
429 (0 == (ntohl (trmsg->msg_options) & (~pos->msg_options))))
431 GNUNET_SERVER_notification_context_unicast (nc,
433 &rnmsg->header, GNUNET_NO);
438 #if DEBUG_CHAT_SERVICE
439 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
440 "Broadcasting message to neighbour peers\n");
444 room_len = strlen (room);
445 p2p_rnmsg = GNUNET_malloc (sizeof (struct P2PReceiveNotificationMessage) +
447 p2p_rnmsg->header.size =
448 htons (sizeof (struct P2PReceiveNotificationMessage) + msg_len +
450 p2p_rnmsg->room_name_len = htons (room_len);
451 memcpy ((char *) &p2p_rnmsg[1], room, room_len);
452 memcpy ((char *) &p2p_rnmsg[1] + room_len, &trmsg[1], msg_len);
456 p2p_rnmsg = GNUNET_malloc (sizeof (struct P2PReceiveNotificationMessage) +
458 p2p_rnmsg->header.size =
459 htons (sizeof (struct P2PReceiveNotificationMessage) + msg_len);
462 memcpy (&p2p_rnmsg[1], encrypted_msg, msg_len);
463 memcpy (&p2p_rnmsg->encrypted_key,
464 &rnmsg->encrypted_key,
465 sizeof (struct GNUNET_CRYPTO_RsaEncryptedData));
468 memcpy (&p2p_rnmsg[1], &trmsg[1], msg_len);
470 p2p_rnmsg->header.type =
471 htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_MESSAGE_NOTIFICATION);
472 p2p_rnmsg->msg_options = trmsg->msg_options;
473 p2p_rnmsg->sequence_number = trmsg->sequence_number;
474 p2p_rnmsg->timestamp = trmsg->timestamp;
475 p2p_rnmsg->reserved = htons (0);
476 p2p_rnmsg->sender = rnmsg->sender;
477 p2p_rnmsg->target = trmsg->target;
479 remember_anonymous_message (p2p_rnmsg);
480 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
481 &send_message_noficiation, p2p_rnmsg);
482 GNUNET_free (p2p_rnmsg);
483 GNUNET_SERVER_receive_done (client, GNUNET_OK);
489 * Transmit a join notification to the peer.
491 * @param cls closure, pointer to the 'struct ChatClient'
492 * @param size number of bytes available in buf
493 * @param buf where the callee should write the message
494 * @return number of bytes written to buf
497 transmit_join_notification_to_peer (void *cls, size_t size, void *buf)
499 struct ChatClient *entry = cls;
500 struct P2PJoinNotificationMessage *m = buf;
506 #if DEBUG_CHAT_SERVICE
507 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting P2P join notification\n");
509 room_len = strlen (entry->room);
510 meta_len = entry->meta_len;
511 msg_size = sizeof (struct P2PJoinNotificationMessage) + meta_len + room_len;
512 GNUNET_assert (size >= msg_size);
513 GNUNET_assert (NULL != buf);
515 m->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_JOIN_NOTIFICATION);
516 m->header.size = htons (msg_size);
517 m->msg_options = htonl (entry->msg_options);
518 m->room_name_len = htons (room_len);
519 m->reserved = htons (0);
520 m->reserved2 = htonl (0);
521 m->public_key = entry->public_key;
522 roomptr = (char *) &m[1];
523 memcpy (roomptr, entry->room, room_len);
525 memcpy (&roomptr[room_len], entry->member_info, meta_len);
531 * Ask to send a join notification to the peer.
534 send_join_noficiation (void *cls, const GNUNET_HashCode * key, void *value)
536 struct ChatClient *entry = cls;
537 struct ConnectedPeer *cp = value;
538 struct GNUNET_PeerIdentity pid;
541 GNUNET_PEER_resolve (cp->pid, &pid);
542 #if DEBUG_CHAT_SERVICE
543 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
544 "Sending join notification to `%s'\n", GNUNET_i2s (&pid));
546 msg_size = sizeof (struct P2PJoinNotificationMessage) +
547 strlen (entry->room) + entry->meta_len;
548 if (NULL == GNUNET_CORE_notify_transmit_ready (core,
554 &transmit_join_notification_to_peer,
556 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
557 _("Failed to queue a join notification\n"));
563 * A client asked for entering a chat room. Add the new member to the list of
564 * clients and notify remaining room members.
566 * @param cls closure, NULL
567 * @param client identification of the client
568 * @param message the actual message
571 handle_join_request (void *cls,
572 struct GNUNET_SERVER_Client *client,
573 const struct GNUNET_MessageHeader *message)
575 const struct JoinRequestMessage *jrmsg;
578 uint16_t header_size;
580 uint16_t room_name_len;
581 struct ChatClient *new_entry;
582 struct ChatClient *entry;
583 struct JoinNotificationMessage *jnmsg;
584 struct JoinNotificationMessage *entry_jnmsg;
586 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client sent a join request\n");
587 if (ntohs (message->size) <= sizeof (struct JoinRequestMessage))
589 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n");
591 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
594 jrmsg = (const struct JoinRequestMessage *) message;
595 header_size = ntohs (jrmsg->header.size);
596 room_name_len = ntohs (jrmsg->room_name_len);
597 if (header_size - sizeof (struct JoinRequestMessage) <= room_name_len)
599 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
600 "Malformed message: wrong length of the room name\n");
602 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
605 meta_len = header_size - sizeof (struct JoinRequestMessage) - room_name_len;
606 roomptr = (const char *) &jrmsg[1];
607 room_name = GNUNET_malloc (room_name_len + 1);
608 memcpy (room_name, roomptr, room_name_len);
609 room_name[room_name_len] = '\0';
610 new_entry = GNUNET_malloc (sizeof (struct ChatClient));
611 memset (new_entry, 0, sizeof (struct ChatClient));
612 new_entry->client = client;
613 new_entry->room = room_name;
614 new_entry->public_key = jrmsg->public_key;
615 new_entry->meta_len = meta_len;
618 new_entry->member_info = GNUNET_malloc (meta_len);
619 memcpy (new_entry->member_info, &roomptr[room_name_len], meta_len);
622 new_entry->member_info = NULL;
623 GNUNET_CRYPTO_hash (&new_entry->public_key,
624 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
626 new_entry->msg_options = ntohl (jrmsg->msg_options);
627 new_entry->next = client_list_head;
628 client_list_head = new_entry;
629 #if DEBUG_CHAT_SERVICE
630 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
631 "Synchronizing room members between local clients\n");
633 jnmsg = GNUNET_malloc (sizeof (struct JoinNotificationMessage) + meta_len);
634 jnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION);
636 htons (sizeof (struct JoinNotificationMessage) + meta_len);
637 jnmsg->msg_options = jrmsg->msg_options;
638 jnmsg->public_key = new_entry->public_key;
639 memcpy (&jnmsg[1], &roomptr[room_name_len], meta_len);
640 GNUNET_SERVER_notification_context_add (nc, client);
641 entry = client_list_head;
642 while (NULL != entry)
644 if (0 == strcmp (room_name, entry->room))
646 if (NULL != entry->client)
647 GNUNET_SERVER_notification_context_unicast (nc,
649 &jnmsg->header, GNUNET_NO);
650 if (entry->client != client)
653 GNUNET_malloc (sizeof (struct JoinNotificationMessage) +
655 entry_jnmsg->header.type =
656 htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION);
657 entry_jnmsg->header.size =
658 htons (sizeof (struct JoinNotificationMessage) + entry->meta_len);
659 entry_jnmsg->msg_options = entry->msg_options;
660 entry_jnmsg->public_key = entry->public_key;
661 memcpy (&entry_jnmsg[1], entry->member_info, entry->meta_len);
662 GNUNET_SERVER_notification_context_unicast (nc,
664 &entry_jnmsg->header,
666 GNUNET_free (entry_jnmsg);
671 #if DEBUG_CHAT_SERVICE
672 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
673 "Broadcasting join notification to neighbour peers\n");
675 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
676 &send_join_noficiation, new_entry);
677 GNUNET_SERVER_receive_done (client, GNUNET_OK);
682 * Transmit a confirmation receipt to the peer.
684 * @param cls closure, pointer to the 'struct P2PConfirmationReceiptMessage'
685 * @param size number of bytes available in buf
686 * @param buf where the callee should write the message
687 * @return number of bytes written to buf
690 transmit_confirmation_receipt_to_peer (void *cls, size_t size, void *buf)
692 struct P2PConfirmationReceiptMessage *receipt = cls;
695 #if DEBUG_CHAT_SERVICE
696 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
697 "Transmitting P2P confirmation receipt to '%s'\n",
698 GNUNET_h2s (&receipt->target));
702 /* client disconnected */
703 #if DEBUG_CHAT_SERVICE
704 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
705 "Buffer is NULL, dropping the message\n");
709 msg_size = sizeof (struct P2PConfirmationReceiptMessage);
710 GNUNET_assert (size >= msg_size);
711 memcpy (buf, receipt, msg_size);
712 GNUNET_free (receipt);
718 * Ask to send a confirmation receipt to the peer.
721 send_confirmation_receipt (void *cls, const GNUNET_HashCode * key, void *value)
723 struct P2PConfirmationReceiptMessage *receipt = cls;
724 struct ConnectedPeer *cp = value;
725 struct GNUNET_PeerIdentity pid;
726 struct P2PConfirmationReceiptMessage *my_receipt;
729 GNUNET_PEER_resolve (cp->pid, &pid);
730 #if DEBUG_CHAT_SERVICE
731 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
732 "Sending confirmation receipt to `%s'\n", GNUNET_i2s (&pid));
734 msg_size = sizeof (struct P2PConfirmationReceiptMessage);
735 my_receipt = GNUNET_memdup (receipt,
736 sizeof (struct P2PConfirmationReceiptMessage));
737 if (NULL == GNUNET_CORE_notify_transmit_ready (core,
743 &transmit_confirmation_receipt_to_peer,
745 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
746 _("Failed to queue a confirmation receipt\n"));
752 * A client sent a confirmation receipt. Broadcast the receipt to all connected
753 * peers if the author of the original message is a local client. Otherwise
754 * check the signature and notify the user if the signature is valid.
756 * @param cls closure, NULL
757 * @param client identification of the client
758 * @param message the actual message
761 handle_acknowledge_request (void *cls,
762 struct GNUNET_SERVER_Client *client,
763 const struct GNUNET_MessageHeader *message)
765 const struct ConfirmationReceiptMessage *receipt;
766 struct ConfirmationReceiptMessage *crmsg;
767 struct P2PConfirmationReceiptMessage *p2p_crmsg;
768 struct ChatClient *target;
769 struct ChatClient *author;
771 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client sent a confirmation receipt\n");
772 receipt = (const struct ConfirmationReceiptMessage *) message;
773 author = client_list_head;
774 while ((NULL != author) &&
775 (0 != memcmp (&receipt->author,
776 &author->id, sizeof (GNUNET_HashCode))))
777 author = author->next;
780 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
781 "Unknown author of the original message\n");
783 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
786 target = client_list_head;
787 while ((NULL != target) &&
788 (0 != memcmp (&receipt->target,
789 &target->id, sizeof (GNUNET_HashCode))))
790 target = target->next;
793 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
794 "Unknown target of the confirmation receipt\n");
796 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
799 if (NULL == author->client)
801 target->rcpt_sequence_number++;
802 #if DEBUG_CHAT_SERVICE
803 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
804 "Broadcasting %s's receipt #%u to neighbour peers\n",
805 GNUNET_h2s (&target->id), target->rcpt_sequence_number);
807 p2p_crmsg = GNUNET_malloc (sizeof (struct P2PConfirmationReceiptMessage));
808 p2p_crmsg->header.size =
809 htons (sizeof (struct P2PConfirmationReceiptMessage));
810 p2p_crmsg->header.type =
811 htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_CONFIRMATION_RECEIPT);
812 p2p_crmsg->reserved = htonl (0);
813 p2p_crmsg->signature = receipt->signature;
814 p2p_crmsg->purpose = receipt->purpose;
815 p2p_crmsg->msg_sequence_number = receipt->sequence_number;
816 p2p_crmsg->timestamp = receipt->timestamp;
817 p2p_crmsg->target = receipt->target;
818 p2p_crmsg->author = receipt->author;
819 p2p_crmsg->content = receipt->content;
820 p2p_crmsg->sequence_number = htonl (target->rcpt_sequence_number);
821 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
822 &send_confirmation_receipt,
824 GNUNET_free (p2p_crmsg);
828 #if DEBUG_CHAT_SERVICE
829 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
830 "Verifying signature of the receipt\n");
833 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_CHAT_RECEIPT,
835 &receipt->signature, &target->public_key))
837 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
838 "Invalid signature of the receipt\n");
840 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
843 #if DEBUG_CHAT_SERVICE
844 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
845 "Sending receipt to the client which sent the original message\n");
847 crmsg = GNUNET_memdup (receipt, sizeof (struct ConfirmationReceiptMessage));
849 htons (GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION);
850 GNUNET_SERVER_notification_context_unicast (nc, author->client,
851 &crmsg->header, GNUNET_NO);
854 GNUNET_SERVER_receive_done (client, GNUNET_OK);
859 * Transmit a leave notification to the peer.
861 * @param cls closure, pointer to the
862 * 'struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded'
863 * @param size number of bytes available in buf
864 * @param buf where the callee should write the message
865 * @return number of bytes written to buf
868 transmit_leave_notification_to_peer (void *cls, size_t size, void *buf)
870 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key = cls;
871 struct P2PLeaveNotificationMessage *m = buf;
874 #if DEBUG_CHAT_SERVICE
875 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting P2P leave notification\n");
879 /* client disconnected */
880 #if DEBUG_CHAT_SERVICE
881 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
882 "Buffer is NULL, dropping the message\n");
886 msg_size = sizeof (struct P2PLeaveNotificationMessage);
887 GNUNET_assert (size >= msg_size);
889 m->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_LEAVE_NOTIFICATION);
890 m->header.size = htons (msg_size);
891 m->reserved = htonl (0);
892 m->user = *public_key;
893 GNUNET_free (public_key);
899 * Ask to send a leave notification to the peer.
902 send_leave_noficiation (void *cls, const GNUNET_HashCode * key, void *value)
904 struct ChatClient *entry = cls;
905 struct ConnectedPeer *cp = value;
906 struct GNUNET_PeerIdentity pid;
907 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key;
910 GNUNET_PEER_resolve (cp->pid, &pid);
911 #if DEBUG_CHAT_SERVICE
912 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
913 "Sending leave notification to `%s'\n", GNUNET_i2s (&pid));
915 msg_size = sizeof (struct P2PLeaveNotificationMessage);
916 public_key = GNUNET_memdup (&entry->public_key,
918 GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
920 GNUNET_CORE_notify_transmit_ready (core, GNUNET_YES, 1,
921 MAX_TRANSMIT_DELAY, &pid, msg_size,
922 &transmit_leave_notification_to_peer,
924 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
925 _("Failed to queue a leave notification\n"));
931 * A client disconnected. Remove all of its data structure entries and notify
932 * remaining room members.
934 * @param cls closure, NULL
935 * @param client identification of the client
938 handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
940 struct ChatClient *entry;
941 struct ChatClient *pos;
942 struct ChatClient *prev;
943 struct LeaveNotificationMessage lnmsg;
945 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client disconnected\n");
946 pos = client_list_head;
948 while ((NULL != pos) && (pos->client != client))
955 #if DEBUG_CHAT_SERVICE
956 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
957 "No such client. There is nothing to do\n");
962 client_list_head = pos->next;
964 prev->next = pos->next;
965 entry = client_list_head;
966 #if DEBUG_CHAT_SERVICE
967 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
968 "Notifying local room members that the client has disconnected\n");
970 lnmsg.header.size = htons (sizeof (struct LeaveNotificationMessage));
971 lnmsg.header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION);
972 lnmsg.reserved = htonl (0);
973 lnmsg.user = pos->public_key;
974 while (NULL != entry)
976 if ((0 == strcmp (pos->room, entry->room)) && (NULL != entry->client))
978 GNUNET_SERVER_notification_context_unicast (nc,
980 &lnmsg.header, GNUNET_NO);
984 #if DEBUG_CHAT_SERVICE
985 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
986 "Broadcasting leave notification to neighbour peers\n");
988 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
989 &send_leave_noficiation, pos);
990 GNUNET_free (pos->room);
991 GNUNET_free_non_null (pos->member_info);
997 * Handle P2P join notification.
999 * @param cls closure, always NULL
1000 * @param other the other peer involved
1001 * @param message the actual message
1002 * @param atsi performance information
1003 * @return GNUNET_OK to keep the connection open,
1004 * GNUNET_SYSERR to close it (signal serious error)
1007 handle_p2p_join_notification (void *cls,
1008 const struct GNUNET_PeerIdentity *other,
1009 const struct GNUNET_MessageHeader *message,
1010 const struct GNUNET_TRANSPORT_ATS_Information
1013 const struct P2PJoinNotificationMessage *p2p_jnmsg;
1015 const char *roomptr;
1016 uint16_t header_size;
1018 uint16_t room_name_len;
1019 struct ChatClient *new_entry;
1020 struct ChatClient *entry;
1021 struct JoinNotificationMessage *jnmsg;
1024 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P join notification\n");
1025 if (ntohs (message->size) <= sizeof (struct P2PJoinNotificationMessage))
1027 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n");
1028 GNUNET_break_op (0);
1029 return GNUNET_SYSERR;
1031 p2p_jnmsg = (const struct P2PJoinNotificationMessage *) message;
1032 header_size = ntohs (p2p_jnmsg->header.size);
1033 room_name_len = ntohs (p2p_jnmsg->room_name_len);
1034 if (header_size - sizeof (struct P2PJoinNotificationMessage) <= room_name_len)
1036 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1037 "Malformed message: wrong length of the room name\n");
1038 GNUNET_break_op (0);
1039 return GNUNET_SYSERR;
1041 GNUNET_CRYPTO_hash (&p2p_jnmsg->public_key,
1042 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1044 entry = client_list_head;
1045 while (NULL != entry)
1047 if (0 == memcmp (&entry->id, &id, sizeof (GNUNET_HashCode)))
1049 #if DEBUG_CHAT_SERVICE
1050 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1051 "The client has already joined. There is nothing to do\n");
1055 entry = entry->next;
1058 header_size - sizeof (struct P2PJoinNotificationMessage) - room_name_len;
1059 roomptr = (const char *) &p2p_jnmsg[1];
1060 room_name = GNUNET_malloc (room_name_len + 1);
1061 memcpy (room_name, roomptr, room_name_len);
1062 room_name[room_name_len] = '\0';
1063 new_entry = GNUNET_malloc (sizeof (struct ChatClient));
1064 memset (new_entry, 0, sizeof (struct ChatClient));
1066 new_entry->client = NULL;
1067 new_entry->room = room_name;
1068 new_entry->public_key = p2p_jnmsg->public_key;
1069 new_entry->meta_len = meta_len;
1072 new_entry->member_info = GNUNET_malloc (meta_len);
1073 memcpy (new_entry->member_info, &roomptr[room_name_len], meta_len);
1076 new_entry->member_info = NULL;
1077 new_entry->msg_options = ntohl (p2p_jnmsg->msg_options);
1078 new_entry->next = client_list_head;
1079 client_list_head = new_entry;
1080 #if DEBUG_CHAT_SERVICE
1081 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1082 "Notifying local room members that we have a new client\n");
1084 jnmsg = GNUNET_malloc (sizeof (struct JoinNotificationMessage) + meta_len);
1085 jnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION);
1086 jnmsg->header.size =
1087 htons (sizeof (struct JoinNotificationMessage) + meta_len);
1088 jnmsg->msg_options = p2p_jnmsg->msg_options;
1089 jnmsg->public_key = new_entry->public_key;
1090 memcpy (&jnmsg[1], &roomptr[room_name_len], meta_len);
1091 entry = client_list_head;
1092 while (NULL != entry)
1094 if ((0 == strcmp (room_name, entry->room)) && (NULL != entry->client))
1096 GNUNET_SERVER_notification_context_unicast (nc,
1098 &jnmsg->header, GNUNET_NO);
1100 entry = entry->next;
1102 #if DEBUG_CHAT_SERVICE
1103 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1104 "Broadcasting join notification to neighbour peers\n");
1106 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
1107 &send_join_noficiation, new_entry);
1108 GNUNET_free (jnmsg);
1114 * Handle P2P leave notification.
1116 * @param cls closure, always NULL
1117 * @param other the other peer involved
1118 * @param message the actual message
1119 * @param atsi performance information
1120 * @return GNUNET_OK to keep the connection open,
1121 * GNUNET_SYSERR to close it (signal serious error)
1124 handle_p2p_leave_notification (void *cls,
1125 const struct GNUNET_PeerIdentity *other,
1126 const struct GNUNET_MessageHeader *message,
1127 const struct GNUNET_TRANSPORT_ATS_Information
1130 const struct P2PLeaveNotificationMessage *p2p_lnmsg;
1132 struct ChatClient *pos;
1133 struct ChatClient *prev;
1134 struct ChatClient *entry;
1135 struct LeaveNotificationMessage lnmsg;
1137 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P leave notification\n");
1138 p2p_lnmsg = (const struct P2PLeaveNotificationMessage *) message;
1139 GNUNET_CRYPTO_hash (&p2p_lnmsg->user,
1140 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1142 pos = client_list_head;
1146 if (0 == memcmp (&pos->id, &id, sizeof (GNUNET_HashCode)))
1153 #if DEBUG_CHAT_SERVICE
1154 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1155 "No such client. There is nothing to do\n");
1160 client_list_head = pos->next;
1162 prev->next = pos->next;
1163 #if DEBUG_CHAT_SERVICE
1164 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1165 "Notifying local room members that the client has gone away\n");
1167 lnmsg.header.size = htons (sizeof (struct LeaveNotificationMessage));
1168 lnmsg.header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION);
1169 lnmsg.reserved = htonl (0);
1170 lnmsg.user = pos->public_key;
1171 entry = client_list_head;
1172 while (NULL != entry)
1174 if (0 == strcmp (pos->room, entry->room) && (NULL != entry->client))
1176 GNUNET_SERVER_notification_context_unicast (nc,
1178 &lnmsg.header, GNUNET_NO);
1180 entry = entry->next;
1182 #if DEBUG_CHAT_SERVICE
1183 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1184 "Broadcasting leave notification to neighbour peers\n");
1186 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
1187 &send_leave_noficiation, pos);
1188 GNUNET_free (pos->room);
1189 GNUNET_free_non_null (pos->member_info);
1196 * Handle P2P message notification.
1198 * @param cls closure, always NULL
1199 * @param other the other peer involved
1200 * @param message the actual message
1201 * @param atsi performance information
1202 * @return GNUNET_OK to keep the connection open,
1203 * GNUNET_SYSERR to close it (signal serious error)
1206 handle_p2p_message_notification (void *cls,
1207 const struct GNUNET_PeerIdentity *other,
1208 const struct GNUNET_MessageHeader *message,
1209 const struct GNUNET_TRANSPORT_ATS_Information
1212 const struct P2PReceiveNotificationMessage *p2p_rnmsg;
1213 struct P2PReceiveNotificationMessage *my_p2p_rnmsg;
1214 struct ReceiveNotificationMessage *rnmsg;
1215 struct ChatClient *sender;
1216 struct ChatClient *pos;
1217 static GNUNET_HashCode all_zeros;
1221 uint16_t room_name_len;
1222 char *room_name = NULL;
1225 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P message notification\n");
1226 if (ntohs (message->size) <= sizeof (struct P2PReceiveNotificationMessage))
1228 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n");
1229 GNUNET_break_op (0);
1230 return GNUNET_SYSERR;
1232 p2p_rnmsg = (const struct P2PReceiveNotificationMessage *) message;
1233 msg_len = ntohs (p2p_rnmsg->header.size) -
1234 sizeof (struct P2PReceiveNotificationMessage);
1236 is_anon = (0 != (ntohl (p2p_rnmsg->msg_options) & GNUNET_CHAT_MSG_ANONYMOUS));
1239 room_name_len = ntohs (p2p_rnmsg->room_name_len);
1240 if (msg_len <= room_name_len)
1242 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1243 "Malformed message: wrong length of the room name\n");
1244 GNUNET_break_op (0);
1245 return GNUNET_SYSERR;
1247 msg_len -= room_name_len;
1248 if (lookup_anonymous_message (p2p_rnmsg))
1250 #if DEBUG_CHAT_SERVICE
1251 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1252 "This anonymous message has already been handled.");
1256 remember_anonymous_message (p2p_rnmsg);
1257 room_name = GNUNET_malloc (room_name_len + 1);
1258 memcpy (room_name, (char *) &p2p_rnmsg[1], room_name_len);
1259 room_name[room_name_len] = '\0';
1260 text = (char *) &p2p_rnmsg[1] + room_name_len;
1264 sender = client_list_head;
1265 while ((NULL != sender) &&
1266 (0 != memcmp (&sender->id,
1267 &p2p_rnmsg->sender, sizeof (GNUNET_HashCode))))
1268 sender = sender->next;
1271 /* not an error since the sender may have left before we got the
1273 #if DEBUG_CHAT_SERVICE
1274 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1275 "Unknown source. Rejecting the message\n");
1279 if (sender->msg_sequence_number >= ntohl (p2p_rnmsg->sequence_number))
1281 #if DEBUG_CHAT_SERVICE
1282 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1283 "This message has already been handled."
1284 " Sequence numbers (msg/sender): %u/%u\n",
1285 ntohl (p2p_rnmsg->sequence_number),
1286 sender->msg_sequence_number);
1290 sender->msg_sequence_number = ntohl (p2p_rnmsg->sequence_number);
1291 room_name = sender->room;
1292 text = (char *) &p2p_rnmsg[1];
1295 #if DEBUG_CHAT_SERVICE
1296 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1297 "Sending message to local room members\n");
1299 rnmsg = GNUNET_malloc (sizeof (struct ReceiveNotificationMessage) + msg_len);
1300 rnmsg->header.size = htons (sizeof (struct ReceiveNotificationMessage) +
1302 rnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION);
1303 rnmsg->msg_options = p2p_rnmsg->msg_options;
1304 rnmsg->sequence_number = p2p_rnmsg->sequence_number;
1305 rnmsg->reserved = htonl (0);
1306 rnmsg->timestamp = p2p_rnmsg->timestamp;
1307 is_priv = (0 != memcmp (&all_zeros,
1308 &p2p_rnmsg->target, sizeof (GNUNET_HashCode)));
1310 memcpy (&rnmsg->encrypted_key,
1311 &p2p_rnmsg->encrypted_key,
1312 sizeof (struct GNUNET_CRYPTO_RsaEncryptedData));
1313 rnmsg->sender = p2p_rnmsg->sender;
1314 memcpy (&rnmsg[1], text, msg_len);
1315 pos = client_list_head;
1318 if ((0 == strcmp (room_name, pos->room)) && (NULL != pos->client))
1321 (0 == memcmp (&p2p_rnmsg->target,
1323 sizeof (GNUNET_HashCode)))) &&
1324 (0 == (ntohl (p2p_rnmsg->msg_options) & (~pos->msg_options))))
1326 GNUNET_SERVER_notification_context_unicast (nc,
1328 &rnmsg->header, GNUNET_NO);
1334 GNUNET_free (room_name);
1335 #if DEBUG_CHAT_SERVICE
1336 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1337 "Broadcasting message notification to neighbour peers\n");
1339 my_p2p_rnmsg = GNUNET_memdup (p2p_rnmsg, ntohs (p2p_rnmsg->header.size));
1340 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
1341 &send_message_noficiation,
1343 GNUNET_free (rnmsg);
1349 * Handle P2P sync request.
1351 * @param cls closure, always NULL
1352 * @param other the other peer involved
1353 * @param message the actual message
1354 * @param atsi performance information
1355 * @return GNUNET_OK to keep the connection open,
1356 * GNUNET_SYSERR to close it (signal serious error)
1359 handle_p2p_sync_request (void *cls,
1360 const struct GNUNET_PeerIdentity *other,
1361 const struct GNUNET_MessageHeader *message,
1362 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1364 struct ChatClient *entry;
1365 struct GNUNET_CORE_TransmitHandle *th;
1368 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P sync request\n");
1369 #if DEBUG_CHAT_SERVICE
1370 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1371 "Notifying the requester of all known clients\n");
1373 entry = client_list_head;
1374 while (NULL != entry)
1376 msg_size = sizeof (struct P2PJoinNotificationMessage) +
1377 strlen (entry->room) + entry->meta_len;
1378 th = GNUNET_CORE_notify_transmit_ready (core,
1384 &transmit_join_notification_to_peer,
1386 GNUNET_assert (NULL != th);
1387 entry = entry->next;
1394 * Handle P2P confirmation receipt.
1396 * @param cls closure, always NULL
1397 * @param other the other peer involved
1398 * @param message the actual message
1399 * @param atsi performance information
1400 * @return GNUNET_OK to keep the connection open,
1401 * GNUNET_SYSERR to close it (signal serious error)
1404 handle_p2p_confirmation_receipt (void *cls,
1405 const struct GNUNET_PeerIdentity *other,
1406 const struct GNUNET_MessageHeader *message,
1407 const struct GNUNET_TRANSPORT_ATS_Information
1410 const struct P2PConfirmationReceiptMessage *p2p_crmsg;
1411 struct P2PConfirmationReceiptMessage *my_p2p_crmsg;
1412 struct ConfirmationReceiptMessage *crmsg;
1413 struct ChatClient *target;
1414 struct ChatClient *author;
1416 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P confirmation receipt\n");
1417 p2p_crmsg = (const struct P2PConfirmationReceiptMessage *) message;
1418 target = client_list_head;
1419 while ((NULL != target) &&
1420 (0 != memcmp (&target->id,
1421 &p2p_crmsg->target, sizeof (GNUNET_HashCode))))
1422 target = target->next;
1425 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1426 "Unknown source of the receipt. Rejecting the message\n");
1427 GNUNET_break_op (0);
1428 return GNUNET_SYSERR;
1430 if (target->rcpt_sequence_number >= ntohl (p2p_crmsg->sequence_number))
1432 #if DEBUG_CHAT_SERVICE
1433 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1434 "This receipt has already been handled."
1435 " Sequence numbers (msg/sender): %u/%u\n",
1436 ntohl (p2p_crmsg->sequence_number),
1437 target->rcpt_sequence_number);
1441 target->rcpt_sequence_number = ntohl (p2p_crmsg->sequence_number);
1442 author = client_list_head;
1443 while ((NULL != author) &&
1444 (0 != memcmp (&author->id,
1445 &p2p_crmsg->author, sizeof (GNUNET_HashCode))))
1446 author = author->next;
1449 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1450 "Unknown addressee. Rejecting the receipt\n");
1451 GNUNET_break_op (0);
1452 return GNUNET_SYSERR;
1455 if (NULL == author->client)
1457 #if DEBUG_CHAT_SERVICE
1458 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1459 "The author of the original message is not a local client."
1460 " Broadcasting receipt to neighbour peers\n");
1463 GNUNET_memdup (p2p_crmsg,
1464 sizeof (struct P2PConfirmationReceiptMessage));
1465 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
1466 &send_confirmation_receipt,
1468 GNUNET_free (my_p2p_crmsg);
1472 #if DEBUG_CHAT_SERVICE
1473 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1474 "The author of the original message is a local client."
1475 " Verifying signature of the receipt\n");
1477 crmsg = GNUNET_malloc (sizeof (struct ConfirmationReceiptMessage));
1478 crmsg->header.size = htons (sizeof (struct ConfirmationReceiptMessage));
1479 crmsg->header.type =
1480 htons (GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION);
1481 crmsg->signature = p2p_crmsg->signature;
1482 crmsg->purpose = p2p_crmsg->purpose;
1483 crmsg->sequence_number = p2p_crmsg->msg_sequence_number;
1484 crmsg->reserved2 = 0;
1485 crmsg->timestamp = p2p_crmsg->timestamp;
1486 crmsg->target = p2p_crmsg->target;
1487 crmsg->author = p2p_crmsg->author;
1488 crmsg->content = p2p_crmsg->content;
1490 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_CHAT_RECEIPT,
1492 &crmsg->signature, &target->public_key))
1494 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1495 "Invalid signature of the receipt\n");
1496 GNUNET_break_op (0);
1497 return GNUNET_SYSERR;
1499 #if DEBUG_CHAT_SERVICE
1500 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1501 "The author of the original message is a local client."
1502 " Sending receipt to the client\n");
1504 GNUNET_SERVER_notification_context_unicast (nc,
1506 &crmsg->header, GNUNET_NO);
1507 GNUNET_free (crmsg);
1514 * Transmit a sync request to the peer.
1516 * @param cls closure, NULL
1517 * @param size number of bytes available in buf
1518 * @param buf where the callee should write the message
1519 * @return number of bytes written to buf
1522 transmit_sync_request_to_peer (void *cls, size_t size, void *buf)
1524 struct GNUNET_MessageHeader *m = buf;
1527 #if DEBUG_CHAT_SERVICE
1528 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting P2P sync request\n");
1530 msg_size = sizeof (struct GNUNET_MessageHeader);
1531 GNUNET_assert (size >= msg_size);
1532 GNUNET_assert (NULL != buf);
1534 m->type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_SYNC_REQUEST);
1535 m->size = htons (msg_size);
1541 * Method called whenever a peer connects.
1543 * @param cls closure
1544 * @param peer peer identity this notification is about
1545 * @param atsi performance data
1548 peer_connect_handler (void *cls,
1549 const struct GNUNET_PeerIdentity *peer,
1550 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1552 struct ConnectedPeer *cp;
1553 struct GNUNET_CORE_TransmitHandle *th;
1555 if (0 == memcmp (peer, me, sizeof (struct GNUNET_PeerIdentity)))
1557 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1558 "Peer connected: %s\n", GNUNET_i2s (peer));
1559 th = GNUNET_CORE_notify_transmit_ready (core,
1564 sizeof (struct GNUNET_MessageHeader),
1565 &transmit_sync_request_to_peer, NULL);
1566 GNUNET_assert (NULL != th);
1567 cp = GNUNET_CONTAINER_multihashmap_get (connected_peers, &peer->hashPubKey);
1573 cp = GNUNET_malloc (sizeof (struct ConnectedPeer));
1574 cp->pid = GNUNET_PEER_intern (peer);
1575 GNUNET_break (GNUNET_OK ==
1576 GNUNET_CONTAINER_multihashmap_put (connected_peers,
1579 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1584 * Iterator to free peer entries.
1586 * @param cls closure, unused
1587 * @param key current key code
1588 * @param value value in the hash map (peer entry)
1589 * @return GNUNET_YES (we should continue to iterate)
1592 clean_peer (void *cls, const GNUNET_HashCode * key, void *value)
1594 struct ConnectedPeer *cp;
1595 const struct GNUNET_PeerIdentity *peer =
1596 (const struct GNUNET_PeerIdentity *) key;
1598 cp = GNUNET_CONTAINER_multihashmap_get (connected_peers, &peer->hashPubKey);
1601 GNUNET_break (GNUNET_YES ==
1602 GNUNET_CONTAINER_multihashmap_remove (connected_peers,
1603 &peer->hashPubKey, cp));
1604 GNUNET_PEER_change_rc (cp->pid, -1);
1611 * Method called whenever a peer disconnects.
1613 * @param cls closure, not used
1614 * @param peer peer identity this notification is about
1617 peer_disconnect_handler (void *cls, const struct GNUNET_PeerIdentity *peer)
1620 if (0 == memcmp (peer, me, sizeof (struct GNUNET_PeerIdentity)))
1622 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1623 "Peer disconnected: %s\n", GNUNET_i2s (peer));
1624 clean_peer (NULL, (const GNUNET_HashCode *) peer, NULL);
1629 * Task run during shutdown.
1635 cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1637 struct AnonymousMessage *next_msg;
1638 struct ChatClient *next_client;
1640 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Cleaning up\n");
1643 GNUNET_CORE_disconnect (core);
1648 GNUNET_SERVER_notification_context_destroy (nc);
1651 while (NULL != client_list_head)
1653 next_client = client_list_head->next;
1654 GNUNET_free (client_list_head->room);
1655 GNUNET_free_non_null (client_list_head->member_info);
1656 GNUNET_free (client_list_head);
1657 client_list_head = next_client;
1659 while (NULL != anonymous_list_head)
1661 next_msg = anonymous_list_head->next;
1662 GNUNET_free (anonymous_list_head);
1663 anonymous_list_head = next_msg;
1665 GNUNET_CONTAINER_multihashmap_iterate (connected_peers, &clean_peer, NULL);
1666 GNUNET_CONTAINER_multihashmap_destroy (connected_peers);
1667 connected_peers = NULL;
1672 * To be called on core init/fail.
1674 * @param cls closure, NULL
1675 * @param server handle to the server for this service
1676 * @param my_identity the public identity of this peer
1677 * @param publicKey the public key of this peer
1680 core_init (void *cls,
1681 struct GNUNET_CORE_Handle *server,
1682 const struct GNUNET_PeerIdentity *my_identity,
1683 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey)
1685 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Core initialized\n");
1691 * Process chat requests.
1693 * @param cls closure, NULL
1694 * @param server the initialized server
1695 * @param c configuration to use
1699 struct GNUNET_SERVER_Handle *server,
1700 const struct GNUNET_CONFIGURATION_Handle *c)
1702 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1703 {&handle_join_request, NULL,
1704 GNUNET_MESSAGE_TYPE_CHAT_JOIN_REQUEST, 0},
1705 {&handle_transmit_request, NULL,
1706 GNUNET_MESSAGE_TYPE_CHAT_TRANSMIT_REQUEST, 0},
1707 {&handle_acknowledge_request, NULL,
1708 GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_RECEIPT,
1709 sizeof (struct ConfirmationReceiptMessage)},
1712 static const struct GNUNET_CORE_MessageHandler p2p_handlers[] = {
1713 {&handle_p2p_join_notification,
1714 GNUNET_MESSAGE_TYPE_CHAT_P2P_JOIN_NOTIFICATION, 0},
1715 {&handle_p2p_leave_notification,
1716 GNUNET_MESSAGE_TYPE_CHAT_P2P_LEAVE_NOTIFICATION,
1717 sizeof (struct P2PLeaveNotificationMessage)},
1718 {&handle_p2p_message_notification,
1719 GNUNET_MESSAGE_TYPE_CHAT_P2P_MESSAGE_NOTIFICATION, 0},
1720 {&handle_p2p_sync_request,
1721 GNUNET_MESSAGE_TYPE_CHAT_P2P_SYNC_REQUEST,
1722 sizeof (struct GNUNET_MessageHeader)},
1723 {&handle_p2p_confirmation_receipt,
1724 GNUNET_MESSAGE_TYPE_CHAT_P2P_CONFIRMATION_RECEIPT,
1725 sizeof (struct P2PConfirmationReceiptMessage)},
1729 GNUNET_log_setup ("gnunet-service-chat",
1730 #if DEBUG_CHAT_SERVICE
1737 nc = GNUNET_SERVER_notification_context_create (server, 16);
1739 GNUNET_CONTAINER_multihashmap_create (EXPECTED_NEIGHBOUR_COUNT);
1740 GNUNET_SERVER_add_handlers (server, handlers);
1741 core = GNUNET_CORE_connect (cfg,
1745 &peer_connect_handler,
1746 &peer_disconnect_handler,
1748 NULL, GNUNET_NO, NULL, GNUNET_NO, p2p_handlers);
1749 GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
1750 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1751 &cleanup_task, NULL);
1756 * The main function for the chat service.
1758 * @param argc number of arguments from the command line
1759 * @param argv command line arguments
1760 * @return 0 ok, 1 on error
1763 main (int argc, char *const *argv)
1765 return (GNUNET_OK ==
1766 GNUNET_SERVICE_run (argc,
1769 GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
1772 /* end of gnunet-service-chat.c */