consensus api, consensus service (local), peer driver and ibf sketch
[oweals/gnunet.git] / src / consensus / gnunet-consensus.c
1 /*
2       This file is part of GNUnet
3       (C) 2012 Christian Grothoff (and other contributing authors)
4
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.
9
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.
14
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.
19  */
20
21 /**
22  * @file consensus/gnunet-consensus.c
23  * @brief 
24  * @author Florian Dold
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_consensus_service.h"
29
30
31
32 /**
33  * Handle to the consensus service
34  */
35 static struct GNUNET_CONSENSUS_Handle *consensus;
36 /**
37  * Session id
38  */
39 static char *session_id_str;
40
41 /**
42  * File handle to STDIN
43  */
44 static struct GNUNET_DISK_FileHandle *stdin_fh;
45
46 /**
47  * Task for reading from stdin
48  */
49 static GNUNET_SCHEDULER_TaskIdentifier stdin_tid = GNUNET_SCHEDULER_NO_TASK;
50
51 /**
52  * Element currently being sent to the service
53  */
54 static struct GNUNET_CONSENSUS_Element *element;
55
56
57
58 static void
59 stdin_cb (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
60
61
62 /**
63  * Called when a conclusion was successful.
64  *
65  * @param cls
66  * @param num_peers_in_consensus
67  * @param peers_in_consensus
68  */
69 static void
70 conclude_cb (void *cls, 
71              unsigned int num_peers_in_consensus,
72              const struct GNUNET_PeerIdentity *peers_in_consensus)
73 {
74   printf("reached conclusion with %d peers\n", num_peers_in_consensus);
75   GNUNET_SCHEDULER_shutdown ();
76 }
77
78
79
80 static void
81 insert_done_cb (void *cls,
82                 int success)
83 {
84   if (GNUNET_YES != success)
85   {
86     printf ("insert failed\n");
87     GNUNET_SCHEDULER_shutdown ();
88   }
89
90   GNUNET_free (element);
91
92   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == stdin_tid);
93
94   stdin_tid = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, stdin_fh,
95                                         &stdin_cb, NULL);    
96 }
97
98
99 /**
100  * Called whenever we can read stdin non-blocking 
101  *
102  * @param cls unused
103  * @param tc scheduler context 
104  */
105 static void
106 stdin_cb (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
107 {
108   char buf[1024];
109   char *ret;
110   ret = fgets (buf, 1024, stdin);
111
112   stdin_tid = GNUNET_SCHEDULER_NO_TASK;
113
114   if (NULL == ret)
115   {
116     if (feof (stdin))
117     {
118       printf ("concluding ...\n");
119       GNUNET_CONSENSUS_conclude (consensus, GNUNET_TIME_UNIT_FOREVER_REL, conclude_cb, NULL);
120     }
121     else
122     {
123       GNUNET_SCHEDULER_shutdown ();
124     }
125     return;
126   }
127
128   printf("read: %s", buf);
129
130   element = GNUNET_malloc (sizeof (struct GNUNET_CONSENSUS_Element) + strlen(buf) + 1);
131   element->type = 0;
132   element->size = strlen(buf) + 1;
133   element->data = &element[1];
134   strcpy((char *) &element[1], buf);
135
136   GNUNET_CONSENSUS_insert (consensus, element, insert_done_cb, NULL);
137 }
138
139 /**
140  * Called when a new element was received from another peer, or an error occured.
141  *
142  * May deliver duplicate values.
143  *
144  * Elements given to a consensus operation by the local peer are NOT given
145  * to this callback.
146  *
147  * @param cls closure
148  * @param element new element, NULL on error
149  * @return GNUNET_OK if the valid is well-formed and should be added to the consensus,
150  *         GNUNET_SYSERR if the element should be ignored and not be propagated
151  */
152 static int
153 cb (void *cls,
154     struct GNUNET_CONSENSUS_Element *element)
155 {
156   printf("got element\n");
157   return GNUNET_YES;
158 }
159
160 /**
161  * Function run on shutdown to clean up.
162  *
163  * @param cls the statistics handle
164  * @param tc scheduler context
165  */
166 static void
167 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
168 {
169
170   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "shutting down\n");
171   if (NULL == consensus)
172   {
173     return;
174   }
175
176   GNUNET_CONSENSUS_destroy (consensus);
177 }
178
179
180 static void
181 run (void *cls, char *const *args, const char *cfgfile,
182      const struct GNUNET_CONFIGURATION_Handle *cfg)
183 {
184   struct GNUNET_HashCode sid;
185   struct GNUNET_PeerIdentity *pids;
186   int count;
187   int i;
188
189   if (NULL == session_id_str)
190   {
191     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "no session id given\n");
192     return;
193   }
194
195   for (count = 0; NULL != args[count]; count++);
196  
197   if (0 != count)
198   { 
199     pids = GNUNET_malloc (count * sizeof (struct GNUNET_PeerIdentity));
200   }
201   else
202   {
203     pids = NULL;
204   }
205
206   for (i = 0; i < count; i++)
207   {
208     int ret;
209     ret = GNUNET_CRYPTO_hash_from_string (args[i], &pids[i].hashPubKey);
210     if (GNUNET_OK != ret)
211     {
212       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "peer identity '%s' is malformed\n", args[i]);
213       return;
214     }
215   }
216
217   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
218                                 &shutdown_task, NULL);
219   
220   consensus = 
221       GNUNET_CONSENSUS_create (cfg,
222                                count, pids,
223                                &sid,
224                                &cb, NULL);
225
226   GNUNET_CONSENSUS_begin (consensus);
227
228
229   stdin_fh = GNUNET_DISK_get_handle_from_native (stdin);
230   stdin_tid = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, stdin_fh,
231                                         &stdin_cb, NULL);
232 }
233
234
235 int
236 main (int argc, char **argv)
237 {
238    static const struct GNUNET_GETOPT_CommandLineOption options[] = {
239       { 's', "session-id", "ID",
240         gettext_noop ("session identifier"),
241         GNUNET_YES, &GNUNET_GETOPT_set_string, &session_id_str },
242         GNUNET_GETOPT_OPTION_END
243    };
244   GNUNET_PROGRAM_run (argc, argv, "gnunet-consensus",
245                       "help",
246                       options, &run, NULL);
247   return 0;
248 }