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_YES
37 #define MAX_TRANSMIT_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
42 * Linked list of our current clients.
46 struct ChatClient *next;
49 * Handle for a chat client (NULL for external clients).
51 struct GNUNET_SERVER_Client *client;
54 * Public key of the client.
56 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key;
59 * Name of the room which the client is in.
64 * Serialized metadata of the client.
69 * Hash of the public key (for convenience).
74 * Options which the client is willing to receive.
79 * Length of serialized metadata in member_info.
84 * Sequence number of the last message sent by the client.
86 uint32_t msg_sequence_number;
89 * Sequence number of the last receipt sent by the client.
90 * Used to discard already processed receipts.
92 uint32_t rcpt_sequence_number;
98 * Handle to the core service (NULL until we've connected to it).
100 static struct GNUNET_CORE_Handle *core;
105 static const struct GNUNET_CONFIGURATION_Handle *cfg;
108 * The identity of this host.
110 static const struct GNUNET_PeerIdentity *me;
113 * Head of the list of current clients.
115 static struct ChatClient *client_list_head = NULL;
118 * Notification context containing all connected clients.
120 struct GNUNET_SERVER_NotificationContext *nc = NULL;
124 * Transmit a message notification to the peer.
126 * @param cls closure, pointer to the 'struct P2PReceiveNotificationMessage'
127 * @param size number of bytes available in buf
128 * @param buf where the callee should write the message
129 * @return number of bytes written to buf
132 transmit_message_notification_to_peer (void *cls,
136 struct P2PReceiveNotificationMessage *my_msg = cls;
137 struct P2PReceiveNotificationMessage *m = buf;
140 #if DEBUG_CHAT_SERVICE
141 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
142 "Transmitting P2P message notification\n");
144 msg_size = ntohs (my_msg->header.size);
145 GNUNET_assert (size >= msg_size);
146 GNUNET_assert (NULL != buf);
147 memcpy (m, my_msg, msg_size);
148 GNUNET_free (my_msg);
154 * Ask to send a message notification to the peer.
157 send_message_noficiation (void *cls,
158 const struct GNUNET_PeerIdentity *peer,
159 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
161 struct P2PReceiveNotificationMessage *msg = cls;
162 struct P2PReceiveNotificationMessage *my_msg;
163 struct GNUNET_CORE_TransmitHandle *th;
169 #if DEBUG_CHAT_SERVICE
170 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
171 "Sending message notification to `%s'\n", GNUNET_i2s (peer));
173 my_msg = GNUNET_memdup (msg, ntohs (msg->header.size));
174 th = GNUNET_CORE_notify_transmit_ready (core,
178 ntohs (msg->header.size),
179 &transmit_message_notification_to_peer,
181 GNUNET_assert (NULL != th);
187 * A client sent a chat message. Encrypt the message text if the message is
188 * private. Send the message to local room members and to all connected peers.
190 * @param cls closure, NULL
191 * @param client identification of the client
192 * @param message the actual message
195 handle_transmit_request (void *cls,
196 struct GNUNET_SERVER_Client *client,
197 const struct GNUNET_MessageHeader *message)
199 static GNUNET_HashCode all_zeros;
200 const struct TransmitRequestMessage *trmsg;
201 struct ReceiveNotificationMessage *rnmsg;
202 struct P2PReceiveNotificationMessage *p2p_rnmsg;
203 struct ChatClient *pos;
204 struct ChatClient *target;
205 struct GNUNET_CRYPTO_AesSessionKey key;
206 char encrypted_msg[MAX_MESSAGE_LENGTH];
211 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client sent a chat message\n");
212 if (ntohs (message->size) <= sizeof (struct TransmitRequestMessage))
214 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n");
216 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
219 trmsg = (const struct TransmitRequestMessage *) message;
220 msg_len = ntohs (trmsg->header.size) - sizeof (struct TransmitRequestMessage);
221 priv_msg = (ntohl (trmsg->msg_options) & GNUNET_CHAT_MSG_PRIVATE) != 0;
224 #if DEBUG_CHAT_SERVICE
225 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypting the message text\n");
227 GNUNET_CRYPTO_aes_create_session_key (&key);
228 msg_len = GNUNET_CRYPTO_aes_encrypt (&trmsg[1],
231 (const struct GNUNET_CRYPTO_AesInitializationVector *) INITVALUE,
235 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
236 "Could not encrypt the message text\n");
238 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
242 rnmsg = GNUNET_malloc (sizeof (struct ReceiveNotificationMessage) + msg_len);
243 rnmsg->header.size = htons (sizeof (struct ReceiveNotificationMessage) +
245 rnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION);
246 rnmsg->msg_options = trmsg->msg_options;
247 rnmsg->sequence_number = trmsg->sequence_number;
248 pos = client_list_head;
249 while ((NULL != pos) && (pos->client != client))
253 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
254 "The client is not a member of a chat room. Client has to "
255 "join a chat room first\n");
257 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
262 pos->msg_sequence_number = ntohl (trmsg->sequence_number);
263 if (0 == (ntohl (trmsg->msg_options) & GNUNET_CHAT_MSG_ANONYMOUS))
264 rnmsg->sender = pos->id;
266 memset (&rnmsg->sender, 0, sizeof (GNUNET_HashCode));
269 #if DEBUG_CHAT_SERVICE
270 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
271 "Encrypting the session key using the public key of '%s'\n",
272 GNUNET_h2s (&trmsg->target));
274 if (0 == memcmp (&all_zeros, &trmsg->target, sizeof (GNUNET_HashCode)))
276 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
277 "Malformed message: private, but no target\n");
279 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
283 memcpy (&rnmsg[1], encrypted_msg, msg_len);
284 target = client_list_head;
285 while ((NULL != target) &&
286 (0 != memcmp (&target->id,
288 sizeof (GNUNET_HashCode))))
289 target = target->next;
292 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
293 "Unknown target of the private message\n");
295 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
299 if (GNUNET_SYSERR == GNUNET_CRYPTO_rsa_encrypt (&key,
300 sizeof (struct GNUNET_CRYPTO_AesSessionKey),
302 &rnmsg->encrypted_key))
304 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
305 "Could not encrypt the session key\n");
307 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
314 memcpy (&rnmsg[1], &trmsg[1], msg_len);
316 pos = client_list_head;
317 #if DEBUG_CHAT_SERVICE
318 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message to local room members\n");
322 if ((0 == strcmp (room, pos->room)) &&
323 (NULL != pos->client) &&
324 (pos->client != client))
327 (0 == memcmp (&trmsg->target,
329 sizeof (GNUNET_HashCode)))) &&
330 (0 == (ntohl (trmsg->msg_options) & (~pos->msg_options))))
332 GNUNET_SERVER_notification_context_unicast (nc,
340 #if DEBUG_CHAT_SERVICE
341 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
342 "Broadcasting message to neighbour peers\n");
344 p2p_rnmsg = GNUNET_malloc (sizeof (struct P2PReceiveNotificationMessage) +
346 p2p_rnmsg->header.size = htons (sizeof (struct P2PReceiveNotificationMessage) +
348 p2p_rnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_MESSAGE_NOTIFICATION);
349 p2p_rnmsg->msg_options = trmsg->msg_options;
350 p2p_rnmsg->sequence_number = trmsg->sequence_number;
351 memcpy (&p2p_rnmsg->sender, &rnmsg->sender, sizeof (GNUNET_HashCode));
352 p2p_rnmsg->target = trmsg->target;
355 memcpy (&p2p_rnmsg[1], encrypted_msg, msg_len);
356 memcpy (&p2p_rnmsg->encrypted_key,
357 &rnmsg->encrypted_key,
358 sizeof (struct GNUNET_CRYPTO_RsaEncryptedData));
362 memcpy (&p2p_rnmsg[1], &trmsg[1], msg_len);
364 GNUNET_CORE_iterate_peers (cfg,
365 &send_message_noficiation,
367 GNUNET_SERVER_receive_done (client, GNUNET_OK);
373 * Transmit a join notification to the peer.
375 * @param cls closure, pointer to the 'struct ChatClient'
376 * @param size number of bytes available in buf
377 * @param buf where the callee should write the message
378 * @return number of bytes written to buf
381 transmit_join_notification_to_peer (void *cls,
385 struct ChatClient *entry = cls;
386 struct P2PJoinNotificationMessage *m = buf;
392 #if DEBUG_CHAT_SERVICE
393 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
394 "Transmitting P2P join notification\n");
396 room_len = strlen (entry->room);
397 meta_len = entry->meta_len;
398 msg_size = sizeof (struct P2PJoinNotificationMessage) + meta_len + room_len;
399 GNUNET_assert (size >= msg_size);
400 GNUNET_assert (NULL != buf);
402 m->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_JOIN_NOTIFICATION);
403 m->header.size = htons (msg_size);
404 m->msg_options = htonl (entry->msg_options);
405 m->room_name_len = htons (room_len);
406 m->reserved = htons (0);
407 m->public_key = entry->public_key;
408 roomptr = (char *) &m[1];
409 memcpy (roomptr, entry->room, room_len);
411 memcpy (&roomptr[room_len], entry->member_info, meta_len);
417 * Ask to send a join notification to the peer.
420 send_join_noficiation (void *cls,
421 const struct GNUNET_PeerIdentity *peer,
422 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
424 struct ChatClient *entry = cls;
425 struct GNUNET_CORE_TransmitHandle *th;
430 #if DEBUG_CHAT_SERVICE
431 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
432 "Sending join notification to `%s'\n", GNUNET_i2s (peer));
434 msg_size = sizeof (struct P2PJoinNotificationMessage) +
435 strlen (entry->room) +
437 th = GNUNET_CORE_notify_transmit_ready (core,
442 &transmit_join_notification_to_peer,
444 GNUNET_assert (NULL != th);
450 * A client asked for entering a chat room. Add the new member to the list of
451 * clients and notify remaining room members.
453 * @param cls closure, NULL
454 * @param client identification of the client
455 * @param message the actual message
458 handle_join_request (void *cls,
459 struct GNUNET_SERVER_Client *client,
460 const struct GNUNET_MessageHeader *message)
462 const struct JoinRequestMessage *jrmsg;
465 uint16_t header_size;
467 uint16_t room_name_len;
468 struct ChatClient *new_entry;
469 struct ChatClient *entry;
470 struct JoinNotificationMessage *jnmsg;
471 struct JoinNotificationMessage *entry_jnmsg;
473 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client sent a join request\n");
474 if (ntohs (message->size) <= sizeof (struct JoinRequestMessage))
476 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n");
478 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
481 jrmsg = (const struct JoinRequestMessage *) message;
482 header_size = ntohs (jrmsg->header.size);
483 room_name_len = ntohs (jrmsg->room_name_len);
484 if (header_size - sizeof (struct JoinRequestMessage) <=
487 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
488 "Malformed message: wrong length of the room name\n");
490 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
494 header_size - sizeof (struct JoinRequestMessage) - room_name_len;
495 roomptr = (const char *) &jrmsg[1];
496 room_name = GNUNET_malloc (room_name_len + 1);
497 memcpy (room_name, roomptr, room_name_len);
498 room_name[room_name_len] = '\0';
499 new_entry = GNUNET_malloc (sizeof (struct ChatClient));
500 memset (new_entry, 0, sizeof (struct ChatClient));
501 new_entry->client = client;
502 new_entry->room = room_name;
503 new_entry->public_key = jrmsg->public_key;
504 new_entry->meta_len = meta_len;
507 new_entry->member_info = GNUNET_malloc (meta_len);
508 memcpy (new_entry->member_info, &roomptr[room_name_len], meta_len);
511 new_entry->member_info = NULL;
512 GNUNET_CRYPTO_hash (&new_entry->public_key,
513 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
515 new_entry->msg_options = ntohl (jrmsg->msg_options);
516 new_entry->next = client_list_head;
517 client_list_head = new_entry;
518 #if DEBUG_CHAT_SERVICE
519 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
520 "Synchronizing room members between local clients\n");
522 jnmsg = GNUNET_malloc (sizeof (struct JoinNotificationMessage) + meta_len);
523 jnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION);
525 htons (sizeof (struct JoinNotificationMessage) + meta_len);
526 jnmsg->msg_options = jrmsg->msg_options;
527 jnmsg->public_key = new_entry->public_key;
528 memcpy (&jnmsg[1], &roomptr[room_name_len], meta_len);
529 GNUNET_SERVER_notification_context_add (nc, client);
530 entry = client_list_head;
531 while (NULL != entry)
533 if (0 == strcmp (room_name, entry->room))
535 if (NULL != entry->client)
536 GNUNET_SERVER_notification_context_unicast (nc,
540 if (entry->client != client)
543 GNUNET_malloc (sizeof (struct JoinNotificationMessage) +
545 entry_jnmsg->header.type =
546 htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION);
547 entry_jnmsg->header.size =
548 htons (sizeof (struct JoinNotificationMessage) +
550 entry_jnmsg->msg_options = entry->msg_options;
551 entry_jnmsg->public_key = entry->public_key;
552 memcpy (&entry_jnmsg[1], entry->member_info, entry->meta_len);
553 GNUNET_SERVER_notification_context_unicast (nc,
555 &entry_jnmsg->header,
557 GNUNET_free (entry_jnmsg);
562 #if DEBUG_CHAT_SERVICE
563 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
564 "Broadcasting join notification to neighbour peers\n");
566 GNUNET_CORE_iterate_peers (cfg,
567 &send_join_noficiation,
569 GNUNET_SERVER_receive_done (client, GNUNET_OK);
574 * Transmit a confirmation receipt to the peer.
576 * @param cls closure, pointer to the 'struct P2PConfirmationReceiptMessage'
577 * @param size number of bytes available in buf
578 * @param buf where the callee should write the message
579 * @return number of bytes written to buf
582 transmit_confirmation_receipt_to_peer (void *cls,
586 struct P2PConfirmationReceiptMessage *receipt = cls;
589 #if DEBUG_CHAT_SERVICE
590 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
591 "Transmitting P2P confirmation receipt to '%s'\n",
592 GNUNET_h2s (&receipt->target));
594 msg_size = sizeof (struct P2PConfirmationReceiptMessage);
595 GNUNET_assert (size >= msg_size);
596 GNUNET_assert (NULL != buf);
597 memcpy (buf, receipt, msg_size);
598 GNUNET_free (receipt);
604 * Ask to send a confirmation receipt to the peer.
607 send_confirmation_receipt (void *cls,
608 const struct GNUNET_PeerIdentity *peer,
609 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
611 struct P2PConfirmationReceiptMessage *receipt = cls;
612 struct P2PConfirmationReceiptMessage *my_receipt;
613 struct GNUNET_CORE_TransmitHandle *th;
617 GNUNET_free (receipt);
620 #if DEBUG_CHAT_SERVICE
621 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
622 "Sending confirmation receipt to `%s'\n", GNUNET_i2s (peer));
624 msg_size = sizeof (struct P2PConfirmationReceiptMessage);
625 my_receipt = GNUNET_memdup (receipt,
626 sizeof (struct P2PConfirmationReceiptMessage));
627 th = GNUNET_CORE_notify_transmit_ready (core,
632 &transmit_confirmation_receipt_to_peer,
634 GNUNET_assert (NULL != th);
640 * A client sent a confirmation receipt. Broadcast the receipt to all connected
641 * peers if the author of the original message is a local client. Otherwise
642 * check the signature and notify the user if the signature is valid.
644 * @param cls closure, NULL
645 * @param client identification of the client
646 * @param message the actual message
649 handle_acknowledge_request (void *cls,
650 struct GNUNET_SERVER_Client *client,
651 const struct GNUNET_MessageHeader *message)
653 const struct ConfirmationReceiptMessage *receipt;
654 struct ConfirmationReceiptMessage *crmsg;
655 struct P2PConfirmationReceiptMessage *p2p_crmsg;
656 struct ChatClient *target;
657 struct ChatClient *author;
659 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client sent a confirmation receipt\n");
660 receipt = (const struct ConfirmationReceiptMessage *) message;
661 author = client_list_head;
662 while ((NULL != author) &&
663 (0 != memcmp (&receipt->author,
665 sizeof (GNUNET_HashCode))))
666 author = author->next;
669 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
670 "Unknown author of the original message\n");
672 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
675 target = client_list_head;
676 while ((NULL != target) &&
677 (0 != memcmp (&receipt->target,
679 sizeof (GNUNET_HashCode))))
680 target = target->next;
683 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
684 "Unknown target of the confirmation receipt\n");
686 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
689 if (NULL == author->client)
691 target->rcpt_sequence_number++;
692 #if DEBUG_CHAT_SERVICE
693 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
694 "Broadcasting %s's receipt #%u to neighbour peers\n",
695 GNUNET_h2s (&target->id), target->rcpt_sequence_number);
697 p2p_crmsg = GNUNET_malloc (sizeof (struct P2PConfirmationReceiptMessage));
698 p2p_crmsg->header.size = htons (sizeof (struct P2PConfirmationReceiptMessage));
699 p2p_crmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_CONFIRMATION_RECEIPT);
700 p2p_crmsg->signature = receipt->signature;
701 p2p_crmsg->purpose = receipt->purpose;
702 p2p_crmsg->msg_sequence_number = receipt->sequence_number;
703 p2p_crmsg->timestamp = receipt->timestamp;
704 p2p_crmsg->target = receipt->target;
705 p2p_crmsg->author = receipt->author;
706 p2p_crmsg->content = receipt->content;
707 p2p_crmsg->sequence_number = htonl (target->rcpt_sequence_number);
708 GNUNET_CORE_iterate_peers (cfg,
709 &send_confirmation_receipt,
714 #if DEBUG_CHAT_SERVICE
715 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
716 "Verifying signature of the receipt\n");
719 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_CHAT_RECEIPT,
722 &target->public_key))
724 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
725 "Invalid signature of the receipt\n");
727 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
730 #if DEBUG_CHAT_SERVICE
731 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
732 "Sending receipt to the client which sent the original message\n");
734 crmsg = GNUNET_memdup (receipt, sizeof (struct ConfirmationReceiptMessage));
735 crmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION);
736 GNUNET_SERVER_notification_context_unicast (nc,
742 GNUNET_SERVER_receive_done (client, GNUNET_OK);
747 * Transmit a leave notification to the peer.
749 * @param cls closure, pointer to the
750 * 'struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded'
751 * @param size number of bytes available in buf
752 * @param buf where the callee should write the message
753 * @return number of bytes written to buf
756 transmit_leave_notification_to_peer (void *cls,
760 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key = cls;
761 struct P2PLeaveNotificationMessage *m = buf;
764 #if DEBUG_CHAT_SERVICE
765 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
766 "Transmitting P2P leave notification\n");
768 msg_size = sizeof (struct P2PLeaveNotificationMessage);
769 GNUNET_assert (size >= msg_size);
770 GNUNET_assert (NULL != buf);
772 m->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_LEAVE_NOTIFICATION);
773 m->header.size = htons (msg_size);
774 m->reserved = htons (0);
775 m->user = *public_key;
776 GNUNET_free (public_key);
782 * Ask to send a leave notification to the peer.
785 send_leave_noficiation (void *cls,
786 const struct GNUNET_PeerIdentity *peer,
787 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
789 struct ChatClient *entry = cls;
790 struct GNUNET_CORE_TransmitHandle *th;
791 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key;
796 GNUNET_free (entry->room);
797 GNUNET_free_non_null (entry->member_info);
802 #if DEBUG_CHAT_SERVICE
803 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
804 "Sending leave notification to `%s'\n", GNUNET_i2s (peer));
806 msg_size = sizeof (struct P2PLeaveNotificationMessage);
807 public_key = GNUNET_memdup (&entry->public_key,
808 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
809 th = GNUNET_CORE_notify_transmit_ready (core,
814 &transmit_leave_notification_to_peer,
816 GNUNET_assert (NULL != th);
822 * A client disconnected. Remove all of its data structure entries and notify
823 * remaining room members.
825 * @param cls closure, NULL
826 * @param client identification of the client
829 handle_client_disconnect (void *cls,
830 struct GNUNET_SERVER_Client *client)
832 struct ChatClient *entry;
833 struct ChatClient *pos;
834 struct ChatClient *prev;
835 struct LeaveNotificationMessage lnmsg;
837 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client disconnected\n");
838 pos = client_list_head;
840 while ((NULL != pos) && (pos->client != client))
847 #if DEBUG_CHAT_SERVICE
848 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
849 "No such client. There is nothing to do\n");
854 client_list_head = pos->next;
856 prev->next = pos->next;
857 entry = client_list_head;
858 #if DEBUG_CHAT_SERVICE
859 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
860 "Notifying local room members that the client has disconnected\n");
862 lnmsg.header.size = htons (sizeof (struct LeaveNotificationMessage));
863 lnmsg.header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION);
864 lnmsg.reserved = htonl (0);
865 lnmsg.user = pos->public_key;
866 while (NULL != entry)
868 if ((0 == strcmp (pos->room, entry->room)) &&
869 (NULL != entry->client))
871 GNUNET_SERVER_notification_context_unicast (nc,
878 #if DEBUG_CHAT_SERVICE
879 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
880 "Broadcasting leave notification to neighbour peers\n");
882 GNUNET_CORE_iterate_peers (cfg,
883 &send_leave_noficiation,
889 * Handle P2P join notification.
891 * @param cls closure, always NULL
892 * @param other the other peer involved
893 * @param message the actual message
894 * @param atsi performance information
895 * @return GNUNET_OK to keep the connection open,
896 * GNUNET_SYSERR to close it (signal serious error)
899 handle_p2p_join_notification (void *cls,
900 const struct GNUNET_PeerIdentity *other,
901 const struct GNUNET_MessageHeader *message,
902 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
904 const struct P2PJoinNotificationMessage *p2p_jnmsg;
907 uint16_t header_size;
909 uint16_t room_name_len;
910 struct ChatClient *new_entry;
911 struct ChatClient *entry;
912 struct JoinNotificationMessage *jnmsg;
915 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P join notification\n");
916 if (ntohs (message->size) <= sizeof (struct P2PJoinNotificationMessage))
918 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n");
920 return GNUNET_SYSERR;
922 p2p_jnmsg = (const struct P2PJoinNotificationMessage *) message;
923 header_size = ntohs (p2p_jnmsg->header.size);
924 room_name_len = ntohs (p2p_jnmsg->room_name_len);
925 if (header_size - sizeof (struct P2PJoinNotificationMessage) <=
928 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
929 "Malformed message: wrong length of the room name\n");
931 return GNUNET_SYSERR;
933 GNUNET_CRYPTO_hash (&p2p_jnmsg->public_key,
934 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
936 entry = client_list_head;
937 while (NULL != entry)
939 if (0 == memcmp (&entry->id, &id, sizeof (GNUNET_HashCode)))
941 #if DEBUG_CHAT_SERVICE
942 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
943 "The client has already joined. There is nothing to do\n");
950 header_size - sizeof (struct P2PJoinNotificationMessage) - room_name_len;
951 roomptr = (const char *) &p2p_jnmsg[1];
952 room_name = GNUNET_malloc (room_name_len + 1);
953 memcpy (room_name, roomptr, room_name_len);
954 room_name[room_name_len] = '\0';
955 new_entry = GNUNET_malloc (sizeof (struct ChatClient));
956 memset (new_entry, 0, sizeof (struct ChatClient));
958 new_entry->client = NULL;
959 new_entry->room = room_name;
960 new_entry->public_key = p2p_jnmsg->public_key;
961 new_entry->meta_len = meta_len;
964 new_entry->member_info = GNUNET_malloc (meta_len);
965 memcpy (new_entry->member_info, &roomptr[room_name_len], meta_len);
968 new_entry->member_info = NULL;
969 new_entry->msg_options = ntohl (p2p_jnmsg->msg_options);
970 new_entry->next = client_list_head;
971 client_list_head = new_entry;
972 #if DEBUG_CHAT_SERVICE
973 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
974 "Notifying local room members that we have a new client\n");
976 jnmsg = GNUNET_malloc (sizeof (struct JoinNotificationMessage) + meta_len);
977 jnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION);
979 htons (sizeof (struct JoinNotificationMessage) + meta_len);
980 jnmsg->msg_options = p2p_jnmsg->msg_options;
981 jnmsg->public_key = new_entry->public_key;
982 memcpy (&jnmsg[1], &roomptr[room_name_len], meta_len);
983 entry = client_list_head;
984 while (NULL != entry)
986 if ((0 == strcmp (room_name, entry->room)) &&
987 (NULL != entry->client))
989 GNUNET_SERVER_notification_context_unicast (nc,
996 #if DEBUG_CHAT_SERVICE
997 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
998 "Broadcasting join notification to neighbour peers\n");
1000 GNUNET_CORE_iterate_peers (cfg,
1001 &send_join_noficiation,
1003 GNUNET_free (jnmsg);
1009 * Handle P2P leave notification.
1011 * @param cls closure, always NULL
1012 * @param other the other peer involved
1013 * @param message the actual message
1014 * @param atsi performance information
1015 * @return GNUNET_OK to keep the connection open,
1016 * GNUNET_SYSERR to close it (signal serious error)
1019 handle_p2p_leave_notification (void *cls,
1020 const struct GNUNET_PeerIdentity *other,
1021 const struct GNUNET_MessageHeader *message,
1022 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1024 const struct P2PLeaveNotificationMessage *p2p_lnmsg;
1026 struct ChatClient *pos;
1027 struct ChatClient *prev;
1028 struct ChatClient *entry;
1029 struct LeaveNotificationMessage lnmsg;
1031 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P leave notification\n");
1032 p2p_lnmsg = (const struct P2PLeaveNotificationMessage *) message;
1033 GNUNET_CRYPTO_hash (&p2p_lnmsg->user,
1034 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1036 pos = client_list_head;
1040 if (0 == memcmp (&pos->id, &id, sizeof (GNUNET_HashCode)))
1047 #if DEBUG_CHAT_SERVICE
1048 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1049 "No such client. There is nothing to do\n");
1054 client_list_head = pos->next;
1056 prev->next = pos->next;
1057 #if DEBUG_CHAT_SERVICE
1058 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1059 "Notifying local room members that the client has gone away\n");
1061 lnmsg.header.size = htons (sizeof (struct LeaveNotificationMessage));
1062 lnmsg.header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION);
1063 lnmsg.reserved = htonl (0);
1064 lnmsg.user = pos->public_key;
1065 entry = client_list_head;
1066 while (NULL != entry)
1068 if (0 == strcmp (pos->room, entry->room) &&
1069 (NULL != entry->client))
1071 GNUNET_SERVER_notification_context_unicast (nc,
1076 entry = entry->next;
1078 #if DEBUG_CHAT_SERVICE
1079 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1080 "Broadcasting leave notification to neighbour peers\n");
1082 GNUNET_CORE_iterate_peers (cfg,
1083 &send_leave_noficiation,
1090 * Handle P2P message notification.
1092 * @param cls closure, always NULL
1093 * @param other the other peer involved
1094 * @param message the actual message
1095 * @param atsi performance information
1096 * @return GNUNET_OK to keep the connection open,
1097 * GNUNET_SYSERR to close it (signal serious error)
1100 handle_p2p_message_notification (void *cls,
1101 const struct GNUNET_PeerIdentity *other,
1102 const struct GNUNET_MessageHeader *message,
1103 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1105 const struct P2PReceiveNotificationMessage *p2p_rnmsg;
1106 struct P2PReceiveNotificationMessage *my_p2p_rnmsg;
1107 struct ReceiveNotificationMessage *rnmsg;
1108 struct ChatClient *sender;
1109 struct ChatClient *pos;
1110 static GNUNET_HashCode all_zeros;
1114 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P message notification\n");
1115 if (ntohs (message->size) <= sizeof (struct P2PReceiveNotificationMessage))
1117 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n");
1118 GNUNET_break_op (0);
1119 return GNUNET_SYSERR;
1121 p2p_rnmsg = (const struct P2PReceiveNotificationMessage *) message;
1122 sender = client_list_head;
1123 while ((NULL != sender) &&
1124 (0 != memcmp (&sender->id,
1126 sizeof (GNUNET_HashCode))))
1127 sender = sender->next;
1130 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1131 "Unknown source. Rejecting the message\n");
1132 GNUNET_break_op (0);
1133 return GNUNET_SYSERR;
1135 if (sender->msg_sequence_number >= ntohl (p2p_rnmsg->sequence_number))
1137 #if DEBUG_CHAT_SERVICE
1138 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1139 "This message has already been handled."
1140 " Sequence numbers (msg/sender): %u/%u\n",
1141 ntohl (p2p_rnmsg->sequence_number), sender->msg_sequence_number);
1145 sender->msg_sequence_number = ntohl (p2p_rnmsg->sequence_number);
1146 msg_len = ntohs (p2p_rnmsg->header.size) -
1147 sizeof (struct P2PReceiveNotificationMessage);
1148 #if DEBUG_CHAT_SERVICE
1149 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message to local room members\n");
1151 rnmsg = GNUNET_malloc (sizeof (struct ReceiveNotificationMessage) + msg_len);
1152 rnmsg->header.size = htons (sizeof (struct ReceiveNotificationMessage) +
1154 rnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION);
1155 rnmsg->msg_options = p2p_rnmsg->msg_options;
1156 rnmsg->sequence_number = p2p_rnmsg->sequence_number;
1157 priv_msg = (0 != memcmp (&all_zeros,
1158 &p2p_rnmsg->target, sizeof (GNUNET_HashCode)));
1160 memcpy (&rnmsg->encrypted_key,
1161 &p2p_rnmsg->encrypted_key,
1162 sizeof (struct GNUNET_CRYPTO_RsaEncryptedData));
1163 memcpy (&rnmsg->sender, &p2p_rnmsg->sender, sizeof (GNUNET_HashCode));
1164 memcpy (&rnmsg[1], &p2p_rnmsg[1], msg_len);
1165 pos = client_list_head;
1168 if ((0 == strcmp (sender->room, pos->room)) &&
1169 (NULL != pos->client))
1172 (0 == memcmp (&p2p_rnmsg->target,
1174 sizeof (GNUNET_HashCode)))) &&
1175 (0 == (ntohl (p2p_rnmsg->msg_options) & (~pos->msg_options))))
1177 GNUNET_SERVER_notification_context_unicast (nc,
1185 #if DEBUG_CHAT_SERVICE
1186 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1187 "Broadcasting message notification to neighbour peers\n");
1189 my_p2p_rnmsg = GNUNET_memdup (p2p_rnmsg, ntohs (p2p_rnmsg->header.size));
1190 GNUNET_CORE_iterate_peers (cfg,
1191 &send_message_noficiation,
1193 GNUNET_free (rnmsg);
1199 * Handle P2P sync request.
1201 * @param cls closure, always NULL
1202 * @param other the other peer involved
1203 * @param message the actual message
1204 * @param atsi performance information
1205 * @return GNUNET_OK to keep the connection open,
1206 * GNUNET_SYSERR to close it (signal serious error)
1209 handle_p2p_sync_request (void *cls,
1210 const struct GNUNET_PeerIdentity *other,
1211 const struct GNUNET_MessageHeader *message,
1212 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1214 struct ChatClient *entry;
1215 struct GNUNET_CORE_TransmitHandle *th;
1218 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P sync request\n");
1219 #if DEBUG_CHAT_SERVICE
1220 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1221 "Notifying the requester of all known clients\n");
1223 entry = client_list_head;
1224 while (NULL != entry)
1226 msg_size = sizeof (struct P2PJoinNotificationMessage) +
1227 strlen (entry->room) +
1229 th = GNUNET_CORE_notify_transmit_ready (core,
1234 &transmit_join_notification_to_peer,
1236 GNUNET_assert (NULL != th);
1237 entry = entry->next;
1244 * Handle P2P confirmation receipt.
1246 * @param cls closure, always NULL
1247 * @param other the other peer involved
1248 * @param message the actual message
1249 * @param atsi performance information
1250 * @return GNUNET_OK to keep the connection open,
1251 * GNUNET_SYSERR to close it (signal serious error)
1254 handle_p2p_confirmation_receipt (void *cls,
1255 const struct GNUNET_PeerIdentity *other,
1256 const struct GNUNET_MessageHeader *message,
1257 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1259 const struct P2PConfirmationReceiptMessage *p2p_crmsg;
1260 struct P2PConfirmationReceiptMessage *my_p2p_crmsg;
1261 struct ConfirmationReceiptMessage *crmsg;
1262 struct ChatClient *target;
1263 struct ChatClient *author;
1265 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P confirmation receipt\n");
1266 p2p_crmsg = (const struct P2PConfirmationReceiptMessage *) message;
1267 target = client_list_head;
1268 while ((NULL != target) &&
1269 (0 != memcmp (&target->id,
1271 sizeof (GNUNET_HashCode))))
1272 target = target->next;
1275 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1276 "Unknown source of the receipt. Rejecting the message\n");
1277 GNUNET_break_op (0);
1278 return GNUNET_SYSERR;
1280 if (target->rcpt_sequence_number >= ntohl (p2p_crmsg->sequence_number))
1282 #if DEBUG_CHAT_SERVICE
1283 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1284 "This receipt has already been handled."
1285 " Sequence numbers (msg/sender): %u/%u\n",
1286 ntohl (p2p_crmsg->sequence_number), target->rcpt_sequence_number);
1290 target->rcpt_sequence_number = ntohl (p2p_crmsg->sequence_number);
1291 author = client_list_head;
1292 while ((NULL != author) &&
1293 (0 != memcmp (&author->id,
1295 sizeof (GNUNET_HashCode))))
1296 author = author->next;
1299 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1300 "Unknown addressee. Rejecting the receipt\n");
1301 GNUNET_break_op (0);
1302 return GNUNET_SYSERR;
1305 if (NULL == author->client)
1307 #if DEBUG_CHAT_SERVICE
1308 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1309 "The author of the original message is not a local client."
1310 " Broadcasting receipt to neighbour peers\n");
1312 my_p2p_crmsg = GNUNET_memdup (p2p_crmsg, sizeof (struct P2PConfirmationReceiptMessage));
1313 GNUNET_CORE_iterate_peers (cfg,
1314 &send_confirmation_receipt,
1319 #if DEBUG_CHAT_SERVICE
1320 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1321 "The author of the original message is a local client."
1322 " Verifying signature of the receipt\n");
1324 crmsg = GNUNET_malloc (sizeof (struct ConfirmationReceiptMessage));
1325 crmsg->header.size = htons (sizeof (struct ConfirmationReceiptMessage));
1326 crmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION);
1327 crmsg->signature = p2p_crmsg->signature;
1328 crmsg->purpose = p2p_crmsg->purpose;
1329 crmsg->sequence_number = p2p_crmsg->msg_sequence_number;
1330 crmsg->reserved2 = 0;
1331 crmsg->timestamp = p2p_crmsg->timestamp;
1332 crmsg->target = p2p_crmsg->target;
1333 crmsg->author = p2p_crmsg->author;
1334 crmsg->content = p2p_crmsg->content;
1336 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_CHAT_RECEIPT,
1339 &target->public_key))
1341 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1342 "Invalid signature of the receipt\n");
1343 GNUNET_break_op (0);
1344 return GNUNET_SYSERR;
1346 #if DEBUG_CHAT_SERVICE
1347 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1348 "The author of the original message is a local client."
1349 " Sending receipt to the client\n");
1351 GNUNET_SERVER_notification_context_unicast (nc,
1355 GNUNET_free (crmsg);
1362 * Transmit a sync request to the peer.
1364 * @param cls closure, NULL
1365 * @param size number of bytes available in buf
1366 * @param buf where the callee should write the message
1367 * @return number of bytes written to buf
1370 transmit_sync_request_to_peer (void *cls,
1374 struct GNUNET_MessageHeader *m = buf;
1377 #if DEBUG_CHAT_SERVICE
1378 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting P2P sync request\n");
1380 msg_size = sizeof (struct GNUNET_MessageHeader);
1381 GNUNET_assert (size >= msg_size);
1382 GNUNET_assert (NULL != buf);
1384 m->type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_SYNC_REQUEST);
1385 m->size = htons (msg_size);
1391 * Method called whenever a peer connects.
1393 * @param cls closure
1394 * @param peer peer identity this notification is about
1395 * @param atsi performance data
1398 peer_connect_handler (void *cls,
1399 const struct GNUNET_PeerIdentity *peer,
1400 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
1402 struct GNUNET_CORE_TransmitHandle *th;
1404 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1405 "Peer connected: %s\n", GNUNET_i2s (peer));
1406 if (0 == memcmp (peer, me, sizeof (struct GNUNET_PeerIdentity)))
1408 th = GNUNET_CORE_notify_transmit_ready (core,
1412 sizeof (struct GNUNET_MessageHeader),
1413 &transmit_sync_request_to_peer,
1415 GNUNET_assert (NULL != th);
1420 * Method called whenever a peer disconnects.
1422 * @param cls closure, not used
1423 * @param peer peer identity this notification is about
1426 peer_disconnect_handler (void *cls,
1427 const struct GNUNET_PeerIdentity *peer)
1429 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1430 "Peer disconnected: %s\n", GNUNET_i2s (peer));
1435 * Task run during shutdown.
1441 cleanup_task (void *cls,
1442 const struct GNUNET_SCHEDULER_TaskContext *tc)
1444 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Cleaning up\n");
1447 GNUNET_CORE_disconnect (core);
1452 GNUNET_SERVER_notification_context_destroy (nc);
1459 * To be called on core init/fail.
1461 * @param cls closure, NULL
1462 * @param server handle to the server for this service
1463 * @param my_identity the public identity of this peer
1464 * @param publicKey the public key of this peer
1467 core_init (void *cls,
1468 struct GNUNET_CORE_Handle *server,
1469 const struct GNUNET_PeerIdentity *my_identity,
1470 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey)
1472 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Core initialized\n");
1478 * Process chat requests.
1480 * @param cls closure, NULL
1481 * @param server the initialized server
1482 * @param c configuration to use
1486 struct GNUNET_SERVER_Handle *server,
1487 const struct GNUNET_CONFIGURATION_Handle *c)
1489 static const struct GNUNET_SERVER_MessageHandler handlers[] =
1491 { &handle_join_request, NULL,
1492 GNUNET_MESSAGE_TYPE_CHAT_JOIN_REQUEST, 0 },
1493 { &handle_transmit_request, NULL,
1494 GNUNET_MESSAGE_TYPE_CHAT_TRANSMIT_REQUEST, 0 },
1495 { &handle_acknowledge_request, NULL,
1496 GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_RECEIPT,
1497 sizeof (struct ConfirmationReceiptMessage) },
1498 { NULL, NULL, 0, 0 }
1500 static const struct GNUNET_CORE_MessageHandler p2p_handlers[] =
1502 { &handle_p2p_join_notification,
1503 GNUNET_MESSAGE_TYPE_CHAT_P2P_JOIN_NOTIFICATION, 0 },
1504 { &handle_p2p_leave_notification,
1505 GNUNET_MESSAGE_TYPE_CHAT_P2P_LEAVE_NOTIFICATION,
1506 sizeof (struct P2PLeaveNotificationMessage) },
1507 { &handle_p2p_message_notification,
1508 GNUNET_MESSAGE_TYPE_CHAT_P2P_MESSAGE_NOTIFICATION, 0 },
1509 { &handle_p2p_sync_request,
1510 GNUNET_MESSAGE_TYPE_CHAT_P2P_SYNC_REQUEST,
1511 sizeof (struct GNUNET_MessageHeader) },
1512 { &handle_p2p_confirmation_receipt,
1513 GNUNET_MESSAGE_TYPE_CHAT_P2P_CONFIRMATION_RECEIPT,
1514 sizeof (struct P2PConfirmationReceiptMessage) },
1518 GNUNET_log_setup ("gnunet-service-chat",
1519 #if DEBUG_CHAT_SERVICE
1526 nc = GNUNET_SERVER_notification_context_create (server, 16);
1527 GNUNET_SERVER_add_handlers (server, handlers);
1528 core = GNUNET_CORE_connect (cfg,
1532 &peer_connect_handler,
1533 &peer_disconnect_handler,
1538 GNUNET_SERVER_disconnect_notify (server,
1539 &handle_client_disconnect,
1541 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1548 * The main function for the chat service.
1550 * @param argc number of arguments from the command line
1551 * @param argv command line arguments
1552 * @return 0 ok, 1 on error
1555 main (int argc, char *const *argv)
1557 return (GNUNET_OK ==
1558 GNUNET_SERVICE_run (argc,
1561 GNUNET_SERVICE_OPTION_NONE,
1562 &run, NULL)) ? 0 : 1;
1565 /* end of gnunet-service-chat.c */