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)
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).
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 * Linked list of recent anonymous messages.
100 struct AnonymousMessage
102 struct AnonymousMessage *next;
105 * Hash of the message.
107 GNUNET_HashCode hash;
113 * Handle to the core service (NULL until we've connected to it).
115 static struct GNUNET_CORE_Handle *core;
120 static const struct GNUNET_CONFIGURATION_Handle *cfg;
123 * The identity of this host.
125 static const struct GNUNET_PeerIdentity *me;
128 * Head of the list of current clients.
130 static struct ChatClient *client_list_head = NULL;
133 * Notification context containing all connected clients.
135 struct GNUNET_SERVER_NotificationContext *nc = NULL;
138 * Head of the list of recent anonymous messages.
140 static struct AnonymousMessage *anonymous_list_head = NULL;
144 remember_anonymous_message (const struct P2PReceiveNotificationMessage *p2p_rnmsg)
146 static GNUNET_HashCode hash;
147 struct AnonymousMessage *anon_msg;
148 struct AnonymousMessage *prev;
151 GNUNET_CRYPTO_hash (p2p_rnmsg, ntohs (p2p_rnmsg->header.size), &hash);
152 anon_msg = GNUNET_malloc (sizeof (struct AnonymousMessage));
153 anon_msg->hash = hash;
154 anon_msg->next = anonymous_list_head;
155 anonymous_list_head = anon_msg;
158 while ((NULL != anon_msg->next))
161 anon_msg = anon_msg->next;
164 if (anon_list_len == MAX_ANONYMOUS_MSG_LIST_LENGTH)
166 GNUNET_free (anon_msg);
174 lookup_anonymous_message (const struct P2PReceiveNotificationMessage *p2p_rnmsg)
176 static GNUNET_HashCode hash;
177 struct AnonymousMessage *anon_msg;
179 GNUNET_CRYPTO_hash (p2p_rnmsg, ntohs (p2p_rnmsg->header.size), &hash);
180 anon_msg = anonymous_list_head;
181 while ((NULL != anon_msg) &&
182 (0 != memcmp (&anon_msg->hash, &hash, sizeof (GNUNET_HashCode))))
183 anon_msg = anon_msg->next;
184 return (NULL != anon_msg);
189 * Transmit a message notification to the peer.
191 * @param cls closure, pointer to the 'struct P2PReceiveNotificationMessage'
192 * @param size number of bytes available in buf
193 * @param buf where the callee should write the message
194 * @return number of bytes written to buf
197 transmit_message_notification_to_peer (void *cls,
201 struct P2PReceiveNotificationMessage *my_msg = cls;
202 struct P2PReceiveNotificationMessage *m = buf;
205 #if DEBUG_CHAT_SERVICE
206 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
207 "Transmitting P2P message notification\n");
211 /* client disconnected */
212 #if DEBUG_CHAT_SERVICE
213 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
214 "Buffer is NULL, dropping the message\n");
218 msg_size = ntohs (my_msg->header.size);
219 GNUNET_assert (size >= msg_size);
220 memcpy (m, my_msg, msg_size);
221 GNUNET_free (my_msg);
227 * Ask to send a message notification to the peer.
230 send_message_noficiation (void *cls,
231 const struct GNUNET_PeerIdentity *peer,
232 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
234 struct P2PReceiveNotificationMessage *msg = cls;
235 struct P2PReceiveNotificationMessage *my_msg;
236 struct GNUNET_CORE_TransmitHandle *th;
242 #if DEBUG_CHAT_SERVICE
243 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
244 "Sending message notification to `%s'\n", GNUNET_i2s (peer));
246 my_msg = GNUNET_memdup (msg, ntohs (msg->header.size));
247 th = GNUNET_CORE_notify_transmit_ready (core,
251 ntohs (msg->header.size),
252 &transmit_message_notification_to_peer,
254 GNUNET_assert (NULL != th);
260 * A client sent a chat message. Encrypt the message text if the message is
261 * private. Send the message to local room members and to all connected peers.
263 * @param cls closure, NULL
264 * @param client identification of the client
265 * @param message the actual message
268 handle_transmit_request (void *cls,
269 struct GNUNET_SERVER_Client *client,
270 const struct GNUNET_MessageHeader *message)
272 static GNUNET_HashCode all_zeros;
273 const struct TransmitRequestMessage *trmsg;
274 struct ReceiveNotificationMessage *rnmsg;
275 struct P2PReceiveNotificationMessage *p2p_rnmsg;
276 struct ChatClient *pos;
277 struct ChatClient *target;
278 struct GNUNET_CRYPTO_AesSessionKey key;
279 char encrypted_msg[MAX_MESSAGE_LENGTH];
286 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client sent a chat message\n");
287 if (ntohs (message->size) <= sizeof (struct TransmitRequestMessage))
289 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n");
291 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
294 trmsg = (const struct TransmitRequestMessage *) message;
295 msg_len = ntohs (trmsg->header.size) - sizeof (struct TransmitRequestMessage);
296 is_priv = (0 != (ntohl (trmsg->msg_options) & GNUNET_CHAT_MSG_PRIVATE));
299 #if DEBUG_CHAT_SERVICE
300 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypting the message text\n");
302 GNUNET_CRYPTO_aes_create_session_key (&key);
303 msg_len = GNUNET_CRYPTO_aes_encrypt (&trmsg[1],
306 (const struct GNUNET_CRYPTO_AesInitializationVector *) INITVALUE,
310 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
311 "Could not encrypt the message text\n");
313 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
317 rnmsg = GNUNET_malloc (sizeof (struct ReceiveNotificationMessage) + msg_len);
318 rnmsg->header.size = htons (sizeof (struct ReceiveNotificationMessage) +
320 rnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION);
321 rnmsg->msg_options = trmsg->msg_options;
322 rnmsg->timestamp = trmsg->timestamp;
323 pos = client_list_head;
324 while ((NULL != pos) && (pos->client != client))
328 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
329 "The client is not a member of a chat room. Client has to "
330 "join a chat room first\n");
332 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
337 pos->msg_sequence_number = ntohl (trmsg->sequence_number);
338 is_anon = (0 != (ntohl (trmsg->msg_options) & GNUNET_CHAT_MSG_ANONYMOUS));
341 memset (&rnmsg->sender, 0, sizeof (GNUNET_HashCode));
342 rnmsg->sequence_number = 0;
346 rnmsg->sender = pos->id;
347 rnmsg->sequence_number = trmsg->sequence_number;
351 #if DEBUG_CHAT_SERVICE
352 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
353 "Encrypting the session key using the public key of '%s'\n",
354 GNUNET_h2s (&trmsg->target));
356 if (0 == memcmp (&all_zeros, &trmsg->target, sizeof (GNUNET_HashCode)))
358 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
359 "Malformed message: private, but no target\n");
361 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
365 memcpy (&rnmsg[1], encrypted_msg, msg_len);
366 target = client_list_head;
367 while ((NULL != target) &&
368 (0 != memcmp (&target->id,
370 sizeof (GNUNET_HashCode))))
371 target = target->next;
374 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
375 "Unknown target of the private message\n");
377 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
381 if (GNUNET_SYSERR == GNUNET_CRYPTO_rsa_encrypt (&key,
382 sizeof (struct GNUNET_CRYPTO_AesSessionKey),
384 &rnmsg->encrypted_key))
386 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
387 "Could not encrypt the session key\n");
389 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
396 memcpy (&rnmsg[1], &trmsg[1], msg_len);
398 pos = client_list_head;
399 #if DEBUG_CHAT_SERVICE
400 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message to local room members\n");
404 if ((0 == strcmp (room, pos->room)) &&
405 (NULL != pos->client) &&
406 (pos->client != client))
409 (0 == memcmp (&trmsg->target,
411 sizeof (GNUNET_HashCode)))) &&
412 (0 == (ntohl (trmsg->msg_options) & (~pos->msg_options))))
414 GNUNET_SERVER_notification_context_unicast (nc,
422 #if DEBUG_CHAT_SERVICE
423 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
424 "Broadcasting message to neighbour peers\n");
428 room_len = strlen (room);
429 p2p_rnmsg = GNUNET_malloc (sizeof (struct P2PReceiveNotificationMessage) +
431 p2p_rnmsg->header.size =
432 htons (sizeof (struct P2PReceiveNotificationMessage) + msg_len +
434 p2p_rnmsg->room_name_len = htons (room_len);
435 memcpy ((char *) &p2p_rnmsg[1], room, room_len);
436 memcpy ((char *) &p2p_rnmsg[1] + room_len, &trmsg[1], msg_len);
440 p2p_rnmsg = GNUNET_malloc (sizeof (struct P2PReceiveNotificationMessage) +
442 p2p_rnmsg->header.size =
443 htons (sizeof (struct P2PReceiveNotificationMessage) + msg_len);
446 memcpy (&p2p_rnmsg[1], encrypted_msg, msg_len);
447 memcpy (&p2p_rnmsg->encrypted_key,
448 &rnmsg->encrypted_key,
449 sizeof (struct GNUNET_CRYPTO_RsaEncryptedData));
452 memcpy (&p2p_rnmsg[1], &trmsg[1], msg_len);
454 p2p_rnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_MESSAGE_NOTIFICATION);
455 p2p_rnmsg->msg_options = trmsg->msg_options;
456 p2p_rnmsg->sequence_number = trmsg->sequence_number;
457 p2p_rnmsg->timestamp = trmsg->timestamp;
458 p2p_rnmsg->reserved = 0;
459 p2p_rnmsg->sender = rnmsg->sender;
460 p2p_rnmsg->target = trmsg->target;
462 remember_anonymous_message (p2p_rnmsg);
463 GNUNET_CORE_iterate_peers (cfg,
464 &send_message_noficiation,
466 GNUNET_SERVER_receive_done (client, GNUNET_OK);
472 * Transmit a join notification to the peer.
474 * @param cls closure, pointer to the 'struct ChatClient'
475 * @param size number of bytes available in buf
476 * @param buf where the callee should write the message
477 * @return number of bytes written to buf
480 transmit_join_notification_to_peer (void *cls,
484 struct ChatClient *entry = cls;
485 struct P2PJoinNotificationMessage *m = buf;
491 #if DEBUG_CHAT_SERVICE
492 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
493 "Transmitting P2P join notification\n");
495 room_len = strlen (entry->room);
496 meta_len = entry->meta_len;
497 msg_size = sizeof (struct P2PJoinNotificationMessage) + meta_len + room_len;
498 GNUNET_assert (size >= msg_size);
499 GNUNET_assert (NULL != buf);
501 m->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_JOIN_NOTIFICATION);
502 m->header.size = htons (msg_size);
503 m->msg_options = htonl (entry->msg_options);
504 m->room_name_len = htons (room_len);
505 m->reserved = htons (0);
506 m->public_key = entry->public_key;
507 roomptr = (char *) &m[1];
508 memcpy (roomptr, entry->room, room_len);
510 memcpy (&roomptr[room_len], entry->member_info, meta_len);
516 * Ask to send a join notification to the peer.
519 send_join_noficiation (void *cls,
520 const struct GNUNET_PeerIdentity *peer,
521 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
523 struct ChatClient *entry = cls;
524 struct GNUNET_CORE_TransmitHandle *th;
529 #if DEBUG_CHAT_SERVICE
530 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
531 "Sending join notification to `%s'\n", GNUNET_i2s (peer));
533 msg_size = sizeof (struct P2PJoinNotificationMessage) +
534 strlen (entry->room) +
536 th = GNUNET_CORE_notify_transmit_ready (core,
541 &transmit_join_notification_to_peer,
543 GNUNET_assert (NULL != th);
549 * A client asked for entering a chat room. Add the new member to the list of
550 * clients and notify remaining room members.
552 * @param cls closure, NULL
553 * @param client identification of the client
554 * @param message the actual message
557 handle_join_request (void *cls,
558 struct GNUNET_SERVER_Client *client,
559 const struct GNUNET_MessageHeader *message)
561 const struct JoinRequestMessage *jrmsg;
564 uint16_t header_size;
566 uint16_t room_name_len;
567 struct ChatClient *new_entry;
568 struct ChatClient *entry;
569 struct JoinNotificationMessage *jnmsg;
570 struct JoinNotificationMessage *entry_jnmsg;
572 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client sent a join request\n");
573 if (ntohs (message->size) <= sizeof (struct JoinRequestMessage))
575 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n");
577 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
580 jrmsg = (const struct JoinRequestMessage *) message;
581 header_size = ntohs (jrmsg->header.size);
582 room_name_len = ntohs (jrmsg->room_name_len);
583 if (header_size - sizeof (struct JoinRequestMessage) <=
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);
593 header_size - sizeof (struct JoinRequestMessage) - room_name_len;
594 roomptr = (const char *) &jrmsg[1];
595 room_name = GNUNET_malloc (room_name_len + 1);
596 memcpy (room_name, roomptr, room_name_len);
597 room_name[room_name_len] = '\0';
598 new_entry = GNUNET_malloc (sizeof (struct ChatClient));
599 memset (new_entry, 0, sizeof (struct ChatClient));
600 new_entry->client = client;
601 new_entry->room = room_name;
602 new_entry->public_key = jrmsg->public_key;
603 new_entry->meta_len = meta_len;
606 new_entry->member_info = GNUNET_malloc (meta_len);
607 memcpy (new_entry->member_info, &roomptr[room_name_len], meta_len);
610 new_entry->member_info = NULL;
611 GNUNET_CRYPTO_hash (&new_entry->public_key,
612 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
614 new_entry->msg_options = ntohl (jrmsg->msg_options);
615 new_entry->next = client_list_head;
616 client_list_head = new_entry;
617 #if DEBUG_CHAT_SERVICE
618 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
619 "Synchronizing room members between local clients\n");
621 jnmsg = GNUNET_malloc (sizeof (struct JoinNotificationMessage) + meta_len);
622 jnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION);
624 htons (sizeof (struct JoinNotificationMessage) + meta_len);
625 jnmsg->msg_options = jrmsg->msg_options;
626 jnmsg->public_key = new_entry->public_key;
627 memcpy (&jnmsg[1], &roomptr[room_name_len], meta_len);
628 GNUNET_SERVER_notification_context_add (nc, client);
629 entry = client_list_head;
630 while (NULL != entry)
632 if (0 == strcmp (room_name, entry->room))
634 if (NULL != entry->client)
635 GNUNET_SERVER_notification_context_unicast (nc,
639 if (entry->client != client)
642 GNUNET_malloc (sizeof (struct JoinNotificationMessage) +
644 entry_jnmsg->header.type =
645 htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION);
646 entry_jnmsg->header.size =
647 htons (sizeof (struct JoinNotificationMessage) +
649 entry_jnmsg->msg_options = entry->msg_options;
650 entry_jnmsg->public_key = entry->public_key;
651 memcpy (&entry_jnmsg[1], entry->member_info, entry->meta_len);
652 GNUNET_SERVER_notification_context_unicast (nc,
654 &entry_jnmsg->header,
656 GNUNET_free (entry_jnmsg);
661 #if DEBUG_CHAT_SERVICE
662 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
663 "Broadcasting join notification to neighbour peers\n");
665 GNUNET_CORE_iterate_peers (cfg,
666 &send_join_noficiation,
668 GNUNET_SERVER_receive_done (client, GNUNET_OK);
673 * Transmit a confirmation receipt to the peer.
675 * @param cls closure, pointer to the 'struct P2PConfirmationReceiptMessage'
676 * @param size number of bytes available in buf
677 * @param buf where the callee should write the message
678 * @return number of bytes written to buf
681 transmit_confirmation_receipt_to_peer (void *cls,
685 struct P2PConfirmationReceiptMessage *receipt = cls;
688 #if DEBUG_CHAT_SERVICE
689 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
690 "Transmitting P2P confirmation receipt to '%s'\n",
691 GNUNET_h2s (&receipt->target));
695 /* client disconnected */
696 #if DEBUG_CHAT_SERVICE
697 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
698 "Buffer is NULL, dropping the message\n");
702 msg_size = sizeof (struct P2PConfirmationReceiptMessage);
703 GNUNET_assert (size >= msg_size);
704 memcpy (buf, receipt, msg_size);
705 GNUNET_free (receipt);
711 * Ask to send a confirmation receipt to the peer.
714 send_confirmation_receipt (void *cls,
715 const struct GNUNET_PeerIdentity *peer,
716 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
718 struct P2PConfirmationReceiptMessage *receipt = cls;
719 struct P2PConfirmationReceiptMessage *my_receipt;
720 struct GNUNET_CORE_TransmitHandle *th;
724 GNUNET_free (receipt);
727 #if DEBUG_CHAT_SERVICE
728 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
729 "Sending confirmation receipt to `%s'\n", GNUNET_i2s (peer));
731 msg_size = sizeof (struct P2PConfirmationReceiptMessage);
732 my_receipt = GNUNET_memdup (receipt,
733 sizeof (struct P2PConfirmationReceiptMessage));
734 th = GNUNET_CORE_notify_transmit_ready (core,
739 &transmit_confirmation_receipt_to_peer,
741 GNUNET_assert (NULL != th);
747 * A client sent a confirmation receipt. Broadcast the receipt to all connected
748 * peers if the author of the original message is a local client. Otherwise
749 * check the signature and notify the user if the signature is valid.
751 * @param cls closure, NULL
752 * @param client identification of the client
753 * @param message the actual message
756 handle_acknowledge_request (void *cls,
757 struct GNUNET_SERVER_Client *client,
758 const struct GNUNET_MessageHeader *message)
760 const struct ConfirmationReceiptMessage *receipt;
761 struct ConfirmationReceiptMessage *crmsg;
762 struct P2PConfirmationReceiptMessage *p2p_crmsg;
763 struct ChatClient *target;
764 struct ChatClient *author;
766 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client sent a confirmation receipt\n");
767 receipt = (const struct ConfirmationReceiptMessage *) message;
768 author = client_list_head;
769 while ((NULL != author) &&
770 (0 != memcmp (&receipt->author,
772 sizeof (GNUNET_HashCode))))
773 author = author->next;
776 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
777 "Unknown author of the original message\n");
779 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
782 target = client_list_head;
783 while ((NULL != target) &&
784 (0 != memcmp (&receipt->target,
786 sizeof (GNUNET_HashCode))))
787 target = target->next;
790 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
791 "Unknown target of the confirmation receipt\n");
793 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
796 if (NULL == author->client)
798 target->rcpt_sequence_number++;
799 #if DEBUG_CHAT_SERVICE
800 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
801 "Broadcasting %s's receipt #%u to neighbour peers\n",
802 GNUNET_h2s (&target->id), target->rcpt_sequence_number);
804 p2p_crmsg = GNUNET_malloc (sizeof (struct P2PConfirmationReceiptMessage));
805 p2p_crmsg->header.size = htons (sizeof (struct P2PConfirmationReceiptMessage));
806 p2p_crmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_CONFIRMATION_RECEIPT);
807 p2p_crmsg->signature = receipt->signature;
808 p2p_crmsg->purpose = receipt->purpose;
809 p2p_crmsg->msg_sequence_number = receipt->sequence_number;
810 p2p_crmsg->timestamp = receipt->timestamp;
811 p2p_crmsg->target = receipt->target;
812 p2p_crmsg->author = receipt->author;
813 p2p_crmsg->content = receipt->content;
814 p2p_crmsg->sequence_number = htonl (target->rcpt_sequence_number);
815 GNUNET_CORE_iterate_peers (cfg,
816 &send_confirmation_receipt,
821 #if DEBUG_CHAT_SERVICE
822 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
823 "Verifying signature of the receipt\n");
826 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_CHAT_RECEIPT,
829 &target->public_key))
831 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
832 "Invalid signature of the receipt\n");
834 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
837 #if DEBUG_CHAT_SERVICE
838 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
839 "Sending receipt to the client which sent the original message\n");
841 crmsg = GNUNET_memdup (receipt, sizeof (struct ConfirmationReceiptMessage));
842 crmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION);
843 GNUNET_SERVER_notification_context_unicast (nc,
849 GNUNET_SERVER_receive_done (client, GNUNET_OK);
854 * Transmit a leave notification to the peer.
856 * @param cls closure, pointer to the
857 * 'struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded'
858 * @param size number of bytes available in buf
859 * @param buf where the callee should write the message
860 * @return number of bytes written to buf
863 transmit_leave_notification_to_peer (void *cls,
867 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key = cls;
868 struct P2PLeaveNotificationMessage *m = buf;
871 #if DEBUG_CHAT_SERVICE
872 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
873 "Transmitting P2P leave notification\n");
877 /* client disconnected */
878 #if DEBUG_CHAT_SERVICE
879 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
880 "Buffer is NULL, dropping the message\n");
884 msg_size = sizeof (struct P2PLeaveNotificationMessage);
885 GNUNET_assert (size >= msg_size);
887 m->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_LEAVE_NOTIFICATION);
888 m->header.size = htons (msg_size);
889 m->reserved = htons (0);
890 m->user = *public_key;
891 GNUNET_free (public_key);
897 * Ask to send a leave notification to the peer.
900 send_leave_noficiation (void *cls,
901 const struct GNUNET_PeerIdentity *peer,
902 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
904 struct ChatClient *entry = cls;
905 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key;
910 GNUNET_free (entry->room);
911 GNUNET_free_non_null (entry->member_info);
916 #if DEBUG_CHAT_SERVICE
917 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
918 "Sending leave notification to `%s'\n", GNUNET_i2s (peer));
920 msg_size = sizeof (struct P2PLeaveNotificationMessage);
921 public_key = GNUNET_memdup (&entry->public_key,
922 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
923 if (NULL == GNUNET_CORE_notify_transmit_ready (core,
928 &transmit_leave_notification_to_peer,
930 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
931 _("Failed to queue a leave notification\n"));
937 * A client disconnected. Remove all of its data structure entries and notify
938 * remaining room members.
940 * @param cls closure, NULL
941 * @param client identification of the client
944 handle_client_disconnect (void *cls,
945 struct GNUNET_SERVER_Client *client)
947 struct ChatClient *entry;
948 struct ChatClient *pos;
949 struct ChatClient *prev;
950 struct LeaveNotificationMessage lnmsg;
952 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client disconnected\n");
953 pos = client_list_head;
955 while ((NULL != pos) && (pos->client != client))
962 #if DEBUG_CHAT_SERVICE
963 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
964 "No such client. There is nothing to do\n");
969 client_list_head = pos->next;
971 prev->next = pos->next;
972 entry = client_list_head;
973 #if DEBUG_CHAT_SERVICE
974 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
975 "Notifying local room members that the client has disconnected\n");
977 lnmsg.header.size = htons (sizeof (struct LeaveNotificationMessage));
978 lnmsg.header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION);
979 lnmsg.reserved = htonl (0);
980 lnmsg.user = pos->public_key;
981 while (NULL != entry)
983 if ((0 == strcmp (pos->room, entry->room)) &&
984 (NULL != entry->client))
986 GNUNET_SERVER_notification_context_unicast (nc,
993 #if DEBUG_CHAT_SERVICE
994 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
995 "Broadcasting leave notification to neighbour peers\n");
997 GNUNET_CORE_iterate_peers (cfg,
998 &send_leave_noficiation,
1004 * Handle P2P join notification.
1006 * @param cls closure, always NULL
1007 * @param other the other peer involved
1008 * @param message the actual message
1009 * @param atsi performance information
1010 * @return GNUNET_OK to keep the connection open,
1011 * GNUNET_SYSERR to close it (signal serious error)
1014 handle_p2p_join_notification (void *cls,
1015 const struct GNUNET_PeerIdentity *other,
1016 const struct GNUNET_MessageHeader *message,
1017 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1019 const struct P2PJoinNotificationMessage *p2p_jnmsg;
1021 const char *roomptr;
1022 uint16_t header_size;
1024 uint16_t room_name_len;
1025 struct ChatClient *new_entry;
1026 struct ChatClient *entry;
1027 struct JoinNotificationMessage *jnmsg;
1030 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P join notification\n");
1031 if (ntohs (message->size) <= sizeof (struct P2PJoinNotificationMessage))
1033 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n");
1034 GNUNET_break_op (0);
1035 return GNUNET_SYSERR;
1037 p2p_jnmsg = (const struct P2PJoinNotificationMessage *) message;
1038 header_size = ntohs (p2p_jnmsg->header.size);
1039 room_name_len = ntohs (p2p_jnmsg->room_name_len);
1040 if (header_size - sizeof (struct P2PJoinNotificationMessage) <=
1043 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1044 "Malformed message: wrong length of the room name\n");
1045 GNUNET_break_op (0);
1046 return GNUNET_SYSERR;
1048 GNUNET_CRYPTO_hash (&p2p_jnmsg->public_key,
1049 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1051 entry = client_list_head;
1052 while (NULL != entry)
1054 if (0 == memcmp (&entry->id, &id, sizeof (GNUNET_HashCode)))
1056 #if DEBUG_CHAT_SERVICE
1057 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1058 "The client has already joined. There is nothing to do\n");
1062 entry = entry->next;
1065 header_size - sizeof (struct P2PJoinNotificationMessage) - room_name_len;
1066 roomptr = (const char *) &p2p_jnmsg[1];
1067 room_name = GNUNET_malloc (room_name_len + 1);
1068 memcpy (room_name, roomptr, room_name_len);
1069 room_name[room_name_len] = '\0';
1070 new_entry = GNUNET_malloc (sizeof (struct ChatClient));
1071 memset (new_entry, 0, sizeof (struct ChatClient));
1073 new_entry->client = NULL;
1074 new_entry->room = room_name;
1075 new_entry->public_key = p2p_jnmsg->public_key;
1076 new_entry->meta_len = meta_len;
1079 new_entry->member_info = GNUNET_malloc (meta_len);
1080 memcpy (new_entry->member_info, &roomptr[room_name_len], meta_len);
1083 new_entry->member_info = NULL;
1084 new_entry->msg_options = ntohl (p2p_jnmsg->msg_options);
1085 new_entry->next = client_list_head;
1086 client_list_head = new_entry;
1087 #if DEBUG_CHAT_SERVICE
1088 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1089 "Notifying local room members that we have a new client\n");
1091 jnmsg = GNUNET_malloc (sizeof (struct JoinNotificationMessage) + meta_len);
1092 jnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION);
1093 jnmsg->header.size =
1094 htons (sizeof (struct JoinNotificationMessage) + meta_len);
1095 jnmsg->msg_options = p2p_jnmsg->msg_options;
1096 jnmsg->public_key = new_entry->public_key;
1097 memcpy (&jnmsg[1], &roomptr[room_name_len], meta_len);
1098 entry = client_list_head;
1099 while (NULL != entry)
1101 if ((0 == strcmp (room_name, entry->room)) &&
1102 (NULL != entry->client))
1104 GNUNET_SERVER_notification_context_unicast (nc,
1109 entry = entry->next;
1111 #if DEBUG_CHAT_SERVICE
1112 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1113 "Broadcasting join notification to neighbour peers\n");
1115 GNUNET_CORE_iterate_peers (cfg,
1116 &send_join_noficiation,
1118 GNUNET_free (jnmsg);
1124 * Handle P2P leave notification.
1126 * @param cls closure, always NULL
1127 * @param other the other peer involved
1128 * @param message the actual message
1129 * @param atsi performance information
1130 * @return GNUNET_OK to keep the connection open,
1131 * GNUNET_SYSERR to close it (signal serious error)
1134 handle_p2p_leave_notification (void *cls,
1135 const struct GNUNET_PeerIdentity *other,
1136 const struct GNUNET_MessageHeader *message,
1137 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1139 const struct P2PLeaveNotificationMessage *p2p_lnmsg;
1141 struct ChatClient *pos;
1142 struct ChatClient *prev;
1143 struct ChatClient *entry;
1144 struct LeaveNotificationMessage lnmsg;
1146 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P leave notification\n");
1147 p2p_lnmsg = (const struct P2PLeaveNotificationMessage *) message;
1148 GNUNET_CRYPTO_hash (&p2p_lnmsg->user,
1149 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1151 pos = client_list_head;
1155 if (0 == memcmp (&pos->id, &id, sizeof (GNUNET_HashCode)))
1162 #if DEBUG_CHAT_SERVICE
1163 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1164 "No such client. There is nothing to do\n");
1169 client_list_head = pos->next;
1171 prev->next = pos->next;
1172 #if DEBUG_CHAT_SERVICE
1173 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1174 "Notifying local room members that the client has gone away\n");
1176 lnmsg.header.size = htons (sizeof (struct LeaveNotificationMessage));
1177 lnmsg.header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION);
1178 lnmsg.reserved = htonl (0);
1179 lnmsg.user = pos->public_key;
1180 entry = client_list_head;
1181 while (NULL != entry)
1183 if (0 == strcmp (pos->room, entry->room) &&
1184 (NULL != entry->client))
1186 GNUNET_SERVER_notification_context_unicast (nc,
1191 entry = entry->next;
1193 #if DEBUG_CHAT_SERVICE
1194 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1195 "Broadcasting leave notification to neighbour peers\n");
1197 GNUNET_CORE_iterate_peers (cfg,
1198 &send_leave_noficiation,
1205 * Handle P2P message notification.
1207 * @param cls closure, always NULL
1208 * @param other the other peer involved
1209 * @param message the actual message
1210 * @param atsi performance information
1211 * @return GNUNET_OK to keep the connection open,
1212 * GNUNET_SYSERR to close it (signal serious error)
1215 handle_p2p_message_notification (void *cls,
1216 const struct GNUNET_PeerIdentity *other,
1217 const struct GNUNET_MessageHeader *message,
1218 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1220 const struct P2PReceiveNotificationMessage *p2p_rnmsg;
1221 struct P2PReceiveNotificationMessage *my_p2p_rnmsg;
1222 struct ReceiveNotificationMessage *rnmsg;
1223 struct ChatClient *sender;
1224 struct ChatClient *pos;
1225 static GNUNET_HashCode all_zeros;
1229 uint16_t room_name_len;
1230 char *room_name = NULL;
1233 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P message notification\n");
1234 if (ntohs (message->size) <= sizeof (struct P2PReceiveNotificationMessage))
1236 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n");
1237 GNUNET_break_op (0);
1238 return GNUNET_SYSERR;
1240 p2p_rnmsg = (const struct P2PReceiveNotificationMessage *) message;
1241 msg_len = ntohs (p2p_rnmsg->header.size) -
1242 sizeof (struct P2PReceiveNotificationMessage);
1244 is_anon = (0 != (ntohl (p2p_rnmsg->msg_options) & GNUNET_CHAT_MSG_ANONYMOUS));
1247 room_name_len = ntohs (p2p_rnmsg->room_name_len);
1248 if (msg_len <= room_name_len)
1250 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1251 "Malformed message: wrong length of the room name\n");
1252 GNUNET_break_op (0);
1253 return GNUNET_SYSERR;
1255 msg_len -= room_name_len;
1256 if (lookup_anonymous_message (p2p_rnmsg))
1258 #if DEBUG_CHAT_SERVICE
1259 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1260 "This anonymous message has already been handled.");
1264 remember_anonymous_message (p2p_rnmsg);
1265 room_name = GNUNET_malloc (room_name_len + 1);
1266 memcpy (room_name, (char *) &p2p_rnmsg[1], room_name_len);
1267 room_name[room_name_len] = '\0';
1268 text = (char *) &p2p_rnmsg[1] + room_name_len;
1272 sender = client_list_head;
1273 while ((NULL != sender) &&
1274 (0 != memcmp (&sender->id,
1276 sizeof (GNUNET_HashCode))))
1277 sender = sender->next;
1280 /* not an error since the sender may have left before we got the
1282 #if DEBUG_CHAT_SERVICE
1283 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1284 "Unknown source. Rejecting the message\n");
1288 if (sender->msg_sequence_number >= ntohl (p2p_rnmsg->sequence_number))
1290 #if DEBUG_CHAT_SERVICE
1291 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1292 "This message has already been handled."
1293 " Sequence numbers (msg/sender): %u/%u\n",
1294 ntohl (p2p_rnmsg->sequence_number),
1295 sender->msg_sequence_number);
1299 sender->msg_sequence_number = ntohl (p2p_rnmsg->sequence_number);
1300 room_name = sender->room;
1301 text = (char *) &p2p_rnmsg[1];
1304 #if DEBUG_CHAT_SERVICE
1305 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1306 "Sending message to local room members\n");
1308 rnmsg = GNUNET_malloc (sizeof (struct ReceiveNotificationMessage) + msg_len);
1309 rnmsg->header.size = htons (sizeof (struct ReceiveNotificationMessage) +
1311 rnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION);
1312 rnmsg->msg_options = p2p_rnmsg->msg_options;
1313 rnmsg->sequence_number = p2p_rnmsg->sequence_number;
1314 rnmsg->timestamp = p2p_rnmsg->timestamp;
1315 is_priv = (0 != memcmp (&all_zeros,
1316 &p2p_rnmsg->target, sizeof (GNUNET_HashCode)));
1318 memcpy (&rnmsg->encrypted_key,
1319 &p2p_rnmsg->encrypted_key,
1320 sizeof (struct GNUNET_CRYPTO_RsaEncryptedData));
1321 rnmsg->sender = p2p_rnmsg->sender;
1322 memcpy (&rnmsg[1], text, msg_len);
1323 pos = client_list_head;
1326 if ((0 == strcmp (room_name, pos->room)) &&
1327 (NULL != pos->client))
1330 (0 == memcmp (&p2p_rnmsg->target,
1332 sizeof (GNUNET_HashCode)))) &&
1333 (0 == (ntohl (p2p_rnmsg->msg_options) & (~pos->msg_options))))
1335 GNUNET_SERVER_notification_context_unicast (nc,
1344 GNUNET_free (room_name);
1345 #if DEBUG_CHAT_SERVICE
1346 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1347 "Broadcasting message notification to neighbour peers\n");
1349 my_p2p_rnmsg = GNUNET_memdup (p2p_rnmsg, ntohs (p2p_rnmsg->header.size));
1350 GNUNET_CORE_iterate_peers (cfg,
1351 &send_message_noficiation,
1353 GNUNET_free (rnmsg);
1359 * Handle P2P sync request.
1361 * @param cls closure, always NULL
1362 * @param other the other peer involved
1363 * @param message the actual message
1364 * @param atsi performance information
1365 * @return GNUNET_OK to keep the connection open,
1366 * GNUNET_SYSERR to close it (signal serious error)
1369 handle_p2p_sync_request (void *cls,
1370 const struct GNUNET_PeerIdentity *other,
1371 const struct GNUNET_MessageHeader *message,
1372 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1374 struct ChatClient *entry;
1375 struct GNUNET_CORE_TransmitHandle *th;
1378 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P sync request\n");
1379 #if DEBUG_CHAT_SERVICE
1380 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1381 "Notifying the requester of all known clients\n");
1383 entry = client_list_head;
1384 while (NULL != entry)
1386 msg_size = sizeof (struct P2PJoinNotificationMessage) +
1387 strlen (entry->room) +
1389 th = GNUNET_CORE_notify_transmit_ready (core,
1394 &transmit_join_notification_to_peer,
1396 GNUNET_assert (NULL != th);
1397 entry = entry->next;
1404 * Handle P2P confirmation receipt.
1406 * @param cls closure, always NULL
1407 * @param other the other peer involved
1408 * @param message the actual message
1409 * @param atsi performance information
1410 * @return GNUNET_OK to keep the connection open,
1411 * GNUNET_SYSERR to close it (signal serious error)
1414 handle_p2p_confirmation_receipt (void *cls,
1415 const struct GNUNET_PeerIdentity *other,
1416 const struct GNUNET_MessageHeader *message,
1417 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1419 const struct P2PConfirmationReceiptMessage *p2p_crmsg;
1420 struct P2PConfirmationReceiptMessage *my_p2p_crmsg;
1421 struct ConfirmationReceiptMessage *crmsg;
1422 struct ChatClient *target;
1423 struct ChatClient *author;
1425 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P confirmation receipt\n");
1426 p2p_crmsg = (const struct P2PConfirmationReceiptMessage *) message;
1427 target = client_list_head;
1428 while ((NULL != target) &&
1429 (0 != memcmp (&target->id,
1431 sizeof (GNUNET_HashCode))))
1432 target = target->next;
1435 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1436 "Unknown source of the receipt. Rejecting the message\n");
1437 GNUNET_break_op (0);
1438 return GNUNET_SYSERR;
1440 if (target->rcpt_sequence_number >= ntohl (p2p_crmsg->sequence_number))
1442 #if DEBUG_CHAT_SERVICE
1443 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1444 "This receipt has already been handled."
1445 " Sequence numbers (msg/sender): %u/%u\n",
1446 ntohl (p2p_crmsg->sequence_number), target->rcpt_sequence_number);
1450 target->rcpt_sequence_number = ntohl (p2p_crmsg->sequence_number);
1451 author = client_list_head;
1452 while ((NULL != author) &&
1453 (0 != memcmp (&author->id,
1455 sizeof (GNUNET_HashCode))))
1456 author = author->next;
1459 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1460 "Unknown addressee. Rejecting the receipt\n");
1461 GNUNET_break_op (0);
1462 return GNUNET_SYSERR;
1465 if (NULL == author->client)
1467 #if DEBUG_CHAT_SERVICE
1468 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1469 "The author of the original message is not a local client."
1470 " Broadcasting receipt to neighbour peers\n");
1472 my_p2p_crmsg = GNUNET_memdup (p2p_crmsg, sizeof (struct P2PConfirmationReceiptMessage));
1473 GNUNET_CORE_iterate_peers (cfg,
1474 &send_confirmation_receipt,
1479 #if DEBUG_CHAT_SERVICE
1480 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1481 "The author of the original message is a local client."
1482 " Verifying signature of the receipt\n");
1484 crmsg = GNUNET_malloc (sizeof (struct ConfirmationReceiptMessage));
1485 crmsg->header.size = htons (sizeof (struct ConfirmationReceiptMessage));
1486 crmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION);
1487 crmsg->signature = p2p_crmsg->signature;
1488 crmsg->purpose = p2p_crmsg->purpose;
1489 crmsg->sequence_number = p2p_crmsg->msg_sequence_number;
1490 crmsg->reserved2 = 0;
1491 crmsg->timestamp = p2p_crmsg->timestamp;
1492 crmsg->target = p2p_crmsg->target;
1493 crmsg->author = p2p_crmsg->author;
1494 crmsg->content = p2p_crmsg->content;
1496 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_CHAT_RECEIPT,
1499 &target->public_key))
1501 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1502 "Invalid signature of the receipt\n");
1503 GNUNET_break_op (0);
1504 return GNUNET_SYSERR;
1506 #if DEBUG_CHAT_SERVICE
1507 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1508 "The author of the original message is a local client."
1509 " Sending receipt to the client\n");
1511 GNUNET_SERVER_notification_context_unicast (nc,
1515 GNUNET_free (crmsg);
1522 * Transmit a sync request to the peer.
1524 * @param cls closure, NULL
1525 * @param size number of bytes available in buf
1526 * @param buf where the callee should write the message
1527 * @return number of bytes written to buf
1530 transmit_sync_request_to_peer (void *cls,
1534 struct GNUNET_MessageHeader *m = buf;
1537 #if DEBUG_CHAT_SERVICE
1538 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting P2P sync request\n");
1540 msg_size = sizeof (struct GNUNET_MessageHeader);
1541 GNUNET_assert (size >= msg_size);
1542 GNUNET_assert (NULL != buf);
1544 m->type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_SYNC_REQUEST);
1545 m->size = htons (msg_size);
1551 * Method called whenever a peer connects.
1553 * @param cls closure
1554 * @param peer peer identity this notification is about
1555 * @param atsi performance data
1558 peer_connect_handler (void *cls,
1559 const struct GNUNET_PeerIdentity *peer,
1560 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1562 struct GNUNET_CORE_TransmitHandle *th;
1564 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1565 "Peer connected: %s\n", GNUNET_i2s (peer));
1566 if (0 == memcmp (peer, me, sizeof (struct GNUNET_PeerIdentity)))
1568 th = GNUNET_CORE_notify_transmit_ready (core,
1572 sizeof (struct GNUNET_MessageHeader),
1573 &transmit_sync_request_to_peer,
1575 GNUNET_assert (NULL != th);
1580 * Method called whenever a peer disconnects.
1582 * @param cls closure, not used
1583 * @param peer peer identity this notification is about
1586 peer_disconnect_handler (void *cls,
1587 const struct GNUNET_PeerIdentity *peer)
1589 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1590 "Peer disconnected: %s\n", GNUNET_i2s (peer));
1595 * Task run during shutdown.
1601 cleanup_task (void *cls,
1602 const struct GNUNET_SCHEDULER_TaskContext *tc)
1604 struct AnonymousMessage *next_msg;
1605 struct ChatClient *next_client;
1607 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Cleaning up\n");
1610 GNUNET_CORE_disconnect (core);
1615 GNUNET_SERVER_notification_context_destroy (nc);
1618 while (NULL != client_list_head)
1620 next_client = client_list_head->next;
1621 GNUNET_free (client_list_head->room);
1622 GNUNET_free_non_null (client_list_head->member_info);
1623 GNUNET_free (client_list_head);
1624 client_list_head = next_client;
1626 while (NULL != anonymous_list_head)
1628 next_msg = anonymous_list_head->next;
1629 GNUNET_free (anonymous_list_head);
1630 anonymous_list_head = next_msg;
1636 * To be called on core init/fail.
1638 * @param cls closure, NULL
1639 * @param server handle to the server for this service
1640 * @param my_identity the public identity of this peer
1641 * @param publicKey the public key of this peer
1644 core_init (void *cls,
1645 struct GNUNET_CORE_Handle *server,
1646 const struct GNUNET_PeerIdentity *my_identity,
1647 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey)
1649 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Core initialized\n");
1655 * Process chat requests.
1657 * @param cls closure, NULL
1658 * @param server the initialized server
1659 * @param c configuration to use
1663 struct GNUNET_SERVER_Handle *server,
1664 const struct GNUNET_CONFIGURATION_Handle *c)
1666 static const struct GNUNET_SERVER_MessageHandler handlers[] =
1668 { &handle_join_request, NULL,
1669 GNUNET_MESSAGE_TYPE_CHAT_JOIN_REQUEST, 0 },
1670 { &handle_transmit_request, NULL,
1671 GNUNET_MESSAGE_TYPE_CHAT_TRANSMIT_REQUEST, 0 },
1672 { &handle_acknowledge_request, NULL,
1673 GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_RECEIPT,
1674 sizeof (struct ConfirmationReceiptMessage) },
1675 { NULL, NULL, 0, 0 }
1677 static const struct GNUNET_CORE_MessageHandler p2p_handlers[] =
1679 { &handle_p2p_join_notification,
1680 GNUNET_MESSAGE_TYPE_CHAT_P2P_JOIN_NOTIFICATION, 0 },
1681 { &handle_p2p_leave_notification,
1682 GNUNET_MESSAGE_TYPE_CHAT_P2P_LEAVE_NOTIFICATION,
1683 sizeof (struct P2PLeaveNotificationMessage) },
1684 { &handle_p2p_message_notification,
1685 GNUNET_MESSAGE_TYPE_CHAT_P2P_MESSAGE_NOTIFICATION, 0 },
1686 { &handle_p2p_sync_request,
1687 GNUNET_MESSAGE_TYPE_CHAT_P2P_SYNC_REQUEST,
1688 sizeof (struct GNUNET_MessageHeader) },
1689 { &handle_p2p_confirmation_receipt,
1690 GNUNET_MESSAGE_TYPE_CHAT_P2P_CONFIRMATION_RECEIPT,
1691 sizeof (struct P2PConfirmationReceiptMessage) },
1695 GNUNET_log_setup ("gnunet-service-chat",
1696 #if DEBUG_CHAT_SERVICE
1703 nc = GNUNET_SERVER_notification_context_create (server, 16);
1704 GNUNET_SERVER_add_handlers (server, handlers);
1705 core = GNUNET_CORE_connect (cfg,
1709 &peer_connect_handler,
1710 &peer_disconnect_handler,
1715 GNUNET_SERVER_disconnect_notify (server,
1716 &handle_client_disconnect,
1718 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1725 * The main function for the chat service.
1727 * @param argc number of arguments from the command line
1728 * @param argv command line arguments
1729 * @return 0 ok, 1 on error
1732 main (int argc, char *const *argv)
1734 return (GNUNET_OK ==
1735 GNUNET_SERVICE_run (argc,
1738 GNUNET_SERVICE_OPTION_NONE,
1739 &run, NULL)) ? 0 : 1;
1742 /* end of gnunet-service-chat.c */