2 This file is part of GNUnet
3 (C) 2013 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 2, 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 set/gnunet-service-set.c
23 * @brief two-peer set operations
24 * @author Florian Dold
28 #include "gnunet-service-set.h"
29 #include "set_protocol.h"
33 * Configuration of our local peer.
35 const struct GNUNET_CONFIGURATION_Handle *configuration;
38 * Socket listening for other peers via stream.
40 static struct GNUNET_STREAM_ListenSocket *stream_listen_socket;
43 * Sets are held in a doubly linked list.
45 static struct Set *sets_head;
48 * Sets are held in a doubly linked list.
50 static struct Set *sets_tail;
53 * Listeners are held in a doubly linked list.
55 static struct Listener *listeners_head;
58 * Listeners are held in a doubly linked list.
60 static struct Listener *listeners_tail;
63 * Incoming sockets from remote peers are
64 * held in a doubly linked list.
66 static struct Incoming *incoming_head;
69 * Incoming sockets from remote peers are
70 * held in a doubly linked list.
72 static struct Incoming *incoming_tail;
75 * Counter for allocating unique request IDs for clients.
77 static uint32_t request_id = 1;
81 * Disconnect a client and free all resources
82 * that the client allocated (e.g. Sets or Listeners)
84 * @param client the client to disconnect
87 client_disconnect (struct GNUNET_SERVER_Client *client)
89 /* FIXME: clean up any data structures belonging to the client */
90 GNUNET_SERVER_client_disconnect (client);
95 * Get set that is owned by the client, if any.
97 * @param client client to look for
98 * @return set that the client owns, NULL if the client
102 get_set (struct GNUNET_SERVER_Client *client)
105 for (set = sets_head; NULL != set; set = set->next)
106 if (set->client == client)
113 * Get the listener associated to a client, if any.
115 * @param client the client
116 * @return listener associated with the client, NULL
119 static struct Listener *
120 get_listener (struct GNUNET_SERVER_Client *client)
122 struct Listener *listener;
123 for (listener = listeners_head; NULL != listener; listener = listener->next)
124 if (listener->client == client)
131 * Get the incoming socket associated with the given id
133 * @param id id to look for
134 * @return the incoming socket associated with the id,
135 * or NULL if there is none
137 static struct Incoming *
138 get_incoming (uint32_t id)
140 struct Incoming *incoming;
141 for (incoming = incoming_head; NULL != incoming; incoming = incoming->next)
142 if (incoming->request_id == id)
149 destroy_incoming (struct Incoming *incoming)
151 if (NULL != incoming->mq)
153 GNUNET_MQ_destroy (incoming->mq);
156 if (NULL != incoming->socket)
158 GNUNET_STREAM_close (incoming->socket);
159 incoming->socket = NULL;
161 GNUNET_CONTAINER_DLL_remove (incoming_head, incoming_tail, incoming);
162 GNUNET_free (incoming);
167 * Handle a request for a set operation for
170 * @param cls the incoming socket
171 * @param mh the message
174 handle_p2p_operation_request (void *cls, const struct GNUNET_MessageHeader *mh)
176 struct Incoming *incoming = cls;
177 const struct OperationRequestMessage *msg = (const struct OperationRequestMessage *) mh;
178 struct GNUNET_MQ_Message *mqm;
179 struct RequestMessage *cmsg;
180 struct Listener *listener;
181 const struct GNUNET_MessageHeader *context_msg;
183 if (ntohs (mh->size) < sizeof *msg)
186 destroy_incoming (incoming);
189 else if (ntohs (mh->size) == sizeof *msg)
195 context_msg = &msg[1].header;
196 if ((ntohs (context_msg->size) + sizeof *msg) != ntohs (msg->header.size))
198 /* size of context message is invalid */
200 destroy_incoming (incoming);
205 for (listener = listeners_head; listener != NULL; listener = listener->next)
207 if ( (0 != GNUNET_CRYPTO_hash_cmp (&msg->app_id, &listener->app_id)) ||
208 (htons (msg->operation) != listener->operation) )
210 mqm = GNUNET_MQ_msg_concat (cmsg, context_msg, GNUNET_MESSAGE_TYPE_SET_REQUEST);
211 incoming->request_id = request_id++;
212 cmsg->request_id = htonl (incoming->request_id);
213 GNUNET_MQ_send (listener->client_mq, mqm);
220 * Called when a client wants to create a new set.
223 * @param client client that sent the message
224 * @param m message sent by the client
227 handle_client_create (void *cls,
228 struct GNUNET_SERVER_Client *client,
229 const struct GNUNET_MessageHeader *m)
231 struct SetCreateMessage *msg = (struct SetCreateMessage *) m;
234 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "new set created\n");
236 if (NULL != get_set (client))
239 GNUNET_SERVER_client_disconnect (client);
243 set = GNUNET_new (struct Set);
245 switch (ntohs (msg->operation))
247 case GNUNET_SET_OPERATION_INTERSECTION:
251 case GNUNET_SET_OPERATION_UNION:
252 set = union_set_create ();
257 GNUNET_SERVER_client_disconnect (client);
261 set->client = client;
262 set->client_mq = GNUNET_MQ_queue_for_server_client (client);
263 GNUNET_CONTAINER_DLL_insert (sets_head, sets_tail, set);
265 GNUNET_SERVER_receive_done (client, GNUNET_OK);
270 * Called when a client wants to create a new set.
273 * @param client client that sent the message
274 * @param m message sent by the client
277 handle_client_listen (void *cls,
278 struct GNUNET_SERVER_Client *client,
279 const struct GNUNET_MessageHeader *m)
281 struct ListenMessage *msg = (struct ListenMessage *) m;
282 struct Listener *listener;
284 if (NULL != get_listener (client))
287 GNUNET_SERVER_client_disconnect (client);
291 listener = GNUNET_new (struct Listener);
292 listener->app_id = msg->app_id;
293 listener->operation = msg->operation;
294 GNUNET_CONTAINER_DLL_insert_tail (listeners_head, listeners_tail, listener);
299 * Called when a client wants to create a new set.
302 * @param client client that sent the message
303 * @param m message sent by the client
306 handle_client_add (void *cls,
307 struct GNUNET_SERVER_Client *client,
308 const struct GNUNET_MessageHeader *m)
312 set = get_set (client);
316 client_disconnect (client);
319 switch (set->operation)
321 case GNUNET_SET_OPERATION_UNION:
322 union_add (set, (struct ElementMessage *) m);
324 case GNUNET_SET_OPERATION_INTERSECTION:
335 * Called when a client wants to evaluate a set operation with another peer.
338 * @param client client that sent the message
339 * @param m message sent by the client
342 handle_client_evaluate (void *cls,
343 struct GNUNET_SERVER_Client *client,
344 const struct GNUNET_MessageHeader *m)
347 struct EvaluateMessage *msg = (struct EvaluateMessage *) m;
348 struct EvaluateOperation *eo;
350 set = get_set (client);
355 client_disconnect (client);
359 eo = GNUNET_new (struct EvaluateOperation);
360 eo->peer = msg->peer;
361 eo->app_id = msg->app_id;
362 eo->request_id = msg->request_id;
363 eo->context_msg = GNUNET_copy_message (&msg[1].header);
366 switch (set->operation)
368 case GNUNET_SET_OPERATION_INTERSECTION:
371 case GNUNET_SET_OPERATION_UNION:
382 * Handle a cancel request from a client.
385 * @param client the client
386 * @param m the cancel message
389 handle_client_cancel (void *cls,
390 struct GNUNET_SERVER_Client *client,
391 const struct GNUNET_MessageHeader *m)
393 /* FIXME: implement */
398 * Handle an ack from a client.
401 * @param client the client
402 * @param m the message
405 handle_client_ack (void *cls,
406 struct GNUNET_SERVER_Client *client,
407 const struct GNUNET_MessageHeader *m)
409 /* FIXME: implement */
414 * Handle a request from the client to accept
418 * @param client the client
419 * @param m the message
422 handle_client_accept (void *cls,
423 struct GNUNET_SERVER_Client *client,
424 const struct GNUNET_MessageHeader *m)
426 struct AcceptMessage *msg = (struct AcceptMessage *) m;
428 struct Incoming *incoming;
429 struct EvaluateOperation *eo;
431 set = get_set (client);
436 client_disconnect (client);
440 incoming = get_incoming (ntohl (msg->request_id));
442 if ( (NULL == incoming) ||
443 (incoming->operation != set->operation) )
446 client_disconnect (client);
450 eo = GNUNET_new (struct EvaluateOperation);
451 eo->peer = incoming->peer;
452 eo->app_id = incoming->app_id;
453 eo->request_id = msg->request_id;
456 switch (set->operation)
458 case GNUNET_SET_OPERATION_INTERSECTION:
462 case GNUNET_SET_OPERATION_UNION:
463 union_accept (eo, incoming);
473 * Functions of this type are called upon new stream connection from other peers
474 * or upon binding error which happen when the app_port given in
475 * GNUNET_STREAM_listen() is already taken.
477 * @param cls the closure from GNUNET_STREAM_listen
478 * @param socket the socket representing the stream; NULL on binding error
479 * @param initiator the identity of the peer who wants to establish a stream
480 * with us; NULL on binding error
481 * @return GNUNET_OK to keep the socket open, GNUNET_SYSERR to close the
482 * stream (the socket will be invalid after the call)
485 stream_listen_cb (void *cls,
486 struct GNUNET_STREAM_Socket *socket,
487 const struct GNUNET_PeerIdentity *initiator)
489 struct Incoming *incoming;
490 static const struct GNUNET_MQ_Handler handlers[] = {
491 {handle_p2p_operation_request, GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST},
492 GNUNET_MQ_HANDLERS_END
498 return GNUNET_SYSERR;
501 incoming = GNUNET_new (struct Incoming);
502 incoming->peer = *initiator;
503 incoming->socket = socket;
504 incoming->mq = GNUNET_MQ_queue_for_stream_socket (incoming->socket, handlers, incoming);
505 /* FIXME: timeout for peers that only connect but don't send anything */
506 GNUNET_CONTAINER_DLL_insert_tail (incoming_head, incoming_tail, incoming);
512 * Called to clean up, after a shutdown has been requested.
515 * @param tc context information (why was this task triggered now)
518 shutdown_task (void *cls,
519 const struct GNUNET_SCHEDULER_TaskContext *tc)
521 if (NULL != stream_listen_socket)
523 GNUNET_STREAM_listen_close (stream_listen_socket);
524 stream_listen_socket = NULL;
527 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "handled shutdown request\n");
532 * Function called by the service's run
533 * method to run service-specific setup code.
536 * @param server the initialized server
537 * @param cfg configuration to use
540 run (void *cls, struct GNUNET_SERVER_Handle *server, const struct GNUNET_CONFIGURATION_Handle *cfg)
542 static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
543 {handle_client_create, NULL, GNUNET_MESSAGE_TYPE_SET_CREATE, 0},
544 {handle_client_listen, NULL, GNUNET_MESSAGE_TYPE_SET_LISTEN, 0},
545 {handle_client_add, NULL, GNUNET_MESSAGE_TYPE_SET_ADD, 0},
546 {handle_client_cancel, NULL, GNUNET_MESSAGE_TYPE_SET_CANCEL, 0},
547 {handle_client_evaluate, NULL, GNUNET_MESSAGE_TYPE_SET_EVALUATE, 0},
548 {handle_client_ack, NULL, GNUNET_MESSAGE_TYPE_SET_ACK, 0},
549 {handle_client_accept, NULL, GNUNET_MESSAGE_TYPE_SET_ACCEPT, 0},
554 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL);
555 GNUNET_SERVER_add_handlers (server, server_handlers);
556 stream_listen_socket = GNUNET_STREAM_listen (cfg, GNUNET_APPLICATION_TYPE_SET,
557 &stream_listen_cb, NULL,
558 GNUNET_STREAM_OPTION_END);
563 * The main function for the set service.
565 * @param argc number of arguments from the command line
566 * @param argv command line arguments
567 * @return 0 ok, 1 on error
570 main (int argc, char *const *argv)
573 ret = GNUNET_SERVICE_run (argc, argv, "set", GNUNET_SERVICE_OPTION_NONE, &run, NULL);
574 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "exit\n");
575 return (GNUNET_OK == ret) ? 0 : 1;