2 This file is part of GNUnet.
3 (C) 2009, 2011 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file chat/gnunet-service-chat.c
23 * @brief service providing chat functionality
24 * @author Christian Grothoff
25 * @author Vitaly Minko
29 #include "gnunet_core_service.h"
30 #include "gnunet_crypto_lib.h"
31 #include "gnunet_protocols.h"
32 #include "gnunet_service_lib.h"
33 #include "gnunet_signatures.h"
36 #define DEBUG_CHAT_SERVICE GNUNET_EXTRA_LOGGING
37 #define MAX_TRANSMIT_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
38 #define EXPECTED_NEIGHBOUR_COUNT 16
39 #define MAX_ANONYMOUS_MSG_LIST_LENGTH 16
43 * Linked list of our current clients.
47 struct ChatClient *next;
50 * Handle for a chat client (NULL for external clients).
52 struct GNUNET_SERVER_Client *client;
55 * Public key of the client.
57 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key;
60 * Name of the room which the client is in.
65 * Serialized metadata of the client.
70 * Hash of the public key (for convenience).
72 struct GNUNET_HashCode id;
75 * Options which the client is willing to receive.
80 * Length of serialized metadata in member_info.
85 * Sequence number of the last message sent by the client.
87 uint32_t msg_sequence_number;
90 * Sequence number of the last receipt sent by the client.
91 * Used to discard already processed receipts.
93 uint32_t rcpt_sequence_number;
98 * Information about a peer that we are connected to.
99 * We track data that is useful for determining which
100 * peers should receive our requests.
105 * The peer's identity.
111 * Linked list of recent anonymous messages.
113 struct AnonymousMessage
115 struct AnonymousMessage *next;
118 * Hash of the message.
120 struct GNUNET_HashCode hash;
126 * Handle to the core service (NULL until we've connected to it).
128 static struct GNUNET_CORE_Handle *core;
133 static const struct GNUNET_CONFIGURATION_Handle *cfg;
136 * The identity of this host.
138 static struct GNUNET_PeerIdentity me;
141 * Head of the list of current clients.
143 static struct ChatClient *client_list_head = NULL;
146 * Notification context containing all connected clients.
148 struct GNUNET_SERVER_NotificationContext *nc = NULL;
151 * Head of the list of recent anonymous messages.
153 static struct AnonymousMessage *anonymous_list_head = NULL;
156 * Map of peer identifiers to "struct ConnectedPeer" (for that peer).
158 static struct GNUNET_CONTAINER_MultiHashMap *connected_peers;
162 remember_anonymous_message (const struct P2PReceiveNotificationMessage
165 static struct 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 struct 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 (struct 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, size_t size, void *buf)
218 struct P2PReceiveNotificationMessage *my_msg = cls;
219 struct P2PReceiveNotificationMessage *m = buf;
222 #if DEBUG_CHAT_SERVICE
223 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
224 "Transmitting P2P message notification\n");
228 /* client disconnected */
229 #if DEBUG_CHAT_SERVICE
230 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
231 "Buffer is NULL, dropping the message\n");
235 msg_size = ntohs (my_msg->header.size);
236 GNUNET_assert (size >= msg_size);
237 memcpy (m, my_msg, msg_size);
238 GNUNET_free (my_msg);
244 * Ask to send a message notification to the peer.
247 send_message_noficiation (void *cls, const struct GNUNET_HashCode * key, void *value)
249 struct P2PReceiveNotificationMessage *msg = cls;
250 struct ConnectedPeer *cp = value;
251 struct GNUNET_PeerIdentity pid;
252 struct P2PReceiveNotificationMessage *my_msg;
254 GNUNET_PEER_resolve (cp->pid, &pid);
255 #if DEBUG_CHAT_SERVICE
256 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message notification to `%s'\n",
259 my_msg = GNUNET_memdup (msg, ntohs (msg->header.size));
261 GNUNET_CORE_notify_transmit_ready (core, GNUNET_NO, 1, MAX_TRANSMIT_DELAY,
262 &pid, ntohs (msg->header.size),
263 &transmit_message_notification_to_peer,
265 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
266 _("Failed to queue a message notification\n"));
272 * A client sent a chat message. Encrypt the message text if the message is
273 * private. Send the message to local room members and to all connected peers.
275 * @param cls closure, NULL
276 * @param client identification of the client
277 * @param message the actual message
280 handle_transmit_request (void *cls, struct GNUNET_SERVER_Client *client,
281 const struct GNUNET_MessageHeader *message)
283 static struct GNUNET_HashCode all_zeros;
284 const struct TransmitRequestMessage *trmsg;
285 struct ReceiveNotificationMessage *rnmsg;
286 struct P2PReceiveNotificationMessage *p2p_rnmsg;
287 struct ChatClient *pos;
288 struct ChatClient *target;
289 struct GNUNET_CRYPTO_AesSessionKey key;
290 char encrypted_msg[MAX_MESSAGE_LENGTH];
297 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client sent a chat message\n");
298 if (ntohs (message->size) <= sizeof (struct TransmitRequestMessage))
300 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n");
302 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
305 trmsg = (const struct TransmitRequestMessage *) message;
306 msg_len = ntohs (trmsg->header.size) - sizeof (struct TransmitRequestMessage);
307 is_priv = (0 != (ntohl (trmsg->msg_options) & GNUNET_CHAT_MSG_PRIVATE));
310 #if DEBUG_CHAT_SERVICE
311 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypting the message text\n");
313 GNUNET_CRYPTO_aes_create_session_key (&key);
315 GNUNET_CRYPTO_aes_encrypt (&trmsg[1], msg_len, &key,
317 GNUNET_CRYPTO_AesInitializationVector *)
318 INITVALUE, encrypted_msg);
321 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
322 "Could not encrypt the message text\n");
324 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
328 rnmsg = GNUNET_malloc (sizeof (struct ReceiveNotificationMessage) + msg_len);
330 htons (sizeof (struct ReceiveNotificationMessage) + msg_len);
331 rnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION);
332 rnmsg->msg_options = trmsg->msg_options;
333 rnmsg->timestamp = trmsg->timestamp;
334 pos = client_list_head;
335 while ((NULL != pos) && (pos->client != client))
339 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
340 "The client is not a member of a chat room. Client has to "
341 "join a chat room first\n");
343 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
348 pos->msg_sequence_number = ntohl (trmsg->sequence_number);
349 is_anon = (0 != (ntohl (trmsg->msg_options) & GNUNET_CHAT_MSG_ANONYMOUS));
352 memset (&rnmsg->sender, 0, sizeof (struct GNUNET_HashCode));
353 rnmsg->sequence_number = 0;
357 rnmsg->sender = pos->id;
358 rnmsg->sequence_number = trmsg->sequence_number;
362 #if DEBUG_CHAT_SERVICE
363 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
364 "Encrypting the session key using the public key of '%s'\n",
365 GNUNET_h2s (&trmsg->target));
367 if (0 == memcmp (&all_zeros, &trmsg->target, sizeof (struct GNUNET_HashCode)))
369 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
370 "Malformed message: private, but no target\n");
372 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
376 memcpy (&rnmsg[1], encrypted_msg, msg_len);
377 target = client_list_head;
378 while ((NULL != target) &&
380 memcmp (&target->id, &trmsg->target, sizeof (struct GNUNET_HashCode))))
381 target = target->next;
384 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
385 "Unknown target of the private message\n");
387 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
392 GNUNET_CRYPTO_rsa_encrypt (&key,
393 sizeof (struct GNUNET_CRYPTO_AesSessionKey),
394 &target->public_key, &rnmsg->encrypted_key))
396 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
397 "Could not encrypt the session key\n");
399 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
406 memcpy (&rnmsg[1], &trmsg[1], msg_len);
408 pos = client_list_head;
409 #if DEBUG_CHAT_SERVICE
410 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
411 "Sending message to local room members\n");
415 if ((0 == strcmp (room, pos->room)) && (NULL != pos->client) &&
416 (pos->client != client))
419 (0 == memcmp (&trmsg->target, &pos->id, sizeof (struct GNUNET_HashCode))))
420 && (0 == (ntohl (trmsg->msg_options) & (~pos->msg_options))))
422 GNUNET_SERVER_notification_context_unicast (nc, pos->client,
423 &rnmsg->header, GNUNET_NO);
428 #if DEBUG_CHAT_SERVICE
429 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
430 "Broadcasting message to neighbour peers\n");
434 room_len = strlen (room);
436 GNUNET_malloc (sizeof (struct P2PReceiveNotificationMessage) + msg_len +
438 p2p_rnmsg->header.size =
439 htons (sizeof (struct P2PReceiveNotificationMessage) + msg_len +
441 p2p_rnmsg->room_name_len = htons (room_len);
442 memcpy ((char *) &p2p_rnmsg[1], room, room_len);
443 memcpy ((char *) &p2p_rnmsg[1] + room_len, &trmsg[1], msg_len);
448 GNUNET_malloc (sizeof (struct P2PReceiveNotificationMessage) + msg_len);
449 p2p_rnmsg->header.size =
450 htons (sizeof (struct P2PReceiveNotificationMessage) + msg_len);
453 memcpy (&p2p_rnmsg[1], encrypted_msg, msg_len);
454 memcpy (&p2p_rnmsg->encrypted_key, &rnmsg->encrypted_key,
455 sizeof (struct GNUNET_CRYPTO_RsaEncryptedData));
458 memcpy (&p2p_rnmsg[1], &trmsg[1], msg_len);
460 p2p_rnmsg->header.type =
461 htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_MESSAGE_NOTIFICATION);
462 p2p_rnmsg->msg_options = trmsg->msg_options;
463 p2p_rnmsg->sequence_number = trmsg->sequence_number;
464 p2p_rnmsg->timestamp = trmsg->timestamp;
465 p2p_rnmsg->reserved = htons (0);
466 p2p_rnmsg->sender = rnmsg->sender;
467 p2p_rnmsg->target = trmsg->target;
469 remember_anonymous_message (p2p_rnmsg);
470 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
471 &send_message_noficiation, p2p_rnmsg);
472 GNUNET_free (p2p_rnmsg);
473 GNUNET_SERVER_receive_done (client, GNUNET_OK);
479 * Transmit a join notification to the peer.
481 * @param cls closure, pointer to the 'struct ChatClient'
482 * @param size number of bytes available in buf
483 * @param buf where the callee should write the message
484 * @return number of bytes written to buf
487 transmit_join_notification_to_peer (void *cls, size_t size, void *buf)
489 struct ChatClient *entry = cls;
490 struct P2PJoinNotificationMessage *m = buf;
496 #if DEBUG_CHAT_SERVICE
497 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting P2P join notification\n");
499 room_len = strlen (entry->room);
500 meta_len = entry->meta_len;
501 msg_size = sizeof (struct P2PJoinNotificationMessage) + meta_len + room_len;
502 GNUNET_assert (size >= msg_size);
503 GNUNET_assert (NULL != buf);
505 m->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_JOIN_NOTIFICATION);
506 m->header.size = htons (msg_size);
507 m->msg_options = htonl (entry->msg_options);
508 m->room_name_len = htons (room_len);
509 m->reserved = htons (0);
510 m->reserved2 = htonl (0);
511 m->public_key = entry->public_key;
512 roomptr = (char *) &m[1];
513 memcpy (roomptr, entry->room, room_len);
515 memcpy (&roomptr[room_len], entry->member_info, meta_len);
521 * Ask to send a join notification to the peer.
524 send_join_noficiation (void *cls, const struct GNUNET_HashCode * key, void *value)
526 struct ChatClient *entry = cls;
527 struct ConnectedPeer *cp = value;
528 struct GNUNET_PeerIdentity pid;
531 GNUNET_PEER_resolve (cp->pid, &pid);
532 #if DEBUG_CHAT_SERVICE
533 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending join notification to `%s'\n",
537 sizeof (struct P2PJoinNotificationMessage) + strlen (entry->room) +
540 GNUNET_CORE_notify_transmit_ready (core, GNUNET_NO, 1, MAX_TRANSMIT_DELAY,
542 &transmit_join_notification_to_peer,
544 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
545 _("Failed to queue a join notification\n"));
551 * A client asked for entering a chat room. Add the new member to the list of
552 * clients and notify remaining room members.
554 * @param cls closure, NULL
555 * @param client identification of the client
556 * @param message the actual message
559 handle_join_request (void *cls, struct GNUNET_SERVER_Client *client,
560 const struct GNUNET_MessageHeader *message)
562 const struct JoinRequestMessage *jrmsg;
565 uint16_t header_size;
567 uint16_t room_name_len;
568 struct ChatClient *new_entry;
569 struct ChatClient *entry;
570 struct JoinNotificationMessage *jnmsg;
571 struct JoinNotificationMessage *entry_jnmsg;
573 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client sent a join request\n");
574 if (ntohs (message->size) <= sizeof (struct JoinRequestMessage))
576 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n");
578 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
581 jrmsg = (const struct JoinRequestMessage *) message;
582 header_size = ntohs (jrmsg->header.size);
583 room_name_len = ntohs (jrmsg->room_name_len);
584 if (header_size - sizeof (struct JoinRequestMessage) <= room_name_len)
586 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
587 "Malformed message: wrong length of the room name\n");
589 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
592 meta_len = header_size - sizeof (struct JoinRequestMessage) - room_name_len;
593 roomptr = (const char *) &jrmsg[1];
594 room_name = GNUNET_malloc (room_name_len + 1);
595 memcpy (room_name, roomptr, room_name_len);
596 room_name[room_name_len] = '\0';
597 new_entry = GNUNET_malloc (sizeof (struct ChatClient));
598 memset (new_entry, 0, sizeof (struct ChatClient));
599 new_entry->client = client;
600 new_entry->room = room_name;
601 new_entry->public_key = jrmsg->public_key;
602 new_entry->meta_len = meta_len;
605 new_entry->member_info = GNUNET_malloc (meta_len);
606 memcpy (new_entry->member_info, &roomptr[room_name_len], meta_len);
609 new_entry->member_info = NULL;
610 GNUNET_CRYPTO_hash (&new_entry->public_key,
611 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
613 new_entry->msg_options = ntohl (jrmsg->msg_options);
614 new_entry->next = client_list_head;
615 client_list_head = new_entry;
616 #if DEBUG_CHAT_SERVICE
617 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
618 "Synchronizing room members between local clients\n");
620 jnmsg = GNUNET_malloc (sizeof (struct JoinNotificationMessage) + meta_len);
621 jnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION);
623 htons (sizeof (struct JoinNotificationMessage) + meta_len);
624 jnmsg->msg_options = jrmsg->msg_options;
625 jnmsg->public_key = new_entry->public_key;
626 memcpy (&jnmsg[1], &roomptr[room_name_len], meta_len);
627 GNUNET_SERVER_notification_context_add (nc, client);
628 entry = client_list_head;
629 while (NULL != entry)
631 if (0 == strcmp (room_name, entry->room))
633 if (NULL != entry->client)
634 GNUNET_SERVER_notification_context_unicast (nc, entry->client,
635 &jnmsg->header, GNUNET_NO);
636 if (entry->client != client)
639 GNUNET_malloc (sizeof (struct JoinNotificationMessage) +
641 entry_jnmsg->header.type =
642 htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION);
643 entry_jnmsg->header.size =
644 htons (sizeof (struct JoinNotificationMessage) + entry->meta_len);
645 entry_jnmsg->msg_options = entry->msg_options;
646 entry_jnmsg->public_key = entry->public_key;
647 memcpy (&entry_jnmsg[1], entry->member_info, entry->meta_len);
648 GNUNET_SERVER_notification_context_unicast (nc, client,
649 &entry_jnmsg->header,
651 GNUNET_free (entry_jnmsg);
656 #if DEBUG_CHAT_SERVICE
657 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
658 "Broadcasting join notification to neighbour peers\n");
660 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
661 &send_join_noficiation, new_entry);
662 GNUNET_SERVER_receive_done (client, GNUNET_OK);
667 * Transmit a confirmation receipt to the peer.
669 * @param cls closure, pointer to the 'struct P2PConfirmationReceiptMessage'
670 * @param size number of bytes available in buf
671 * @param buf where the callee should write the message
672 * @return number of bytes written to buf
675 transmit_confirmation_receipt_to_peer (void *cls, size_t size, void *buf)
677 struct P2PConfirmationReceiptMessage *receipt = cls;
680 #if DEBUG_CHAT_SERVICE
681 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
682 "Transmitting P2P confirmation receipt to '%s'\n",
683 GNUNET_h2s (&receipt->target));
687 /* client disconnected */
688 #if DEBUG_CHAT_SERVICE
689 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
690 "Buffer is NULL, dropping the message\n");
694 msg_size = sizeof (struct P2PConfirmationReceiptMessage);
695 GNUNET_assert (size >= msg_size);
696 memcpy (buf, receipt, msg_size);
697 GNUNET_free (receipt);
703 * Ask to send a confirmation receipt to the peer.
706 send_confirmation_receipt (void *cls, const struct GNUNET_HashCode * key, void *value)
708 struct P2PConfirmationReceiptMessage *receipt = cls;
709 struct ConnectedPeer *cp = value;
710 struct GNUNET_PeerIdentity pid;
711 struct P2PConfirmationReceiptMessage *my_receipt;
714 GNUNET_PEER_resolve (cp->pid, &pid);
715 #if DEBUG_CHAT_SERVICE
716 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending confirmation receipt to `%s'\n",
719 msg_size = sizeof (struct P2PConfirmationReceiptMessage);
721 GNUNET_memdup (receipt, sizeof (struct P2PConfirmationReceiptMessage));
723 GNUNET_CORE_notify_transmit_ready (core, GNUNET_YES, 1,
724 MAX_TRANSMIT_DELAY, &pid, msg_size,
725 &transmit_confirmation_receipt_to_peer,
727 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
728 _("Failed to queue a confirmation receipt\n"));
734 * A client sent a confirmation receipt. Broadcast the receipt to all connected
735 * peers if the author of the original message is a local client. Otherwise
736 * check the signature and notify the user if the signature is valid.
738 * @param cls closure, NULL
739 * @param client identification of the client
740 * @param message the actual message
743 handle_acknowledge_request (void *cls, struct GNUNET_SERVER_Client *client,
744 const struct GNUNET_MessageHeader *message)
746 const struct ConfirmationReceiptMessage *receipt;
747 struct ConfirmationReceiptMessage *crmsg;
748 struct P2PConfirmationReceiptMessage *p2p_crmsg;
749 struct ChatClient *target;
750 struct ChatClient *author;
752 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client sent a confirmation receipt\n");
753 receipt = (const struct ConfirmationReceiptMessage *) message;
754 author = client_list_head;
755 while ((NULL != author) &&
757 memcmp (&receipt->author, &author->id, sizeof (struct GNUNET_HashCode))))
758 author = author->next;
761 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
762 "Unknown author of the original message\n");
764 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
767 target = client_list_head;
768 while ((NULL != target) &&
770 memcmp (&receipt->target, &target->id, sizeof (struct GNUNET_HashCode))))
771 target = target->next;
774 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
775 "Unknown target of the confirmation receipt\n");
777 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
780 if (NULL == author->client)
782 target->rcpt_sequence_number++;
783 #if DEBUG_CHAT_SERVICE
784 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
785 "Broadcasting %s's receipt #%u to neighbour peers\n",
786 GNUNET_h2s (&target->id), target->rcpt_sequence_number);
788 p2p_crmsg = GNUNET_malloc (sizeof (struct P2PConfirmationReceiptMessage));
789 p2p_crmsg->header.size =
790 htons (sizeof (struct P2PConfirmationReceiptMessage));
791 p2p_crmsg->header.type =
792 htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_CONFIRMATION_RECEIPT);
793 p2p_crmsg->reserved = htonl (0);
794 p2p_crmsg->signature = receipt->signature;
795 p2p_crmsg->purpose = receipt->purpose;
796 p2p_crmsg->msg_sequence_number = receipt->sequence_number;
797 p2p_crmsg->timestamp = receipt->timestamp;
798 p2p_crmsg->target = receipt->target;
799 p2p_crmsg->author = receipt->author;
800 p2p_crmsg->content = receipt->content;
801 p2p_crmsg->sequence_number = htonl (target->rcpt_sequence_number);
802 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
803 &send_confirmation_receipt,
805 GNUNET_free (p2p_crmsg);
809 #if DEBUG_CHAT_SERVICE
810 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
811 "Verifying signature of the receipt\n");
814 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_CHAT_RECEIPT,
815 &receipt->purpose, &receipt->signature,
816 &target->public_key))
818 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
819 "Invalid signature of the receipt\n");
821 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
824 #if DEBUG_CHAT_SERVICE
825 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
826 "Sending receipt to the client which sent the original message\n");
828 crmsg = GNUNET_memdup (receipt, sizeof (struct ConfirmationReceiptMessage));
830 htons (GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION);
831 GNUNET_SERVER_notification_context_unicast (nc, author->client,
832 &crmsg->header, GNUNET_NO);
835 GNUNET_SERVER_receive_done (client, GNUNET_OK);
840 * Transmit a leave notification to the peer.
842 * @param cls closure, pointer to the
843 * 'struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded'
844 * @param size number of bytes available in buf
845 * @param buf where the callee should write the message
846 * @return number of bytes written to buf
849 transmit_leave_notification_to_peer (void *cls, size_t size, void *buf)
851 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key = cls;
852 struct P2PLeaveNotificationMessage *m = buf;
855 #if DEBUG_CHAT_SERVICE
856 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting P2P leave notification\n");
860 /* client disconnected */
861 #if DEBUG_CHAT_SERVICE
862 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
863 "Buffer is NULL, dropping the message\n");
867 msg_size = sizeof (struct P2PLeaveNotificationMessage);
868 GNUNET_assert (size >= msg_size);
870 m->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_LEAVE_NOTIFICATION);
871 m->header.size = htons (msg_size);
872 m->reserved = htonl (0);
873 m->user = *public_key;
874 GNUNET_free (public_key);
880 * Ask to send a leave notification to the peer.
883 send_leave_noficiation (void *cls, const struct GNUNET_HashCode * key, void *value)
885 struct ChatClient *entry = cls;
886 struct ConnectedPeer *cp = value;
887 struct GNUNET_PeerIdentity pid;
888 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key;
891 GNUNET_PEER_resolve (cp->pid, &pid);
892 #if DEBUG_CHAT_SERVICE
893 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending leave notification to `%s'\n",
896 msg_size = sizeof (struct P2PLeaveNotificationMessage);
898 GNUNET_memdup (&entry->public_key,
899 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
901 GNUNET_CORE_notify_transmit_ready (core, GNUNET_YES, 1,
902 MAX_TRANSMIT_DELAY, &pid, msg_size,
903 &transmit_leave_notification_to_peer,
905 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
906 _("Failed to queue a leave notification\n"));
912 * A client disconnected. Remove all of its data structure entries and notify
913 * remaining room members.
915 * @param cls closure, NULL
916 * @param client identification of the client
919 handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
921 struct ChatClient *entry;
922 struct ChatClient *pos;
923 struct ChatClient *prev;
924 struct LeaveNotificationMessage lnmsg;
926 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client disconnected\n");
927 pos = client_list_head;
929 while ((NULL != pos) && (pos->client != client))
936 #if DEBUG_CHAT_SERVICE
937 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
938 "No such client. There is nothing to do\n");
943 client_list_head = pos->next;
945 prev->next = pos->next;
946 entry = client_list_head;
947 #if DEBUG_CHAT_SERVICE
948 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
949 "Notifying local room members that the client has disconnected\n");
951 lnmsg.header.size = htons (sizeof (struct LeaveNotificationMessage));
952 lnmsg.header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION);
953 lnmsg.reserved = htonl (0);
954 lnmsg.user = pos->public_key;
955 while (NULL != entry)
957 if ((0 == strcmp (pos->room, entry->room)) && (NULL != entry->client))
959 GNUNET_SERVER_notification_context_unicast (nc, entry->client,
960 &lnmsg.header, GNUNET_NO);
964 #if DEBUG_CHAT_SERVICE
965 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
966 "Broadcasting leave notification to neighbour peers\n");
968 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
969 &send_leave_noficiation, pos);
970 GNUNET_free (pos->room);
971 GNUNET_free_non_null (pos->member_info);
977 * Handle P2P join notification.
979 * @param cls closure, always NULL
980 * @param other the other peer involved
981 * @param message the actual message
983 * @return GNUNET_OK to keep the connection open,
984 * GNUNET_SYSERR to close it (signal serious error)
987 handle_p2p_join_notification (void *cls,
988 const struct GNUNET_PeerIdentity *other,
989 const struct GNUNET_MessageHeader *message)
991 const struct P2PJoinNotificationMessage *p2p_jnmsg;
994 uint16_t header_size;
996 uint16_t room_name_len;
997 struct ChatClient *new_entry;
998 struct ChatClient *entry;
999 struct JoinNotificationMessage *jnmsg;
1000 struct GNUNET_HashCode id;
1002 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P join notification\n");
1003 if (ntohs (message->size) <= sizeof (struct P2PJoinNotificationMessage))
1005 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n");
1006 GNUNET_break_op (0);
1007 return GNUNET_SYSERR;
1009 p2p_jnmsg = (const struct P2PJoinNotificationMessage *) message;
1010 header_size = ntohs (p2p_jnmsg->header.size);
1011 room_name_len = ntohs (p2p_jnmsg->room_name_len);
1012 if (header_size - sizeof (struct P2PJoinNotificationMessage) <= room_name_len)
1014 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1015 "Malformed message: wrong length of the room name\n");
1016 GNUNET_break_op (0);
1017 return GNUNET_SYSERR;
1019 GNUNET_CRYPTO_hash (&p2p_jnmsg->public_key,
1020 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1022 entry = client_list_head;
1023 while (NULL != entry)
1025 if (0 == memcmp (&entry->id, &id, sizeof (struct GNUNET_HashCode)))
1027 #if DEBUG_CHAT_SERVICE
1028 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1029 "The client has already joined. There is nothing to do\n");
1033 entry = entry->next;
1036 header_size - sizeof (struct P2PJoinNotificationMessage) - room_name_len;
1037 roomptr = (const char *) &p2p_jnmsg[1];
1038 room_name = GNUNET_malloc (room_name_len + 1);
1039 memcpy (room_name, roomptr, room_name_len);
1040 room_name[room_name_len] = '\0';
1041 new_entry = GNUNET_malloc (sizeof (struct ChatClient));
1042 memset (new_entry, 0, sizeof (struct ChatClient));
1044 new_entry->client = NULL;
1045 new_entry->room = room_name;
1046 new_entry->public_key = p2p_jnmsg->public_key;
1047 new_entry->meta_len = meta_len;
1050 new_entry->member_info = GNUNET_malloc (meta_len);
1051 memcpy (new_entry->member_info, &roomptr[room_name_len], meta_len);
1054 new_entry->member_info = NULL;
1055 new_entry->msg_options = ntohl (p2p_jnmsg->msg_options);
1056 new_entry->next = client_list_head;
1057 client_list_head = new_entry;
1058 #if DEBUG_CHAT_SERVICE
1059 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1060 "Notifying local room members that we have a new client\n");
1062 jnmsg = GNUNET_malloc (sizeof (struct JoinNotificationMessage) + meta_len);
1063 jnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION);
1064 jnmsg->header.size =
1065 htons (sizeof (struct JoinNotificationMessage) + meta_len);
1066 jnmsg->msg_options = p2p_jnmsg->msg_options;
1067 jnmsg->public_key = new_entry->public_key;
1068 memcpy (&jnmsg[1], &roomptr[room_name_len], meta_len);
1069 entry = client_list_head;
1070 while (NULL != entry)
1072 if ((0 == strcmp (room_name, entry->room)) && (NULL != entry->client))
1074 GNUNET_SERVER_notification_context_unicast (nc, entry->client,
1075 &jnmsg->header, GNUNET_NO);
1077 entry = entry->next;
1079 #if DEBUG_CHAT_SERVICE
1080 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1081 "Broadcasting join notification to neighbour peers\n");
1083 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
1084 &send_join_noficiation, new_entry);
1085 GNUNET_free (jnmsg);
1091 * Handle P2P leave notification.
1093 * @param cls closure, always NULL
1094 * @param other the other peer involved
1095 * @param message the actual message
1096 * @return GNUNET_OK to keep the connection open,
1097 * GNUNET_SYSERR to close it (signal serious error)
1100 handle_p2p_leave_notification (void *cls,
1101 const struct GNUNET_PeerIdentity *other,
1102 const struct GNUNET_MessageHeader *message)
1104 const struct P2PLeaveNotificationMessage *p2p_lnmsg;
1105 struct GNUNET_HashCode id;
1106 struct ChatClient *pos;
1107 struct ChatClient *prev;
1108 struct ChatClient *entry;
1109 struct LeaveNotificationMessage lnmsg;
1111 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P leave notification\n");
1112 p2p_lnmsg = (const struct P2PLeaveNotificationMessage *) message;
1113 GNUNET_CRYPTO_hash (&p2p_lnmsg->user,
1114 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1116 pos = client_list_head;
1120 if (0 == memcmp (&pos->id, &id, sizeof (struct GNUNET_HashCode)))
1127 #if DEBUG_CHAT_SERVICE
1128 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1129 "No such client. There is nothing to do\n");
1134 client_list_head = pos->next;
1136 prev->next = pos->next;
1137 #if DEBUG_CHAT_SERVICE
1138 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1139 "Notifying local room members that the client has gone away\n");
1141 lnmsg.header.size = htons (sizeof (struct LeaveNotificationMessage));
1142 lnmsg.header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION);
1143 lnmsg.reserved = htonl (0);
1144 lnmsg.user = pos->public_key;
1145 entry = client_list_head;
1146 while (NULL != entry)
1148 if (0 == strcmp (pos->room, entry->room) && (NULL != entry->client))
1150 GNUNET_SERVER_notification_context_unicast (nc, entry->client,
1151 &lnmsg.header, GNUNET_NO);
1153 entry = entry->next;
1155 #if DEBUG_CHAT_SERVICE
1156 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1157 "Broadcasting leave notification to neighbour peers\n");
1159 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
1160 &send_leave_noficiation, pos);
1161 GNUNET_free (pos->room);
1162 GNUNET_free_non_null (pos->member_info);
1169 * Handle P2P message notification.
1171 * @param cls closure, always NULL
1172 * @param other the other peer involved
1173 * @param message the actual message
1174 * @return GNUNET_OK to keep the connection open,
1175 * GNUNET_SYSERR to close it (signal serious error)
1178 handle_p2p_message_notification (void *cls,
1179 const struct GNUNET_PeerIdentity *other,
1180 const struct GNUNET_MessageHeader *message)
1182 const struct P2PReceiveNotificationMessage *p2p_rnmsg;
1183 struct P2PReceiveNotificationMessage *my_p2p_rnmsg;
1184 struct ReceiveNotificationMessage *rnmsg;
1185 struct ChatClient *sender;
1186 struct ChatClient *pos;
1187 static struct GNUNET_HashCode all_zeros;
1191 uint16_t room_name_len;
1192 char *room_name = NULL;
1195 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P message notification\n");
1196 if (ntohs (message->size) <= sizeof (struct P2PReceiveNotificationMessage))
1198 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n");
1199 GNUNET_break_op (0);
1200 return GNUNET_SYSERR;
1202 p2p_rnmsg = (const struct P2PReceiveNotificationMessage *) message;
1204 ntohs (p2p_rnmsg->header.size) -
1205 sizeof (struct P2PReceiveNotificationMessage);
1207 is_anon = (0 != (ntohl (p2p_rnmsg->msg_options) & GNUNET_CHAT_MSG_ANONYMOUS));
1210 room_name_len = ntohs (p2p_rnmsg->room_name_len);
1211 if (msg_len <= room_name_len)
1213 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1214 "Malformed message: wrong length of the room name\n");
1215 GNUNET_break_op (0);
1216 return GNUNET_SYSERR;
1218 msg_len -= room_name_len;
1219 if (lookup_anonymous_message (p2p_rnmsg))
1221 #if DEBUG_CHAT_SERVICE
1222 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1223 "This anonymous message has already been handled.");
1227 remember_anonymous_message (p2p_rnmsg);
1228 room_name = GNUNET_malloc (room_name_len + 1);
1229 memcpy (room_name, (char *) &p2p_rnmsg[1], room_name_len);
1230 room_name[room_name_len] = '\0';
1231 text = (char *) &p2p_rnmsg[1] + room_name_len;
1235 sender = client_list_head;
1236 while ((NULL != sender) &&
1238 memcmp (&sender->id, &p2p_rnmsg->sender, sizeof (struct GNUNET_HashCode))))
1239 sender = sender->next;
1242 /* not an error since the sender may have left before we got the
1244 #if DEBUG_CHAT_SERVICE
1245 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1246 "Unknown source. Rejecting the message\n");
1250 if (sender->msg_sequence_number >= ntohl (p2p_rnmsg->sequence_number))
1252 #if DEBUG_CHAT_SERVICE
1253 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1254 "This message has already been handled."
1255 " Sequence numbers (msg/sender): %u/%u\n",
1256 ntohl (p2p_rnmsg->sequence_number),
1257 sender->msg_sequence_number);
1261 sender->msg_sequence_number = ntohl (p2p_rnmsg->sequence_number);
1262 room_name = sender->room;
1263 text = (char *) &p2p_rnmsg[1];
1266 #if DEBUG_CHAT_SERVICE
1267 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1268 "Sending message to local room members\n");
1270 rnmsg = GNUNET_malloc (sizeof (struct ReceiveNotificationMessage) + msg_len);
1271 rnmsg->header.size =
1272 htons (sizeof (struct ReceiveNotificationMessage) + msg_len);
1273 rnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION);
1274 rnmsg->msg_options = p2p_rnmsg->msg_options;
1275 rnmsg->sequence_number = p2p_rnmsg->sequence_number;
1276 rnmsg->reserved = htonl (0);
1277 rnmsg->timestamp = p2p_rnmsg->timestamp;
1279 (0 != memcmp (&all_zeros, &p2p_rnmsg->target, sizeof (struct GNUNET_HashCode)));
1281 memcpy (&rnmsg->encrypted_key, &p2p_rnmsg->encrypted_key,
1282 sizeof (struct GNUNET_CRYPTO_RsaEncryptedData));
1283 rnmsg->sender = p2p_rnmsg->sender;
1284 memcpy (&rnmsg[1], text, msg_len);
1285 pos = client_list_head;
1288 if ((0 == strcmp (room_name, pos->room)) && (NULL != pos->client))
1292 memcmp (&p2p_rnmsg->target, &pos->id, sizeof (struct GNUNET_HashCode)))) &&
1293 (0 == (ntohl (p2p_rnmsg->msg_options) & (~pos->msg_options))))
1295 GNUNET_SERVER_notification_context_unicast (nc, pos->client,
1296 &rnmsg->header, GNUNET_NO);
1302 GNUNET_free (room_name);
1303 #if DEBUG_CHAT_SERVICE
1304 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1305 "Broadcasting message notification to neighbour peers\n");
1307 my_p2p_rnmsg = GNUNET_memdup (p2p_rnmsg, ntohs (p2p_rnmsg->header.size));
1308 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
1309 &send_message_noficiation,
1311 GNUNET_free (rnmsg);
1317 * Handle P2P sync request.
1319 * @param cls closure, always NULL
1320 * @param other the other peer involved
1321 * @param message the actual message
1322 * @return GNUNET_OK to keep the connection open,
1323 * GNUNET_SYSERR to close it (signal serious error)
1326 handle_p2p_sync_request (void *cls, const struct GNUNET_PeerIdentity *other,
1327 const struct GNUNET_MessageHeader *message)
1329 struct ChatClient *entry;
1330 struct GNUNET_CORE_TransmitHandle *th;
1333 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P sync request\n");
1334 #if DEBUG_CHAT_SERVICE
1335 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1336 "Notifying the requester of all known clients\n");
1338 entry = client_list_head;
1339 while (NULL != entry)
1342 sizeof (struct P2PJoinNotificationMessage) + strlen (entry->room) +
1344 th = GNUNET_CORE_notify_transmit_ready (core, GNUNET_NO, 1,
1345 MAX_TRANSMIT_DELAY, other, msg_size,
1346 &transmit_join_notification_to_peer,
1348 GNUNET_assert (NULL != th);
1349 entry = entry->next;
1356 * Handle P2P confirmation receipt.
1358 * @param cls closure, always NULL
1359 * @param other the other peer involved
1360 * @param message the actual message
1361 * @return GNUNET_OK to keep the connection open,
1362 * GNUNET_SYSERR to close it (signal serious error)
1365 handle_p2p_confirmation_receipt (void *cls,
1366 const struct GNUNET_PeerIdentity *other,
1367 const struct GNUNET_MessageHeader *message)
1369 const struct P2PConfirmationReceiptMessage *p2p_crmsg;
1370 struct P2PConfirmationReceiptMessage *my_p2p_crmsg;
1371 struct ConfirmationReceiptMessage *crmsg;
1372 struct ChatClient *target;
1373 struct ChatClient *author;
1375 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P confirmation receipt\n");
1376 p2p_crmsg = (const struct P2PConfirmationReceiptMessage *) message;
1377 target = client_list_head;
1378 while ((NULL != target) &&
1380 memcmp (&target->id, &p2p_crmsg->target, sizeof (struct GNUNET_HashCode))))
1381 target = target->next;
1384 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1385 "Unknown source of the receipt. Rejecting the message\n");
1386 GNUNET_break_op (0);
1387 return GNUNET_SYSERR;
1389 if (target->rcpt_sequence_number >= ntohl (p2p_crmsg->sequence_number))
1391 #if DEBUG_CHAT_SERVICE
1392 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1393 "This receipt has already been handled."
1394 " Sequence numbers (msg/sender): %u/%u\n",
1395 ntohl (p2p_crmsg->sequence_number),
1396 target->rcpt_sequence_number);
1400 target->rcpt_sequence_number = ntohl (p2p_crmsg->sequence_number);
1401 author = client_list_head;
1402 while ((NULL != author) &&
1404 memcmp (&author->id, &p2p_crmsg->author, sizeof (struct GNUNET_HashCode))))
1405 author = author->next;
1408 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1409 "Unknown addressee. Rejecting the receipt\n");
1410 GNUNET_break_op (0);
1411 return GNUNET_SYSERR;
1414 if (NULL == author->client)
1416 #if DEBUG_CHAT_SERVICE
1417 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1418 "The author of the original message is not a local client."
1419 " Broadcasting receipt to neighbour peers\n");
1422 GNUNET_memdup (p2p_crmsg,
1423 sizeof (struct P2PConfirmationReceiptMessage));
1424 GNUNET_CONTAINER_multihashmap_iterate (connected_peers,
1425 &send_confirmation_receipt,
1427 GNUNET_free (my_p2p_crmsg);
1431 #if DEBUG_CHAT_SERVICE
1432 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1433 "The author of the original message is a local client."
1434 " Verifying signature of the receipt\n");
1436 crmsg = GNUNET_malloc (sizeof (struct ConfirmationReceiptMessage));
1437 crmsg->header.size = htons (sizeof (struct ConfirmationReceiptMessage));
1438 crmsg->header.type =
1439 htons (GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION);
1440 crmsg->signature = p2p_crmsg->signature;
1441 crmsg->purpose = p2p_crmsg->purpose;
1442 crmsg->sequence_number = p2p_crmsg->msg_sequence_number;
1443 crmsg->reserved2 = 0;
1444 crmsg->timestamp = p2p_crmsg->timestamp;
1445 crmsg->target = p2p_crmsg->target;
1446 crmsg->author = p2p_crmsg->author;
1447 crmsg->content = p2p_crmsg->content;
1449 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_CHAT_RECEIPT,
1450 &crmsg->purpose, &crmsg->signature,
1451 &target->public_key))
1453 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1454 "Invalid signature of the receipt\n");
1455 GNUNET_break_op (0);
1456 return GNUNET_SYSERR;
1458 #if DEBUG_CHAT_SERVICE
1459 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1460 "The author of the original message is a local client."
1461 " Sending receipt to the client\n");
1463 GNUNET_SERVER_notification_context_unicast (nc, author->client,
1464 &crmsg->header, GNUNET_NO);
1465 GNUNET_free (crmsg);
1472 * Transmit a sync request to the peer.
1474 * @param cls closure, NULL
1475 * @param size number of bytes available in buf
1476 * @param buf where the callee should write the message
1477 * @return number of bytes written to buf
1480 transmit_sync_request_to_peer (void *cls, size_t size, void *buf)
1482 struct GNUNET_MessageHeader *m = buf;
1485 #if DEBUG_CHAT_SERVICE
1486 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting P2P sync request\n");
1488 msg_size = sizeof (struct GNUNET_MessageHeader);
1489 GNUNET_assert (size >= msg_size);
1490 GNUNET_assert (NULL != buf);
1492 m->type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_SYNC_REQUEST);
1493 m->size = htons (msg_size);
1499 * Method called whenever a peer connects.
1501 * @param cls closure
1502 * @param peer peer identity this notification is about
1505 peer_connect_handler (void *cls, const struct GNUNET_PeerIdentity *peer)
1507 struct ConnectedPeer *cp;
1508 struct GNUNET_CORE_TransmitHandle *th;
1510 if (0 == memcmp (peer, &me, sizeof (struct GNUNET_PeerIdentity)))
1512 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Peer connected: %s\n",
1514 th = GNUNET_CORE_notify_transmit_ready (core, GNUNET_YES, 1,
1515 MAX_TRANSMIT_DELAY, peer,
1516 sizeof (struct GNUNET_MessageHeader),
1517 &transmit_sync_request_to_peer, NULL);
1518 GNUNET_assert (NULL != th);
1519 cp = GNUNET_CONTAINER_multihashmap_get (connected_peers, &peer->hashPubKey);
1525 cp = GNUNET_malloc (sizeof (struct ConnectedPeer));
1526 cp->pid = GNUNET_PEER_intern (peer);
1527 GNUNET_break (GNUNET_OK ==
1528 GNUNET_CONTAINER_multihashmap_put (connected_peers,
1529 &peer->hashPubKey, cp,
1530 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1535 * Iterator to free peer entries.
1537 * @param cls closure, unused
1538 * @param key current key code
1539 * @param value value in the hash map (peer entry)
1540 * @return GNUNET_YES (we should continue to iterate)
1543 clean_peer (void *cls, const struct GNUNET_HashCode * key, void *value)
1545 struct ConnectedPeer *cp;
1546 const struct GNUNET_PeerIdentity *peer =
1547 (const struct GNUNET_PeerIdentity *) key;
1549 cp = GNUNET_CONTAINER_multihashmap_get (connected_peers, &peer->hashPubKey);
1552 GNUNET_break (GNUNET_YES ==
1553 GNUNET_CONTAINER_multihashmap_remove (connected_peers,
1554 &peer->hashPubKey, cp));
1555 GNUNET_PEER_change_rc (cp->pid, -1);
1562 * Method called whenever a peer disconnects.
1564 * @param cls closure, not used
1565 * @param peer peer identity this notification is about
1568 peer_disconnect_handler (void *cls, const struct GNUNET_PeerIdentity *peer)
1571 if (0 == memcmp (peer, &me, sizeof (struct GNUNET_PeerIdentity)))
1573 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Peer disconnected: %s\n",
1575 clean_peer (NULL, (const struct GNUNET_HashCode *) peer, NULL);
1580 * Task run during shutdown.
1586 cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1588 struct AnonymousMessage *next_msg;
1589 struct ChatClient *next_client;
1591 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Cleaning up\n");
1594 GNUNET_CORE_disconnect (core);
1599 GNUNET_SERVER_notification_context_destroy (nc);
1602 while (NULL != client_list_head)
1604 next_client = client_list_head->next;
1605 GNUNET_free (client_list_head->room);
1606 GNUNET_free_non_null (client_list_head->member_info);
1607 GNUNET_free (client_list_head);
1608 client_list_head = next_client;
1610 while (NULL != anonymous_list_head)
1612 next_msg = anonymous_list_head->next;
1613 GNUNET_free (anonymous_list_head);
1614 anonymous_list_head = next_msg;
1616 GNUNET_CONTAINER_multihashmap_iterate (connected_peers, &clean_peer, NULL);
1617 GNUNET_CONTAINER_multihashmap_destroy (connected_peers);
1618 connected_peers = NULL;
1623 * To be called on core init/fail.
1625 * @param cls closure, NULL
1626 * @param server handle to the server for this service
1627 * @param my_identity the public identity of this peer
1630 core_init (void *cls, struct GNUNET_CORE_Handle *server,
1631 const struct GNUNET_PeerIdentity *my_identity)
1633 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Core initialized\n");
1639 * Process chat requests.
1641 * @param cls closure, NULL
1642 * @param server the initialized server
1643 * @param c configuration to use
1646 run (void *cls, struct GNUNET_SERVER_Handle *server,
1647 const struct GNUNET_CONFIGURATION_Handle *c)
1649 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1650 {&handle_join_request, NULL,
1651 GNUNET_MESSAGE_TYPE_CHAT_JOIN_REQUEST, 0},
1652 {&handle_transmit_request, NULL,
1653 GNUNET_MESSAGE_TYPE_CHAT_TRANSMIT_REQUEST, 0},
1654 {&handle_acknowledge_request, NULL,
1655 GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_RECEIPT,
1656 sizeof (struct ConfirmationReceiptMessage)},
1659 static const struct GNUNET_CORE_MessageHandler p2p_handlers[] = {
1660 {&handle_p2p_join_notification,
1661 GNUNET_MESSAGE_TYPE_CHAT_P2P_JOIN_NOTIFICATION, 0},
1662 {&handle_p2p_leave_notification,
1663 GNUNET_MESSAGE_TYPE_CHAT_P2P_LEAVE_NOTIFICATION,
1664 sizeof (struct P2PLeaveNotificationMessage)},
1665 {&handle_p2p_message_notification,
1666 GNUNET_MESSAGE_TYPE_CHAT_P2P_MESSAGE_NOTIFICATION, 0},
1667 {&handle_p2p_sync_request,
1668 GNUNET_MESSAGE_TYPE_CHAT_P2P_SYNC_REQUEST,
1669 sizeof (struct GNUNET_MessageHeader)},
1670 {&handle_p2p_confirmation_receipt,
1671 GNUNET_MESSAGE_TYPE_CHAT_P2P_CONFIRMATION_RECEIPT,
1672 sizeof (struct P2PConfirmationReceiptMessage)},
1676 GNUNET_log_setup ("gnunet-service-chat",
1677 #if DEBUG_CHAT_SERVICE
1684 nc = GNUNET_SERVER_notification_context_create (server, 16);
1686 GNUNET_CONTAINER_multihashmap_create (EXPECTED_NEIGHBOUR_COUNT, GNUNET_NO);
1687 GNUNET_SERVER_add_handlers (server, handlers);
1689 GNUNET_CORE_connect (cfg, NULL, &core_init,
1690 &peer_connect_handler, &peer_disconnect_handler,
1691 NULL, GNUNET_NO, NULL, GNUNET_NO, p2p_handlers);
1692 GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
1693 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
1699 * The main function for the chat service.
1701 * @param argc number of arguments from the command line
1702 * @param argv command line arguments
1703 * @return 0 ok, 1 on error
1706 main (int argc, char *const *argv)
1708 return (GNUNET_OK ==
1709 GNUNET_SERVICE_run (argc, argv, "chat", GNUNET_SERVICE_OPTION_NONE,
1710 &run, NULL)) ? 0 : 1;
1713 /* end of gnunet-service-chat.c */