- fix encryption/decryption visisbility
[oweals/gnunet.git] / src / include / gnunet_namestore_service.h
1
2 /*
3      This file is part of GNUnet
4      (C) 2012, 2013 Christian Grothoff (and other contributing authors)
5
6      GNUnet is free software; you can redistribute it and/or modify
7      it under the terms of the GNU General Public License as published
8      by the Free Software Foundation; either version 3, or (at your
9      option) any later version.
10
11      GNUnet is distributed in the hope that it will be useful, but
12      WITHOUT ANY WARRANTY; without even the implied warranty of
13      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14      General Public License for more details.
15
16      You should have received a copy of the GNU General Public License
17      along with GNUnet; see the file COPYING.  If not, write to the
18      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19      Boston, MA 02111-1307, USA.
20 */
21
22 /**
23  * @file include/gnunet_namestore_service.h
24  * @brief API that can be used to store naming information on a GNUnet node;
25  *        Naming information can either be records for which this peer/user
26  *        is authoritative, or blocks which are cached, encrypted naming
27  *        data from other peers.
28  * @author Christian Grothoff
29  */
30 #ifndef GNUNET_NAMESTORE_SERVICE_H
31 #define GNUNET_NAMESTORE_SERVICE_H
32
33 #include "gnunet_util_lib.h"
34 #include "gnunet_block_lib.h"
35
36 #ifdef __cplusplus
37 extern "C"
38 {
39 #if 0                           /* keep Emacsens' auto-indent happy */
40 }
41 #endif
42 #endif
43
44 /**
45  * Record type indicating any record/'*'
46  */
47 #define GNUNET_NAMESTORE_TYPE_ANY 0
48
49 /**
50  * Record type for GNS zone transfer ("PKEY").
51  */
52 #define GNUNET_NAMESTORE_TYPE_PKEY 65536
53
54 /**
55  * Record type for GNS zone transfer ("PSEU").
56  */
57 #define GNUNET_NAMESTORE_TYPE_PSEU 65537
58
59 /**
60  * Record type for GNS legacy hostnames ("LEHO").
61  */
62 #define GNUNET_NAMESTORE_TYPE_LEHO 65538
63
64 /**
65  * Record type for VPN resolution
66  */
67 #define GNUNET_NAMESTORE_TYPE_VPN 65539
68
69 /**
70  * Record type for delegation to DNS.
71  */
72 #define GNUNET_NAMESTORE_TYPE_GNS2DNS 65540
73
74 /**
75  * Record type for a social place.
76  */
77 #define GNUNET_NAMESTORE_TYPE_PLACE 65541
78
79 /**
80  * Record type for a phone (of CONVERSATION).
81  */
82 #define GNUNET_NAMESTORE_TYPE_PHONE 65542
83
84
85 /**
86  * Entry in the queue.
87  */
88 struct GNUNET_NAMESTORE_QueueEntry;
89
90 /**
91  * Handle to the namestore service.
92  */
93 struct GNUNET_NAMESTORE_Handle;
94
95 /**
96  * Handle to the namestore zone iterator.
97  */
98 struct GNUNET_NAMESTORE_ZoneIterator;
99
100 /**
101  * Maximum size of a value that can be stored in the namestore.
102  */
103 #define GNUNET_NAMESTORE_MAX_VALUE_SIZE (63 * 1024)
104
105
106 /**
107  * Connect to the namestore service.
108  *
109  * @param cfg configuration to use
110  * @return handle to use to access the service
111  */
112 struct GNUNET_NAMESTORE_Handle *
113 GNUNET_NAMESTORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg);
114
115
116 /**
117  * Disconnect from the namestore service (and free associated
118  * resources).  Must not be called from within operation callbacks of
119  * the API.
120  *
121  * @param h handle to the namestore
122  */
123 void
124 GNUNET_NAMESTORE_disconnect (struct GNUNET_NAMESTORE_Handle *h);
125
126
127 /**
128  * Continuation called to notify client about result of the
129  * operation.
130  *
131  * @param cls closure
132  * @param success #GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate)
133  *                #GNUNET_NO if content was already there or not found
134  *                #GNUNET_YES (or other positive value) on success
135  * @param emsg NULL on success, otherwise an error message
136  */
137 typedef void (*GNUNET_NAMESTORE_ContinuationWithStatus) (void *cls,
138                                                          int32_t success,
139                                                          const char *emsg);
140
141
142 /**
143  * Flags that can be set for a record.
144  */
145 enum GNUNET_NAMESTORE_RecordFlags
146 {
147
148   /**
149    * No special options.
150    */
151   GNUNET_NAMESTORE_RF_NONE = 0,
152
153   /**
154    * This is a private record of this peer and it should
155    * thus not be handed out to other peers.
156    */
157   GNUNET_NAMESTORE_RF_PRIVATE = 2,
158
159   /**
160    * This record was added automatically by the system
161    * and is pending user confimation.
162    */
163   GNUNET_NAMESTORE_RF_PENDING = 4,
164
165   /**
166    * This expiration time of the record is a relative
167    * time (not an absolute time).
168    */
169   GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION = 8,
170
171   /**
172    * This record should not be used unless all (other) records with an absolute
173    * expiration time have expired.
174    */
175   GNUNET_NAMESTORE_RF_SHADOW_RECORD = 16
176
177   /**
178    * When comparing flags for record equality for removal,
179    * which flags should must match (in addition to the type,
180    * name, expiration value and data of the record)?  All flags
181    * that are not listed here will be ignored for this purpose.
182    * (for example, we don't expect that users will remember to
183    * pass the '--private' option when removing a record from
184    * the namestore, hence we don't require this particular option
185    * to match upon removal).  See also
186    * #GNUNET_NAMESTORE_records_cmp.
187    */
188 #define GNUNET_NAMESTORE_RF_RCMP_FLAGS (GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION)
189 };
190
191
192 /**
193  * A GNS record.
194  */
195 struct GNUNET_NAMESTORE_RecordData
196 {
197
198   /**
199    * Binary value stored in the DNS record.  Note: "data" must never
200    * be individually 'malloc'ed, but instead always points into some
201    * existing data area.
202    */
203   const void *data;
204
205   /**
206    * Expiration time for the DNS record.  Can be relative
207    * or absolute, depending on 'flags'.  Measured in the same
208    * unit as GNUnet time (microseconds).
209    */
210   uint64_t expiration_time;
211
212   /**
213    * Number of bytes in 'data'.
214    */
215   size_t data_size;
216
217   /**
218    * Type of the GNS/DNS record.
219    */
220   uint32_t record_type;
221
222   /**
223    * Flags for the record.
224    */
225   enum GNUNET_NAMESTORE_RecordFlags flags;
226 };
227
228
229
230 GNUNET_NETWORK_STRUCT_BEGIN
231
232
233 /**
234  * Information we have in an encrypted block with record data (i.e. in the DHT).
235  */
236 struct GNUNET_NAMESTORE_Block
237 {
238
239   /**
240    * Signature of the block.
241    */
242   struct GNUNET_CRYPTO_EcdsaSignature signature;
243
244   /**
245    * Derived key used for signing; hash of this is the query.
246    */
247   struct GNUNET_CRYPTO_EcdsaPublicKey derived_key;
248
249   /**
250    * Number of bytes signed; also specifies the number of bytes
251    * of encrypted data that follow.
252    */
253   struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
254
255   /**
256    * Expiration time of the block.
257    */
258   struct GNUNET_TIME_AbsoluteNBO expiration_time;
259
260   /* followed by encrypted data */
261 };
262
263
264
265 GNUNET_NETWORK_STRUCT_END
266
267 /**
268  * Store an item in the namestore.  If the item is already present,
269  * it is replaced with the new record.
270  *
271  * @param h handle to the namestore
272  * @param block block to store
273  * @param cont continuation to call when done
274  * @param cont_cls closure for @a cont
275  * @return handle to abort the request
276  */
277 struct GNUNET_NAMESTORE_QueueEntry *
278 GNUNET_NAMESTORE_block_cache (struct GNUNET_NAMESTORE_Handle *h,
279                               const struct GNUNET_NAMESTORE_Block *block,
280                               GNUNET_NAMESTORE_ContinuationWithStatus cont,
281                               void *cont_cls);
282
283
284 /**
285  * Store an item in the namestore.  If the item is already present,
286  * it is replaced with the new record.  Use an empty array to
287  * remove all records under the given name.
288  *
289  * @param h handle to the namestore
290  * @param pkey private key of the zone
291  * @param label name that is being mapped (at most 255 characters long)
292  * @param rd_count number of records in the 'rd' array
293  * @param rd array of records with data to store
294  * @param cont continuation to call when done
295  * @param cont_cls closure for @a cont
296  * @return handle to abort the request
297  */
298 struct GNUNET_NAMESTORE_QueueEntry *
299 GNUNET_NAMESTORE_records_store (struct GNUNET_NAMESTORE_Handle *h,
300                                 const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey,
301                                 const char *label,
302                                 unsigned int rd_count,
303                                 const struct GNUNET_NAMESTORE_RecordData *rd,
304                                 GNUNET_NAMESTORE_ContinuationWithStatus cont,
305                                 void *cont_cls);
306
307
308 /**
309  * Process a record that was stored in the namestore.
310  *
311  * @param cls closure
312  * @param block block that was stored in the namestore
313  */
314 typedef void (*GNUNET_NAMESTORE_BlockProcessor) (void *cls,
315                                                  const struct GNUNET_NAMESTORE_Block *block);
316
317
318 /**
319  * Get a result for a particular key from the namestore.  The processor
320  * will only be called once.
321  *
322  * @param h handle to the namestore
323  * @param derived_hash hash of zone key combined with name to lookup
324  *        then at the end once with NULL
325  * @param proc function to call on the matching block, or with
326  *        NULL if there is no matching block
327  * @param proc_cls closure for @a proc
328  * @return a handle that can be used to cancel
329  */
330 struct GNUNET_NAMESTORE_QueueEntry *
331 GNUNET_NAMESTORE_lookup_block (struct GNUNET_NAMESTORE_Handle *h,
332                                const struct GNUNET_HashCode *derived_hash,
333                                GNUNET_NAMESTORE_BlockProcessor proc, void *proc_cls);
334
335
336 /**
337  * Process a record that was stored in the namestore.
338  *
339  * @param cls closure
340  * @param zone private key of the zone; NULL on disconnect
341  * @param label label of the records; NULL on disconnect
342  * @param rd_count number of entries in @a rd array, 0 if label was deleted
343  * @param rd array of records with data to store
344  */
345 typedef void (*GNUNET_NAMESTORE_RecordMonitor) (void *cls,
346                                                 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
347                                                 const char *label,
348                                                 unsigned int rd_count,
349                                                 const struct GNUNET_NAMESTORE_RecordData *rd);
350
351
352 /**
353  * Look for an existing PKEY delegation record for a given public key.
354  * Returns at most one result to the processor.
355  *
356  * @param h handle to the namestore
357  * @param zone public key of the zone to look up in, never NULL
358  * @param value_zone public key of the target zone (value), never NULL
359  * @param proc function to call on the matching records, or with
360  *        NULL (rd_count == 0) if there are no matching records
361  * @param proc_cls closure for @a proc
362  * @return a handle that can be used to
363  *         cancel
364  */
365 struct GNUNET_NAMESTORE_QueueEntry *
366 GNUNET_NAMESTORE_zone_to_name (struct GNUNET_NAMESTORE_Handle *h,
367                                const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
368                                const struct GNUNET_CRYPTO_EcdsaPublicKey *value_zone,
369                                GNUNET_NAMESTORE_RecordMonitor proc, void *proc_cls);
370
371
372 /**
373  * Process a records that were decrypted from a block.
374  *
375  * @param cls closure
376  * @param rd_count number of entries in @a rd array
377  * @param rd array of records with data to store
378  */
379 typedef void (*GNUNET_NAMESTORE_RecordCallback) (void *cls,
380                                                  unsigned int rd_count,
381                                                  const struct GNUNET_NAMESTORE_RecordData *rd);
382
383
384 /**
385  * Cancel a namestore operation.  The final callback from the
386  * operation must not have been done yet.  Must be called on any
387  * namestore operation that has not yet completed prior to calling
388  * #GNUNET_NAMESTORE_disconnect.
389  *
390  * @param qe operation to cancel
391  */
392 void
393 GNUNET_NAMESTORE_cancel (struct GNUNET_NAMESTORE_QueueEntry *qe);
394
395
396 /**
397  * Starts a new zone iteration (used to periodically PUT all of our
398  * records into our DHT). This MUST lock the struct GNUNET_NAMESTORE_Handle
399  * for any other calls than #GNUNET_NAMESTORE_zone_iterator_next and
400  * #GNUNET_NAMESTORE_zone_iteration_stop. @a proc will be called once
401  * immediately, and then again after
402  * #GNUNET_NAMESTORE_zone_iterator_next is invoked.
403  *
404  * @param h handle to the namestore
405  * @param zone zone to access, NULL for all zones
406  * @param proc function to call on each name from the zone; it
407  *        will be called repeatedly with a value (if available)
408  *        and always once at the end with a name of NULL.
409  * @param proc_cls closure for @a proc
410  * @return an iterator handle to use for iteration
411  */
412 struct GNUNET_NAMESTORE_ZoneIterator *
413 GNUNET_NAMESTORE_zone_iteration_start (struct GNUNET_NAMESTORE_Handle *h,
414                                        const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
415                                        GNUNET_NAMESTORE_RecordMonitor proc,
416                                        void *proc_cls);
417
418
419 /**
420  * Calls the record processor specified in #GNUNET_NAMESTORE_zone_iteration_start
421  * for the next record.
422  *
423  * @param it the iterator
424  */
425 void
426 GNUNET_NAMESTORE_zone_iterator_next (struct GNUNET_NAMESTORE_ZoneIterator *it);
427
428
429 /**
430  * Stops iteration and releases the namestore handle for further calls.  Must
431  * be called on any iteration that has not yet completed prior to calling
432  * #GNUNET_NAMESTORE_disconnect.
433  *
434  * @param it the iterator
435  */
436 void
437 GNUNET_NAMESTORE_zone_iteration_stop (struct GNUNET_NAMESTORE_ZoneIterator *it);
438
439
440 /**
441  * Handle for a monitoring activity.
442  */
443 struct GNUNET_NAMESTORE_ZoneMonitor;
444
445
446 /**
447  * Function called once the monitor has caught up with the current
448  * state of the database.  Will be called AGAIN after each disconnect
449  * (record monitor called with 'NULL' for zone_key) once we're again
450  * in sync.
451  *
452  * @param cls closure
453  */
454 typedef void (*GNUNET_NAMESTORE_RecordsSynchronizedCallback)(void *cls);
455
456
457 /**
458  * Begin monitoring a zone for changes.  Will first call the @a monitor function
459  * on all existing records in the selected zone(s), then calls @a sync_cb,
460  * and then calls the @a monitor whenever a record changes.  If the namestore
461  * disconnects, the @a monitor function is called with a disconnect event; if
462  * the connection is re-established, the process begins from the start (all
463  * existing records, sync, then updates).
464  *
465  * @param cfg configuration to use to connect to namestore
466  * @param zone zone to monitor
467  * @param monitor function to call on zone changes
468  * @param sync_cb function called when we're in sync with the namestore
469  * @param cls closure for @a monitor and @a sync_cb
470  * @return handle to stop monitoring
471  */
472 struct GNUNET_NAMESTORE_ZoneMonitor *
473 GNUNET_NAMESTORE_zone_monitor_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
474                                      const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
475                                      GNUNET_NAMESTORE_RecordMonitor monitor,
476                                      GNUNET_NAMESTORE_RecordsSynchronizedCallback sync_cb,
477                                      void *cls);
478
479
480 /**
481  * Stop monitoring a zone for changes.
482  *
483  * @param zm handle to the monitor activity to stop
484  */
485 void
486 GNUNET_NAMESTORE_zone_monitor_stop (struct GNUNET_NAMESTORE_ZoneMonitor *zm);
487
488
489 /* convenience APIs for serializing / deserializing GNS records */
490
491 /**
492  * Calculate how many bytes we will need to serialize the given
493  * records.
494  *
495  * @param rd_count number of records in the @a rd array
496  * @param rd array of #GNUNET_NAMESTORE_RecordData with @a rd_count elements
497  * @return the required size to serialize
498  */
499 size_t
500 GNUNET_NAMESTORE_records_get_size (unsigned int rd_count,
501                                    const struct GNUNET_NAMESTORE_RecordData *rd);
502
503
504 /**
505  * Serialize the given records to the given destination buffer.
506  *
507  * @param rd_count number of records in the @a rd array
508  * @param rd array of #GNUNET_NAMESTORE_RecordData with @a rd_count elements
509  * @param dest_size size of the destination array @a dst
510  * @param dest where to write the result
511  * @return the size of serialized records, -1 if records do not fit
512  */
513 ssize_t
514 GNUNET_NAMESTORE_records_serialize (unsigned int rd_count,
515                                     const struct GNUNET_NAMESTORE_RecordData *rd,
516                                     size_t dest_size,
517                                     char *dest);
518
519
520 /**
521  * Deserialize the given records to the given destination.
522  *
523  * @param len size of the serialized record data
524  * @param src the serialized record data
525  * @param rd_count number of records in the @a dest array
526  * @param dest where to put the data
527  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
528  */
529 int
530 GNUNET_NAMESTORE_records_deserialize (size_t len,
531                                       const char *src,
532                                       unsigned int rd_count,
533                                       struct GNUNET_NAMESTORE_RecordData *dest);
534
535
536 /**
537  * Convert the binary value @a data of a record of
538  * type @a type to a human-readable string.
539  *
540  * @param type type of the record
541  * @param data value in binary encoding
542  * @param data_size number of bytes in @a data
543  * @return NULL on error, otherwise human-readable representation of the value
544  */
545 char *
546 GNUNET_NAMESTORE_value_to_string (uint32_t type,
547                                   const void *data,
548                                   size_t data_size);
549
550
551 /**
552  * Convert human-readable version of the value @a s of a record
553  * of type @a type to the respective binary representation.
554  *
555  * @param type type of the record
556  * @param s human-readable string
557  * @param data set to value in binary encoding (will be allocated)
558  * @param data_size set to number of bytes in @a data
559  * @return #GNUNET_OK on success
560  */
561 int
562 GNUNET_NAMESTORE_string_to_value (uint32_t type,
563                                   const char *s,
564                                   void **data,
565                                   size_t *data_size);
566
567
568 /**
569  * Convert a type name (i.e. "AAAA") to the corresponding number.
570  *
571  * @param dns_typename name to convert
572  * @return corresponding number, UINT32_MAX on error
573  */
574 uint32_t
575 GNUNET_NAMESTORE_typename_to_number (const char *dns_typename);
576
577
578 /**
579  * Convert a type number (i.e. 1) to the corresponding type string (i.e. "A")
580  *
581  * @param type number of a type to convert
582  * @return corresponding typestring, NULL on error
583  */
584 const char *
585 GNUNET_NAMESTORE_number_to_typename (uint32_t type);
586
587
588 /**
589  * Test if a given record is expired.
590  *
591  * @param rd record to test
592  * @return #GNUNET_YES if the record is expired,
593  *         #GNUNET_NO if not
594  */
595 int
596 GNUNET_NAMESTORE_is_expired (const struct GNUNET_NAMESTORE_RecordData *rd);
597
598
599 /**
600  * Convert a UTF-8 string to UTF-8 lowercase
601  * @param src source string
602  * @return converted result
603  */
604 char *
605 GNUNET_NAMESTORE_normalize_string (const char *src);
606
607
608 /**
609  * Convert a zone to a string (for printing debug messages).
610  * This is one of the very few calls in the entire API that is
611  * NOT reentrant!
612  *
613  * @param z public key of a zone
614  * @return string form; will be overwritten by next call to #GNUNET_NAMESTORE_z2s.
615  */
616 const char *
617 GNUNET_NAMESTORE_z2s (const struct GNUNET_CRYPTO_EcdsaPublicKey *z);
618
619
620 /**
621  * Convert public key to the respective absolute domain name in the
622  * ".zkey" pTLD.
623  * This is one of the very few calls in the entire API that is
624  * NOT reentrant!
625  *
626  * @param pkey a public key with a point on the eliptic curve
627  * @return string "X.zkey" where X is the coordinates of the public
628  *         key in an encoding suitable for DNS labels.
629  */
630 const char *
631 GNUNET_NAMESTORE_pkey_to_zkey (const struct GNUNET_CRYPTO_EcdsaPublicKey *pkey);
632
633
634 /**
635  * Convert an absolute domain name in the ".zkey" pTLD to the
636  * respective public key.
637  *
638  * @param zkey string "X.zkey" where X is the public
639  *         key in an encoding suitable for DNS labels.
640  * @param pkey set to a public key on the eliptic curve
641  * @return #GNUNET_SYSERR if @a zkey has the wrong syntax
642  */
643 int
644 GNUNET_NAMESTORE_zkey_to_pkey (const char *zkey,
645                                struct GNUNET_CRYPTO_EcdsaPublicKey *pkey);
646
647
648 /**
649  * Calculate the DHT query for a given @a label in a given @a zone.
650  *
651  * @param zone private key of the zone
652  * @param label label of the record
653  * @param query hash to use for the query
654  */
655 void
656 GNUNET_NAMESTORE_query_from_private_key (const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
657                                          const char *label,
658                                          struct GNUNET_HashCode *query);
659
660
661 /**
662  * Calculate the DHT query for a given @a label in a given @a zone.
663  *
664  * @param pub public key of the zone
665  * @param label label of the record
666  * @param query hash to use for the query
667  */
668 void
669 GNUNET_NAMESTORE_query_from_public_key (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
670                                         const char *label,
671                                         struct GNUNET_HashCode *query);
672
673
674 /**
675  * Sign name and records
676  *
677  * @param key the private key
678  * @param expire block expiration
679  * @param label the name for the records
680  * @param rd record data
681  * @param rd_count number of records in @a rd
682  */
683 struct GNUNET_NAMESTORE_Block *
684 GNUNET_NAMESTORE_block_create (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
685                                struct GNUNET_TIME_Absolute expire,
686                                const char *label,
687                                const struct GNUNET_NAMESTORE_RecordData *rd,
688                                unsigned int rd_count);
689
690
691 /**
692  * Check if a signature is valid.  This API is used by the GNS Block
693  * to validate signatures received from the network.
694  *
695  * @param block block to verify
696  * @return #GNUNET_OK if the signature is valid
697  */
698 int
699 GNUNET_NAMESTORE_block_verify (const struct GNUNET_NAMESTORE_Block *block);
700
701
702 /**
703  * Decrypt block.
704  *
705  * @param block block to decrypt
706  * @param zone_key public key of the zone
707  * @param label the name for the records
708  * @param proc function to call with the result
709  * @param proc_cls closure for @a proc
710  * @return #GNUNET_OK on success, #GNUNET_SYSERR if the block was
711  *        not well-formed
712  */
713 int
714 GNUNET_NAMESTORE_block_decrypt (const struct GNUNET_NAMESTORE_Block *block,
715                                 const struct GNUNET_CRYPTO_EcdsaPublicKey *zone_key,
716                                 const char *label,
717                                 GNUNET_NAMESTORE_RecordCallback proc,
718                                 void *proc_cls);
719
720
721 /**
722  * Compares if two records are equal
723  *
724  * @param a a record
725  * @param b another record
726  * @return #GNUNET_YES if the records are equal, or #GNUNET_NO if not.
727  */
728 int
729 GNUNET_NAMESTORE_records_cmp (const struct GNUNET_NAMESTORE_RecordData *a,
730                               const struct GNUNET_NAMESTORE_RecordData *b);
731
732
733 /**
734  * Returns the expiration time of the given block of records. The block
735  * expiration time is the expiration time of the record with smallest
736  * expiration time.
737  *
738  * @param rd_count number of records given in @a rd
739  * @param rd array of records
740  * @return absolute expiration time
741  */
742 struct GNUNET_TIME_Absolute
743 GNUNET_NAMESTORE_record_get_expiration_time (unsigned int rd_count,
744                                              const struct GNUNET_NAMESTORE_RecordData *rd);
745
746
747 #if 0                           /* keep Emacsens' auto-indent happy */
748 {
749 #endif
750 #ifdef __cplusplus
751 }
752 #endif
753
754 /* end of gnunet_namestore_service.h */
755 #endif