ensure datacache does not return expired records, fixig pq behavior with respect...
[oweals/gnunet.git] / src / pq / pq_result_helper.c
1  /*
2   This file is part of GNUnet
3   Copyright (C) 2014, 2015, 2016 GNUnet e.V.
4
5   GNUnet is free software: you can redistribute it and/or modify it
6   under the terms of the GNU Affero General Public License as published
7   by the Free Software Foundation, either version 3 of the License,
8   or (at your 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   Affero General Public License for more details.
14  
15   You should have received a copy of the GNU Affero General Public License
16   along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 /**
19  * @file pq/pq_result_helper.c
20  * @brief functions to extract result values
21  * @author Christian Grothoff
22  */
23 #include "platform.h"
24 #include "gnunet_util_lib.h"
25 #include "gnunet_pq_lib.h"
26
27
28 /**
29  * Function called to clean up memory allocated
30  * by a #GNUNET_PQ_ResultConverter.
31  *
32  * @param cls closure
33  * @param rd result data to clean up
34  */
35 static void
36 clean_varsize_blob (void *cls,
37                     void *rd)
38 {
39   void **dst = rd;
40
41   (void) cls;
42   if (NULL != *dst)
43   {
44     GNUNET_free (*dst);
45     *dst = NULL;
46   }
47 }
48
49
50 /**
51  * Extract data from a Postgres database @a result at row @a row.
52  *
53  * @param cls closure
54  * @param result where to extract data from
55  * @param int row to extract data from
56  * @param fname name (or prefix) of the fields to extract from
57  * @param[in,out] dst_size where to store size of result, may be NULL
58  * @param[out] dst where to store the result
59  * @return
60  *   #GNUNET_YES if all results could be extracted
61  *   #GNUNET_SYSERR if a result was invalid (non-existing field)
62  */
63 static int
64 extract_varsize_blob (void *cls,
65                       PGresult *result,
66                       int row,
67                       const char *fname,
68                       size_t *dst_size,
69                       void *dst)
70 {
71   size_t len;
72   const char *res;
73   void *idst;
74   int fnum;
75
76   (void) cls;
77   *dst_size = 0;
78   *((void **) dst) = NULL;
79
80   fnum = PQfnumber (result,
81                     fname);
82   if (fnum < 0)
83   {
84     GNUNET_break (0);
85     return GNUNET_SYSERR;
86   }
87   if (PQgetisnull (result,
88                    row,
89                    fnum))
90   {
91     /* Let's allow this for varsize */
92     return GNUNET_OK;
93   }
94   /* if a field is null, continue but
95    * remember that we now return a different result */
96   len = PQgetlength (result,
97                      row,
98                      fnum);
99   res = PQgetvalue (result,
100                     row,
101                     fnum);
102   GNUNET_assert (NULL != res);
103   *dst_size = len;
104   idst = GNUNET_malloc (len);
105   *((void **) dst) = idst;
106   GNUNET_memcpy (idst,
107                  res,
108                  len);
109   return GNUNET_OK;
110 }
111
112
113 /**
114  * Variable-size result expected.
115  *
116  * @param name name of the field in the table
117  * @param[out] dst where to store the result, allocated
118  * @param[out] sptr where to store the size of @a dst
119  * @return array entry for the result specification to use
120  */
121 struct GNUNET_PQ_ResultSpec
122 GNUNET_PQ_result_spec_variable_size (const char *name,
123                                      void **dst,
124                                      size_t *sptr)
125 {
126   struct GNUNET_PQ_ResultSpec res =
127     { &extract_varsize_blob,
128       &clean_varsize_blob, NULL,
129       (void *) (dst), 0, name, sptr };
130   return res;
131 }
132
133
134 /**
135  * Extract data from a Postgres database @a result at row @a row.
136  *
137  * @param cls closure
138  * @param result where to extract data from
139  * @param int row to extract data from
140  * @param fname name (or prefix) of the fields to extract from
141  * @param[in] dst_size desired size, never NULL
142  * @param[out] dst where to store the result
143  * @return
144  *   #GNUNET_YES if all results could be extracted
145  *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
146  */
147 static int
148 extract_fixed_blob (void *cls,
149                     PGresult *result,
150                     int row,
151                     const char *fname,
152                     size_t *dst_size,
153                     void *dst)
154 {
155   size_t len;
156   const char *res;
157   int fnum;
158
159   (void) cls;
160   fnum = PQfnumber (result,
161                     fname);
162   if (fnum < 0)
163   {
164     GNUNET_break (0);
165     return GNUNET_SYSERR;
166   }
167   if (PQgetisnull (result,
168                    row,
169                    fnum))
170   {
171     GNUNET_break (0);
172     return GNUNET_SYSERR;
173   }
174
175   /* if a field is null, continue but
176    * remember that we now return a different result */
177   len = PQgetlength (result,
178                      row,
179                      fnum);
180   if (*dst_size != len)
181   {
182     GNUNET_break (0);
183     return GNUNET_SYSERR;
184   }
185   res = PQgetvalue (result,
186                     row,
187                     fnum);
188   GNUNET_assert (NULL != res);
189   GNUNET_memcpy (dst,
190                  res,
191                  len);
192   return GNUNET_OK;
193 }
194
195
196 /**
197  * Fixed-size result expected.
198  *
199  * @param name name of the field in the table
200  * @param[out] dst where to store the result
201  * @param dst_size number of bytes in @a dst
202  * @return array entry for the result specification to use
203  */
204 struct GNUNET_PQ_ResultSpec
205 GNUNET_PQ_result_spec_fixed_size (const char *name,
206                                   void *dst,
207                                   size_t dst_size)
208 {
209   struct GNUNET_PQ_ResultSpec res =
210     { &extract_fixed_blob,
211       NULL, NULL,
212       (dst), dst_size, name, NULL };
213   return res;
214 }
215
216
217 /**
218  * Extract data from a Postgres database @a result at row @a row.
219  *
220  * @param cls closure
221  * @param result where to extract data from
222  * @param int row to extract data from
223  * @param fname name (or prefix) of the fields to extract from
224  * @param[in,out] dst_size where to store size of result, may be NULL
225  * @param[out] dst where to store the result
226  * @return
227  *   #GNUNET_YES if all results could be extracted
228  *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
229  */
230 static int
231 extract_rsa_public_key (void *cls,
232                         PGresult *result,
233                         int row,
234                         const char *fname,
235                         size_t *dst_size,
236                         void *dst)
237 {
238   struct GNUNET_CRYPTO_RsaPublicKey **pk = dst;
239   size_t len;
240   const char *res;
241   int fnum;
242
243   (void) cls;
244   *pk = NULL;
245   fnum = PQfnumber (result,
246                     fname);
247   if (fnum < 0)
248   {
249     GNUNET_break (0);
250     return GNUNET_SYSERR;
251   }
252   if (PQgetisnull (result,
253                    row,
254                    fnum))
255   {
256     GNUNET_break (0);
257     return GNUNET_SYSERR;
258   }
259   /* if a field is null, continue but
260    * remember that we now return a different result */
261   len = PQgetlength (result,
262                      row,
263                      fnum);
264   res = PQgetvalue (result,
265                     row,
266                     fnum);
267   *pk = GNUNET_CRYPTO_rsa_public_key_decode (res,
268                                              len);
269   if (NULL == *pk)
270   {
271     GNUNET_break (0);
272     return GNUNET_SYSERR;
273   }
274   return GNUNET_OK;
275 }
276
277
278 /**
279  * Function called to clean up memory allocated
280  * by a #GNUNET_PQ_ResultConverter.
281  *
282  * @param cls closure
283  * @param rd result data to clean up
284  */
285 static void
286 clean_rsa_public_key (void *cls,
287                       void *rd)
288 {
289   struct GNUNET_CRYPTO_RsaPublicKey **pk = rd;
290
291   (void) cls;
292   if (NULL != *pk)
293   {
294     GNUNET_CRYPTO_rsa_public_key_free (*pk);
295     *pk = NULL;
296   }
297 }
298
299
300 /**
301  * RSA public key expected.
302  *
303  * @param name name of the field in the table
304  * @param[out] rsa where to store the result
305  * @return array entry for the result specification to use
306  */
307 struct GNUNET_PQ_ResultSpec
308 GNUNET_PQ_result_spec_rsa_public_key (const char *name,
309                                       struct GNUNET_CRYPTO_RsaPublicKey **rsa)
310 {
311   struct GNUNET_PQ_ResultSpec res =
312     { &extract_rsa_public_key,
313       &clean_rsa_public_key,
314       NULL,
315       (void *) rsa, 0, name, NULL };
316   return res;
317 }
318
319
320 /**
321  * Extract data from a Postgres database @a result at row @a row.
322  *
323  * @param cls closure
324  * @param result where to extract data from
325  * @param int row to extract data from
326  * @param fname name (or prefix) of the fields to extract from
327  * @param[in,out] dst_size where to store size of result, may be NULL
328  * @param[out] dst where to store the result
329  * @return
330  *   #GNUNET_YES if all results could be extracted
331  *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
332  */
333 static int
334 extract_rsa_signature (void *cls,
335                        PGresult *result,
336                        int row,
337                        const char *fname,
338                        size_t *dst_size,
339                        void *dst)
340 {
341   struct GNUNET_CRYPTO_RsaSignature **sig = dst;
342   size_t len;
343   const char *res;
344   int fnum;
345
346   (void) cls;
347   *sig = NULL;
348   fnum = PQfnumber (result,
349                     fname);
350   if (fnum < 0)
351   {
352     GNUNET_break (0);
353     return GNUNET_SYSERR;
354   }
355   if (PQgetisnull (result,
356                    row,
357                    fnum))
358   {
359     GNUNET_break (0);
360     return GNUNET_SYSERR;
361   }
362   /* if a field is null, continue but
363    * remember that we now return a different result */
364   len = PQgetlength (result,
365                      row,
366                      fnum);
367   res = PQgetvalue (result,
368                     row,
369                     fnum);
370   *sig = GNUNET_CRYPTO_rsa_signature_decode (res,
371                                              len);
372   if (NULL == *sig)
373   {
374     GNUNET_break (0);
375     return GNUNET_SYSERR;
376   }
377   return GNUNET_OK;
378 }
379
380
381 /**
382  * Function called to clean up memory allocated
383  * by a #GNUNET_PQ_ResultConverter.
384  *
385  * @param cls closure
386  * @param rd result data to clean up
387  */
388 static void
389 clean_rsa_signature (void *cls,
390                      void *rd)
391 {
392   struct GNUNET_CRYPTO_RsaSignature **sig = rd;
393
394   (void) cls;
395   if (NULL != *sig)
396   {
397     GNUNET_CRYPTO_rsa_signature_free (*sig);
398     *sig = NULL;
399   }
400 }
401
402
403 /**
404  * RSA signature expected.
405  *
406  * @param name name of the field in the table
407  * @param[out] sig where to store the result;
408  * @return array entry for the result specification to use
409  */
410 struct GNUNET_PQ_ResultSpec
411 GNUNET_PQ_result_spec_rsa_signature (const char *name,
412                                     struct GNUNET_CRYPTO_RsaSignature **sig)
413 {
414   struct GNUNET_PQ_ResultSpec res =
415     { &extract_rsa_signature,
416       &clean_rsa_signature,
417       NULL,
418       (void *) sig, 0, (name), NULL };
419   return res;
420 }
421
422
423 /**
424  * Extract data from a Postgres database @a result at row @a row.
425  *
426  * @param cls closure
427  * @param result where to extract data from
428  * @param int row to extract data from
429  * @param fname name (or prefix) of the fields to extract from
430  * @param[in,out] dst_size where to store size of result, may be NULL
431  * @param[out] dst where to store the result
432  * @return
433  *   #GNUNET_YES if all results could be extracted
434  *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
435  */
436 static int
437 extract_string (void *cls,
438                 PGresult *result,
439                 int row,
440                 const char *fname,
441                 size_t *dst_size,
442                 void *dst)
443 {
444   char **str = dst;
445   size_t len;
446   const char *res;
447   int fnum;
448
449   (void) cls;
450   *str = NULL;
451   fnum = PQfnumber (result,
452                     fname);
453   if (fnum < 0)
454   {
455     GNUNET_break (0);
456     return GNUNET_SYSERR;
457   }
458   if (PQgetisnull (result,
459                    row,
460                    fnum))
461   {
462     GNUNET_break (0);
463     return GNUNET_SYSERR;
464   }
465   /* if a field is null, continue but
466    * remember that we now return a different result */
467   len = PQgetlength (result,
468                      row,
469                      fnum);
470   res = PQgetvalue (result,
471                     row,
472                     fnum);
473   *str = GNUNET_strndup (res,
474                          len);
475   if (NULL == *str)
476   {
477     GNUNET_break (0);
478     return GNUNET_SYSERR;
479   }
480   return GNUNET_OK;
481 }
482
483
484 /**
485  * Function called to clean up memory allocated
486  * by a #GNUNET_PQ_ResultConverter.
487  *
488  * @param cls closure
489  * @param rd result data to clean up
490  */
491 static void
492 clean_string (void *cls,
493               void *rd)
494 {
495   char **str = rd;
496
497   (void) cls;
498   if (NULL != *str)
499   {
500     GNUNET_free (*str);
501     *str = NULL;
502   }
503 }
504
505
506 /**
507  * 0-terminated string expected.
508  *
509  * @param name name of the field in the table
510  * @param[out] dst where to store the result, allocated
511  * @return array entry for the result specification to use
512  */
513 struct GNUNET_PQ_ResultSpec
514 GNUNET_PQ_result_spec_string (const char *name,
515                               char **dst)
516 {
517   struct GNUNET_PQ_ResultSpec res =
518     { &extract_string,
519       &clean_string,
520       NULL,
521       (void *) dst, 0, (name), NULL };
522   return res;
523 }
524
525
526 /**
527  * Extract data from a Postgres database @a result at row @a row.
528  *
529  * @param cls closure
530  * @param result where to extract data from
531  * @param int row to extract data from
532  * @param fname name (or prefix) of the fields to extract from
533  * @param[in,out] dst_size where to store size of result, may be NULL
534  * @param[out] dst where to store the result
535  * @return
536  *   #GNUNET_YES if all results could be extracted
537  *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
538  */
539 static int
540 extract_abs_time (void *cls,
541                   PGresult *result,
542                   int row,
543                   const char *fname,
544                   size_t *dst_size,
545                   void *dst)
546 {
547   struct GNUNET_TIME_Absolute *udst = dst;
548   const int64_t *res;
549   int fnum;
550
551   (void) cls;
552   fnum = PQfnumber (result,
553                     fname);
554   if (fnum < 0)
555   {
556     GNUNET_break (0);
557     return GNUNET_SYSERR;
558   }
559   if (PQgetisnull (result,
560                    row,
561                    fnum))
562   {
563     GNUNET_break (0);
564     return GNUNET_SYSERR;
565   }
566   GNUNET_assert (NULL != dst);
567   if (sizeof (struct GNUNET_TIME_Absolute) != *dst_size)
568   {
569     GNUNET_break (0);
570     return GNUNET_SYSERR;
571   }
572   if (sizeof (int64_t) !=
573       PQgetlength (result,
574                    row,
575                    fnum))
576   {
577     GNUNET_break (0);
578     return GNUNET_SYSERR;
579   }
580   res = (int64_t *) PQgetvalue (result,
581                                 row,
582                                 fnum);
583   if (INT64_MAX == *res)
584     *udst = GNUNET_TIME_UNIT_FOREVER_ABS;
585   else
586     udst->abs_value_us = GNUNET_ntohll ((uint64_t) *res);
587   return GNUNET_OK;
588 }
589
590
591 /**
592  * Absolute time expected.
593  *
594  * @param name name of the field in the table
595  * @param[out] at where to store the result
596  * @return array entry for the result specification to use
597  */
598 struct GNUNET_PQ_ResultSpec
599 GNUNET_PQ_result_spec_absolute_time (const char *name,
600                                      struct GNUNET_TIME_Absolute *at)
601 {
602   struct GNUNET_PQ_ResultSpec res =
603     { &extract_abs_time,
604       NULL,
605       NULL,
606       (void *) at, sizeof (*at), (name), NULL };
607   return res;
608 }
609
610
611 /**
612  * Absolute time in network byte order expected.
613  *
614  * @param name name of the field in the table
615  * @param[out] at where to store the result
616  * @return array entry for the result specification to use
617  */
618 struct GNUNET_PQ_ResultSpec
619 GNUNET_PQ_result_spec_absolute_time_nbo (const char *name,
620                                          struct GNUNET_TIME_AbsoluteNBO *at)
621 {
622   struct GNUNET_PQ_ResultSpec res =
623     GNUNET_PQ_result_spec_auto_from_type(name, &at->abs_value_us__);
624   return res;
625 }
626
627
628 /**
629  * Extract data from a Postgres database @a result at row @a row.
630  *
631  * @param cls closure
632  * @param result where to extract data from
633  * @param int row to extract data from
634  * @param fname name (or prefix) of the fields to extract from
635  * @param[in,out] dst_size where to store size of result, may be NULL
636  * @param[out] dst where to store the result
637  * @return
638  *   #GNUNET_YES if all results could be extracted
639  *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
640  */
641 static int
642 extract_uint16 (void *cls,
643                 PGresult *result,
644                 int row,
645                 const char *fname,
646                 size_t *dst_size,
647                 void *dst)
648 {
649   uint16_t *udst = dst;
650   const uint16_t *res;
651   int fnum;
652
653   (void) cls;
654   fnum = PQfnumber (result,
655                     fname);
656   if (fnum < 0)
657   {
658     GNUNET_break (0);
659     return GNUNET_SYSERR;
660   }
661   if (PQgetisnull (result,
662                    row,
663                    fnum))
664   {
665     GNUNET_break (0);
666     return GNUNET_SYSERR;
667   }
668   GNUNET_assert (NULL != dst);
669   if (sizeof (uint16_t) != *dst_size)
670   {
671     GNUNET_break (0);
672     return GNUNET_SYSERR;
673   }
674   if (sizeof (uint16_t) !=
675       PQgetlength (result,
676                    row,
677                    fnum))
678   {
679     GNUNET_break (0);
680     return GNUNET_SYSERR;
681   }
682   res = (uint16_t *) PQgetvalue (result,
683                                  row,
684                                  fnum);
685   *udst = ntohs (*res);
686   return GNUNET_OK;
687 }
688
689
690 /**
691  * uint16_t expected.
692  *
693  * @param name name of the field in the table
694  * @param[out] u16 where to store the result
695  * @return array entry for the result specification to use
696  */
697 struct GNUNET_PQ_ResultSpec
698 GNUNET_PQ_result_spec_uint16 (const char *name,
699                               uint16_t *u16)
700 {
701   struct GNUNET_PQ_ResultSpec res =
702     { &extract_uint16,
703       NULL,
704       NULL,
705       (void *) u16, sizeof (*u16), (name), NULL };
706   return res;
707 }
708
709
710 /**
711  * Extract data from a Postgres database @a result at row @a row.
712  *
713  * @param cls closure
714  * @param result where to extract data from
715  * @param int row to extract data from
716  * @param fname name (or prefix) of the fields to extract from
717  * @param[in,out] dst_size where to store size of result, may be NULL
718  * @param[out] dst where to store the result
719  * @return
720  *   #GNUNET_YES if all results could be extracted
721  *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
722  */
723 static int
724 extract_uint32 (void *cls,
725                 PGresult *result,
726                 int row,
727                 const char *fname,
728                 size_t *dst_size,
729                 void *dst)
730 {
731   uint32_t *udst = dst;
732   const uint32_t *res;
733   int fnum;
734
735   (void) cls;
736   fnum = PQfnumber (result,
737                     fname);
738   if (fnum < 0)
739   {
740     GNUNET_break (0);
741     return GNUNET_SYSERR;
742   }
743   if (PQgetisnull (result,
744                    row,
745                    fnum))
746   {
747     GNUNET_break (0);
748     return GNUNET_SYSERR;
749   }
750   GNUNET_assert (NULL != dst);
751   if (sizeof (uint32_t) != *dst_size)
752   {
753     GNUNET_break (0);
754     return GNUNET_SYSERR;
755   }
756   if (sizeof (uint32_t) !=
757       PQgetlength (result,
758                    row,
759                    fnum))
760   {
761     GNUNET_break (0);
762     return GNUNET_SYSERR;
763   }
764   res = (uint32_t *) PQgetvalue (result,
765                                  row,
766                                  fnum);
767   *udst = ntohl (*res);
768   return GNUNET_OK;
769 }
770
771
772 /**
773  * uint32_t expected.
774  *
775  * @param name name of the field in the table
776  * @param[out] u32 where to store the result
777  * @return array entry for the result specification to use
778  */
779 struct GNUNET_PQ_ResultSpec
780 GNUNET_PQ_result_spec_uint32 (const char *name,
781                               uint32_t *u32)
782 {
783   struct GNUNET_PQ_ResultSpec res =
784     { &extract_uint32,
785       NULL,
786       NULL,
787       (void *) u32, sizeof (*u32), (name), NULL };
788   return res;
789 }
790
791
792 /**
793  * Extract data from a Postgres database @a result at row @a row.
794  *
795  * @param cls closure
796  * @param result where to extract data from
797  * @param int row to extract data from
798  * @param fname name (or prefix) of the fields to extract from
799  * @param[in,out] dst_size where to store size of result, may be NULL
800  * @param[out] dst where to store the result
801  * @return
802  *   #GNUNET_YES if all results could be extracted
803  *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
804  */
805 static int
806 extract_uint64 (void *cls,
807                 PGresult *result,
808                 int row,
809                 const char *fname,
810                 size_t *dst_size,
811                 void *dst)
812 {
813   uint64_t *udst = dst;
814   const uint64_t *res;
815   int fnum;
816
817   (void) cls;
818   fnum = PQfnumber (result,
819                     fname);
820   if (fnum < 0)
821   {
822     GNUNET_break (0);
823     return GNUNET_SYSERR;
824   }
825   if (PQgetisnull (result,
826                    row,
827                    fnum))
828   {
829     GNUNET_break (0);
830     return GNUNET_SYSERR;
831   }
832   GNUNET_assert (NULL != dst);
833   if (sizeof (uint64_t) != *dst_size)
834   {
835     GNUNET_break (0);
836     return GNUNET_SYSERR;
837   }
838   if (sizeof (uint64_t) !=
839       PQgetlength (result,
840                    row,
841                    fnum))
842   {
843     GNUNET_break (0);
844     return GNUNET_SYSERR;
845   }
846   res = (uint64_t *) PQgetvalue (result,
847                                  row,
848                                  fnum);
849   *udst = GNUNET_ntohll (*res);
850   return GNUNET_OK;
851 }
852
853
854 /**
855  * uint64_t expected.
856  *
857  * @param name name of the field in the table
858  * @param[out] u64 where to store the result
859  * @return array entry for the result specification to use
860  */
861 struct GNUNET_PQ_ResultSpec
862 GNUNET_PQ_result_spec_uint64 (const char *name,
863                               uint64_t *u64)
864 {
865   struct GNUNET_PQ_ResultSpec res =
866     { &extract_uint64,
867       NULL,
868       NULL,
869       (void *) u64, sizeof (*u64), (name), NULL };
870   return res;
871 }
872
873
874 /* end of pq_result_helper.c */