aboutsummaryrefslogtreecommitdiff
path: root/src/identity/identity_api.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2013-07-14 20:27:06 +0000
committerChristian Grothoff <christian@grothoff.org>2013-07-14 20:27:06 +0000
commita7349d7a85cc142fa2416671da346d368819775d (patch)
tree855d1a44417cb31bdb1852ff1a845529191c2337 /src/identity/identity_api.c
parentcd96a296196e7951be4064cdab4824fda0b4b1d7 (diff)
downloadgnunet-a7349d7a85cc142fa2416671da346d368819775d.tar.gz
gnunet-a7349d7a85cc142fa2416671da346d368819775d.zip
-first steps towards identity client API
Diffstat (limited to 'src/identity/identity_api.c')
-rw-r--r--src/identity/identity_api.c490
1 files changed, 426 insertions, 64 deletions
diff --git a/src/identity/identity_api.c b/src/identity/identity_api.c
index 44cdcab2c..757cec76d 100644
--- a/src/identity/identity_api.c
+++ b/src/identity/identity_api.c
@@ -42,6 +42,72 @@
42 */ 42 */
43struct GNUNET_IDENTITY_Ego 43struct GNUNET_IDENTITY_Ego
44{ 44{
45 /**
46 * Private key associated with this ego.
47 */
48 struct GNUNET_CRYPTO_EccPrivateKey *pk;
49
50 /**
51 * Current identifier (name) associated with this ego.
52 */
53 char *identifier;
54
55 /**
56 * Client context associated with this ego.
57 */
58 void *ctx;
59
60 /**
61 * Hash of the public key of this ego.
62 */
63 struct GNUNET_HashCode id;
64};
65
66
67/**
68 * Handle for an operation with the identity service.
69 */
70struct GNUNET_IDENTITY_Operation
71{
72
73 /**
74 * Main identity handle.
75 */
76 struct GNUNET_IDENTITY_Handle *h;
77
78 /**
79 * We keep operations in a DLL.
80 */
81 struct GNUNET_IDENTITY_Operation *next;
82
83 /**
84 * We keep operations in a DLL.
85 */
86 struct GNUNET_IDENTITY_Operation *prev;
87
88 /**
89 * Message to send to the identity service.
90 * Allocated at the end of this struct.
91 */
92 const struct GNUNET_MessageHeader *msg;
93
94 /**
95 * Continuation to invoke with the result of the transmission; 'cb'
96 * will be NULL in this case.
97 */
98 GNUNET_IDENTITY_Continuation cont;
99
100 /**
101 * Continuation to invoke with the result of the transmission for
102 * 'get' operations ('cont' will be NULL in this case).
103 */
104 GNUNET_IDENTITY_Callback cb;
105
106 /**
107 * Closure for 'cont' or 'cb'.
108 */
109 void *cls;
110
45}; 111};
46 112
47 113
@@ -61,7 +127,33 @@ struct GNUNET_IDENTITY_Handle
61 struct GNUNET_CLIENT_Connection *client; 127 struct GNUNET_CLIENT_Connection *client;
62 128
63 /** 129 /**
64 * Currently pending transmission request. 130 * Hash map from the hash of the public key to the
131 * respective 'GNUNET_IDENTITY_Ego' handle.
132 */
133 struct GNUNET_CONTAINER_MultiHashMap *egos;
134
135 /**
136 * Function to call when we receive updates.
137 */
138 GNUNET_IDENTITY_Callback cb;
139
140 /**
141 * Closure for 'cb'.
142 */
143 void *cb_cls;
144
145 /**
146 * Head of active operations.
147 */
148 struct GNUNET_IDENTITY_Operation *op_head;
149
150 /**
151 * Tail of active operations.
152 */
153 struct GNUNET_IDENTITY_Operation *op_tail;
154
155 /**
156 * Currently pending transmission request, or NULL for none.
65 */ 157 */
66 struct GNUNET_CLIENT_TransmitHandle *th; 158 struct GNUNET_CLIENT_TransmitHandle *th;
67 159
@@ -75,9 +167,15 @@ struct GNUNET_IDENTITY_Handle
75 */ 167 */
76 struct GNUNET_TIME_Relative reconnect_delay; 168 struct GNUNET_TIME_Relative reconnect_delay;
77 169
170 /**
171 * Are we polling for incoming messages right now?
172 */
173 int in_receive;
174
78}; 175};
79 176
80 177
178
81/** 179/**
82 * Try again to connect to network size estimation service. 180 * Try again to connect to network size estimation service.
83 * 181 *
@@ -90,6 +188,36 @@ reconnect (void *cls,
90 188
91 189
92/** 190/**
191 * Reschedule a connect attempt to the service.
192 *
193 * @param h transport service to reconnect
194 */
195static void
196reschedule_connect (struct GNUNET_IDENTITY_Handle *h)
197{
198 GNUNET_assert (h->reconnect_task == GNUNET_SCHEDULER_NO_TASK);
199
200 if (NULL != h->th)
201 {
202 GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
203 h->th = NULL;
204 }
205 if (NULL != h->client)
206 {
207 GNUNET_CLIENT_disconnect (h->client);
208 h->client = NULL;
209 }
210 h->in_receive = GNUNET_NO;
211 LOG (GNUNET_ERROR_TYPE_DEBUG,
212 "Scheduling task to reconnect to identity service in %s.\n",
213 GNUNET_STRINGS_relative_time_to_string (h->reconnect_delay, GNUNET_YES));
214 h->reconnect_task =
215 GNUNET_SCHEDULER_add_delayed (h->reconnect_delay, &reconnect, h);
216 h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay);
217}
218
219
220/**
93 * Type of a function to call when we receive a message 221 * Type of a function to call when we receive a message
94 * from the service. 222 * from the service.
95 * 223 *
@@ -101,68 +229,271 @@ message_handler (void *cls,
101 const struct GNUNET_MessageHeader *msg) 229 const struct GNUNET_MessageHeader *msg)
102{ 230{
103 struct GNUNET_IDENTITY_Handle *h = cls; 231 struct GNUNET_IDENTITY_Handle *h = cls;
104 const struct GNUNET_IDENTITY_ClientMessage *client_msg; 232 struct GNUNET_IDENTITY_Operation *op;
105 233 struct GNUNET_IDENTITY_Ego *ego;
106 if (msg == NULL) 234 const struct GNUNET_IDENTITY_ResultCodeMessage *rcm;
235 const struct GNUNET_IDENTITY_UpdateMessage *um;
236 const struct GNUNET_IDENTITY_SetDefaultMessage *sdm;
237 struct GNUNET_CRYPTO_EccPrivateKey *priv;
238 struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded pub;
239 struct GNUNET_HashCode id;
240 const char *str;
241 uint16_t size;
242
243 if (NULL == msg)
107 { 244 {
108 /* Error, timeout, death */ 245 reschedule_connect (h);
109 GNUNET_CLIENT_disconnect (h->client); 246 return;
110 h->client = NULL; 247 }
111 h->reconnect_task = 248 size = ntohs (msg->size);
112 GNUNET_SCHEDULER_add_delayed (h->reconnect_delay, &reconnect, h); 249 switch (ntohs (msg->type))
250 {
251 case GNUNET_MESSAGE_TYPE_IDENTITY_RESULT_CODE:
252 if (size < sizeof (struct GNUNET_IDENTITY_ResultCodeMessage))
253 {
254 GNUNET_break (0);
255 reschedule_connect (h);
256 return;
257 }
258 rcm = (const struct GNUNET_IDENTITY_ResultCodeMessage *) msg;
259 str = (const char *) &rcm[1];
260 if ( (size > sizeof (struct GNUNET_IDENTITY_ResultCodeMessage)) &&
261 ('\0' != str[size - sizeof (struct GNUNET_IDENTITY_ResultCodeMessage) - 1]) )
262 {
263 GNUNET_break (0);
264 reschedule_connect (h);
265 return;
266 }
267 if (size == sizeof (struct GNUNET_IDENTITY_ResultCodeMessage))
268 str = NULL;
269
270 op = h->op_head;
271 GNUNET_CONTAINER_DLL_remove (h->op_head,
272 h->op_tail,
273 op);
274 if (NULL != op->cont)
275 op->cont (op->cls,
276 str);
277 GNUNET_break (NULL == op->cb);
278 GNUNET_free (op);
279 break;
280 case GNUNET_MESSAGE_TYPE_IDENTITY_UPDATE:
281 if (size < sizeof (struct GNUNET_IDENTITY_UpdateMessage))
282 {
283 GNUNET_break (0);
284 reschedule_connect (h);
285 return;
286 }
287 um = (const struct GNUNET_IDENTITY_UpdateMessage *) msg;
288 str = (const char *) &um[1];
289 if ( (size > sizeof (struct GNUNET_IDENTITY_UpdateMessage)) &&
290 ('\0' != str[size - sizeof (struct GNUNET_IDENTITY_UpdateMessage) - 1]) )
291 {
292 GNUNET_break (0);
293 reschedule_connect (h);
294 return;
295 }
296 if (size == sizeof (struct GNUNET_IDENTITY_UpdateMessage))
297 str = NULL;
298
299 // FIXME: um->pk does NOT work!
300 priv = GNUNET_CRYPTO_ecc_decode_key (NULL, 0, GNUNET_YES); // FIXME...
301 if (NULL == priv)
302 {
303 GNUNET_break (0);
304 reschedule_connect (h);
305 return;
306 }
307 GNUNET_CRYPTO_ecc_key_get_public (priv,
308 &pub);
309 GNUNET_CRYPTO_hash (&pub, sizeof (pub), &id);
310
311 ego = GNUNET_CONTAINER_multihashmap_get (h->egos,
312 &id);
313 if (NULL == ego)
314 {
315 /* ego was created */
316 if (NULL == str)
317 {
318 /* deletion of unknown ego? not allowed */
319 GNUNET_break (0);
320 GNUNET_CRYPTO_ecc_key_free (priv);
321 reschedule_connect (h);
322 return;
323 }
324 ego = GNUNET_new (struct GNUNET_IDENTITY_Ego);
325 ego->pk = priv;
326 ego->identifier = GNUNET_strdup (str);
327 ego->id = id;
328 GNUNET_assert (GNUNET_YES ==
329 GNUNET_CONTAINER_multihashmap_put (h->egos,
330 &ego->id,
331 ego,
332 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
333 }
334 else
335 {
336 GNUNET_CRYPTO_ecc_key_free (priv);
337 }
338 /* inform application about change */
339 h->cb (h->cb_cls,
340 ego,
341 &ego->ctx,
342 str);
343 if (NULL == str)
344 {
345 /* ego was deleted */
346 GNUNET_assert (GNUNET_YES ==
347 GNUNET_CONTAINER_multihashmap_remove (h->egos,
348 &ego->id,
349 ego));
350 GNUNET_CRYPTO_ecc_key_free (ego->pk);
351 GNUNET_free (ego->identifier);
352 GNUNET_free (ego);
353 }
354 else
355 {
356 /* ego changed name */
357 GNUNET_free (ego->identifier);
358 ego->identifier = GNUNET_strdup (str);
359 }
360 break;
361 case GNUNET_MESSAGE_TYPE_IDENTITY_SET_DEFAULT:
362 if (size < sizeof (struct GNUNET_IDENTITY_SetDefaultMessage))
363 {
364 GNUNET_break (0);
365 reschedule_connect (h);
366 return;
367 }
368 sdm = (const struct GNUNET_IDENTITY_SetDefaultMessage *) msg;
369 str = (const char *) &sdm[1];
370 if ( (size > sizeof (struct GNUNET_IDENTITY_SetDefaultMessage)) &&
371 ('\0' != str[size - sizeof (struct GNUNET_IDENTITY_SetDefaultMessage) - 1]) )
372 {
373 GNUNET_break (0);
374 reschedule_connect (h);
375 return;
376 }
377 if (size == sizeof (struct GNUNET_IDENTITY_SetDefaultMessage))
378 str = NULL;
379 // FIXME: sdr->pk does NOT work!
380 priv = GNUNET_CRYPTO_ecc_decode_key (NULL, 0, GNUNET_YES); // FIXME...
381 if (NULL == priv)
382 {
383 GNUNET_break (0);
384 reschedule_connect (h);
385 return;
386 }
387 GNUNET_CRYPTO_ecc_key_get_public (priv,
388 &pub);
389 GNUNET_CRYPTO_ecc_key_free (priv);
390 GNUNET_CRYPTO_hash (&pub, sizeof (pub), &id);
391 ego = GNUNET_CONTAINER_multihashmap_get (h->egos,
392 &id);
393 if (NULL == ego)
394 {
395 GNUNET_break (0);
396 reschedule_connect (h);
397 return;
398 }
399 op = h->op_head;
400 GNUNET_CONTAINER_DLL_remove (h->op_head,
401 h->op_tail,
402 op);
403 if (NULL != op->cb)
404 op->cb (op->cls,
405 ego,
406 &ego->ctx,
407 ego->identifier);
408 GNUNET_break (NULL == op->cont);
409 GNUNET_free (op);
410 break;
411 default:
412 GNUNET_break (0);
413 reschedule_connect (h);
113 return; 414 return;
114 } 415 }
115 // FIXME: process...
116 GNUNET_CLIENT_receive (h->client, &message_handler, h, 416 GNUNET_CLIENT_receive (h->client, &message_handler, h,
117 GNUNET_TIME_UNIT_FOREVER_REL); 417 GNUNET_TIME_UNIT_FOREVER_REL);
118} 418}
119 419
120 420
121
122/** 421/**
123 * Reschedule a connect attempt to the service. 422 * Schedule transmission of the next message from our queue.
124 * 423 *
125 * @param h transport service to reconnect 424 * @param h identity handle
126 */ 425 */
127static void 426static void
128reschedule_connect (struct GNUNET_IDENTITY_Handle *h) 427transmit_next (struct GNUNET_IDENTITY_Handle *h);
129{
130 GNUNET_assert (h->reconnect_task == GNUNET_SCHEDULER_NO_TASK);
131 428
132 if (NULL != h->th) 429
430/**
431 * Transmit next message to service.
432 *
433 * @param cls the 'struct GNUNET_IDENTITY_Handle'.
434 * @param size number of bytes available in buf
435 * @param buf where to copy the message
436 * @return number of bytes copied to buf
437 */
438static size_t
439send_next_message (void *cls,
440 size_t size,
441 void *buf)
442{
443 struct GNUNET_IDENTITY_Handle *h = cls;
444 struct GNUNET_IDENTITY_Operation *op = h->op_head;
445 size_t ret;
446
447 h->th = NULL;
448 if (NULL == op)
449 return 0;
450 ret = ntohs (op->msg->size);
451 if (ret > size)
133 { 452 {
134 GNUNET_CLIENT_notify_transmit_ready_cancel (h->th); 453 reschedule_connect (h);
135 h->th = NULL; 454 return 0;
455 }
456 memcpy (buf, op->msg, ret);
457 if ( (NULL == op->cont) &&
458 (NULL == op->cb) )
459 {
460 GNUNET_CONTAINER_DLL_remove (h->op_head,
461 h->op_tail,
462 op);
463 GNUNET_free (op);
464 transmit_next (h);
136 } 465 }
137 if (NULL != h->client) 466 if (GNUNET_NO == h->in_receive)
138 { 467 {
139 GNUNET_CLIENT_disconnect (h->client); 468 h->in_receive = GNUNET_YES;
140 h->client = NULL; 469 GNUNET_CLIENT_receive (h->client,
470 &message_handler, h,
471 GNUNET_TIME_UNIT_FOREVER_REL);
141 } 472 }
142 473 return ret;
143 LOG (GNUNET_ERROR_TYPE_DEBUG,
144 "Scheduling task to reconnect to identity service in %llu ms.\n",
145 h->reconnect_delay.rel_value);
146 h->reconnect_task =
147 GNUNET_SCHEDULER_add_delayed (h->reconnect_delay, &reconnect, h);
148 h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay);
149} 474}
150 475
151 476
152/** 477/**
153 * Transmit START message to service. 478 * Schedule transmission of the next message from our queue.
154 * 479 *
155 * @param cls unused 480 * @param h identity handle
156 * @param size number of bytes available in buf
157 * @param buf where to copy the message
158 * @return number of bytes copied to buf
159 */ 481 */
160static size_t 482static void
161send_start (void *cls, 483transmit_next (struct GNUNET_IDENTITY_Handle *h)
162 size_t size,
163 void *buf)
164{ 484{
165 return 0; 485 struct GNUNET_IDENTITY_Operation *op = h->op_head;
486
487 GNUNET_assert (NULL == h->th);
488 if (NULL == op)
489 return;
490 h->th = GNUNET_CLIENT_notify_transmit_ready (h->client,
491 ntohs (op->msg->size),
492 GNUNET_TIME_UNIT_FOREVER_REL,
493 GNUNET_NO,
494 &send_next_message,
495 h);
496
166} 497}
167 498
168 499
@@ -176,25 +507,27 @@ static void
176reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 507reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
177{ 508{
178 struct GNUNET_IDENTITY_Handle *h = cls; 509 struct GNUNET_IDENTITY_Handle *h = cls;
510 struct GNUNET_IDENTITY_Operation *op;
511 struct GNUNET_MessageHeader msg;
179 512
180 h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; 513 h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
181 if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
182 {
183 /* shutdown, just give up */
184 return;
185 }
186 LOG (GNUNET_ERROR_TYPE_DEBUG, 514 LOG (GNUNET_ERROR_TYPE_DEBUG,
187 "Connecting to network size estimation service.\n"); 515 "Connecting to identity service.\n");
188 GNUNET_assert (h->client == NULL); 516 GNUNET_assert (NULL == h->client);
189 h->client = GNUNET_CLIENT_connect ("identity", h->cfg); 517 h->client = GNUNET_CLIENT_connect ("identity", h->cfg);
190 GNUNET_assert (h->client != NULL); 518 GNUNET_assert (NULL != h->client);
191 519 op = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_Operation) +
192 h->th = 520 sizeof (struct GNUNET_MessageHeader));
193 GNUNET_CLIENT_notify_transmit_ready (h->client, 521 op->h = h;
194 sizeof (struct GNUNET_MessageHeader), 522 op->msg = (const struct GNUNET_MessageHeader *) &op[1];
195 GNUNET_TIME_UNIT_FOREVER_REL, 523 msg.size = htons (sizeof (msg));
196 GNUNET_NO, &send_start, h); 524 msg.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_START);
197 GNUNET_assert (h->th != NULL); 525 memcpy (&op[1], &msg, sizeof (msg));
526 GNUNET_CONTAINER_DLL_insert (h->op_head,
527 h->op_tail,
528 op);
529 transmit_next (h);
530 GNUNET_assert (NULL != h->th);
198} 531}
199 532
200 533
@@ -211,13 +544,15 @@ GNUNET_IDENTITY_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
211 GNUNET_IDENTITY_Callback cb, 544 GNUNET_IDENTITY_Callback cb,
212 void *cb_cls) 545 void *cb_cls)
213{ 546{
214 struct GNUNET_IDENTITY_Handle *ret; 547 struct GNUNET_IDENTITY_Handle *h;
215 548
216 ret = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_Handle)); 549 h = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_Handle));
217 ret->cfg = cfg; 550 h->cfg = cfg;
218 ret->reconnect_delay = GNUNET_TIME_UNIT_ZERO; 551 h->cb = cb;
219 ret->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, ret); 552 h->cb_cls = cb_cls;
220 return ret; 553 h->reconnect_delay = GNUNET_TIME_UNIT_ZERO;
554 h->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, h);
555 return h;
221} 556}
222 557
223 558
@@ -230,7 +565,7 @@ GNUNET_IDENTITY_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
230const struct GNUNET_CRYPTO_EccPrivateKey * 565const struct GNUNET_CRYPTO_EccPrivateKey *
231GNUNET_IDENTITY_ego_get_key (struct GNUNET_IDENTITY_Ego *ego) 566GNUNET_IDENTITY_ego_get_key (struct GNUNET_IDENTITY_Ego *ego)
232{ 567{
233 return NULL; 568 return ego->pk;
234} 569}
235 570
236 571
@@ -345,6 +680,33 @@ GNUNET_IDENTITY_delete (struct GNUNET_IDENTITY_Handle *id,
345void 680void
346GNUNET_IDENITY_cancel (struct GNUNET_IDENTITY_Operation *op) 681GNUNET_IDENITY_cancel (struct GNUNET_IDENTITY_Operation *op)
347{ 682{
683 struct GNUNET_IDENTITY_Handle *h = op->h;
684
685 if ( (h->op_head != op) ||
686 (NULL == h->client) )
687 {
688 /* request not active, can simply remove */
689 GNUNET_CONTAINER_DLL_remove (h->op_head,
690 h->op_tail,
691 op);
692 GNUNET_free (op);
693 return;
694 }
695 if (NULL != h->th)
696 {
697 /* request active but not yet with service, can still abort */
698 GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
699 h->th = NULL;
700 GNUNET_CONTAINER_DLL_remove (h->op_head,
701 h->op_tail,
702 op);
703 GNUNET_free (op);
704 transmit_next (h);
705 return;
706 }
707 /* request active with service, simply ensure continuations are not called */
708 op->cont = NULL;
709 op->cb = NULL;
348} 710}
349 711
350 712
@@ -362,12 +724,12 @@ GNUNET_IDENTITY_disconnect (struct GNUNET_IDENTITY_Handle *h)
362 GNUNET_SCHEDULER_cancel (h->reconnect_task); 724 GNUNET_SCHEDULER_cancel (h->reconnect_task);
363 h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; 725 h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
364 } 726 }
365 if (h->th != NULL) 727 if (NULL != h->th)
366 { 728 {
367 GNUNET_CLIENT_notify_transmit_ready_cancel (h->th); 729 GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
368 h->th = NULL; 730 h->th = NULL;
369 } 731 }
370 if (h->client != NULL) 732 if (NULL != h->client)
371 { 733 {
372 GNUNET_CLIENT_disconnect (h->client); 734 GNUNET_CLIENT_disconnect (h->client);
373 h->client = NULL; 735 h->client = NULL;