060b6f94b8f13f44f01affd454d0d1c988f16b93
[oweals/gnunet.git] / src / util / bio.c
1 /*
2      This file is part of GNUnet.
3      (C) 2006, 2009 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 /**
23  * @file util/bio.c
24  * @brief functions for buffering IO
25  * @author Christian Grothoff
26  */
27 #include "platform.h"
28 #include "gnunet_bio_lib.h"
29
30
31 /**
32  * Handle for buffered reading.
33  */
34 struct GNUNET_BIO_ReadHandle
35 {
36 };
37
38
39 /**
40  * Open a file for reading.
41  *
42  * @param fn file name to be opened
43  * @return IO handle on success, NULL on error
44  */
45 struct GNUNET_BIO_ReadHandle *GNUNET_BIO_read_open (const char *fn)
46 {
47   return NULL;
48 }
49
50
51 /**
52  * Close an open file.  Reports if any errors reading
53  * from the file were encountered.
54  *
55  * @param h file handle
56  * @param emsg set to the error message
57  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
58  */
59 int GNUNET_BIO_read_close (struct GNUNET_BIO_ReadHandle *h,
60                            char **emsg)
61 {
62   return GNUNET_SYSERR;
63 }
64
65
66 /**
67  * Read the contents of a binary file into a buffer.
68  *
69  * @param h handle to an open file
70  * @param what describes what is being read (for error message creation)
71  * @param result the buffer to write the result to
72  * @param len the number of bytes to read
73  * @return len on success, GNUNET_SYSERR on failure
74  */
75 ssize_t GNUNET_BIO_read (struct GNUNET_BIO_ReadHandle *h, 
76                          const char *what,
77                          void *result, 
78                          size_t len)
79 {
80 }
81
82
83 /**
84  * Read 0-terminated string from a file.
85  *
86  * @param h handle to an open file
87  * @param what describes what is being read (for error message creation)
88  * @param result the buffer to store a pointer to the (allocated) string to
89  *        (note that *result could be set to NULL as well)
90  * @return GNUNET_OK on success, GNUNET_SYSERR on failure
91  */
92 int GNUNET_BIO_read_string (struct GNUNET_BIO_ReadHandle *h, 
93                             const char *what,
94                             char **result)
95 {
96 }
97
98
99 /**
100  * Read metadata container from a file.
101  *
102  * @param h handle to an open file
103  * @param what describes what is being read (for error message creation)
104  * @param result the buffer to store a pointer to the (allocated) metadata
105  * @return GNUNET_OK on success, GNUNET_SYSERR on failure
106  */
107 int GNUNET_BIO_read_meta_data (struct GNUNET_BIO_ReadHandle *h, 
108                                const char *what,
109                                struct GNUNET_CONTAINER_MetaData **result)
110 {
111 }
112
113
114 /**
115  * Read an (u)int32_t.
116  *
117  * @param h hande to open file
118  * @param what describes what is being read (for error message creation)
119  * @param i address of 32-bit integer to read
120  * @return GNUNET_OK on success, GNUNET_SYSERR on error
121  */ 
122 int GNUNET_BIO_read_int32__ (struct GNUNET_BIO_ReadHandle *h, 
123                              const char *what,
124                              int32_t *i);
125
126
127 /**
128  * Read an (u)int64_t.
129  *
130  * @param h hande to open file
131  * @param what describes what is being read (for error message creation)
132  * @param i address of 64-bit integer to read
133  * @return GNUNET_OK on success, GNUNET_SYSERR on error
134  */ 
135 int GNUNET_BIO_read_int64__ (struct GNUNET_BIO_ReadHandle *h, 
136                              const char *what,
137                              int64_t *i);
138
139 /**
140  * Handle for buffered writing.
141  */
142 struct GNUNET_BIO_WriteHandle
143 {
144 };
145
146
147 /**
148  * Open a file for writing.
149  *
150  * @param fn file name to be opened
151  * @return IO handle on success, NULL on error
152  */
153 struct GNUNET_BIO_WriteHandle *GNUNET_BIO_write_open (const char *fn)
154 {
155   return NULL;
156 }
157
158
159 /**
160  * Close an open file for writing.
161  *
162  * @param h file handle
163  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
164  */
165 int GNUNET_BIO_write_close (struct GNUNET_BIO_WriteHandle *h);
166
167
168 /**
169  * Write a buffer to a file.
170  *
171  * @param h handle to open file
172  * @param buffer the data to write
173  * @param n number of bytes to write
174  * @return GNUNET_OK on success, GNUNET_SYSERR on error
175  */
176 ssize_t GNUNET_BIO_write (struct GNUNET_BIO_WriteHandle *h, 
177                           const void *buffer,
178                           size_t n);
179
180
181 /**
182  * Write a string to a file.
183  *
184  * @param h handle to open file
185  * @param s string to write (can be NULL)
186  * @return GNUNET_OK on success, GNUNET_SYSERR on error
187  */
188 int GNUNET_BIO_write_string (struct GNUNET_BIO_WriteHandle *h, 
189                              const char *s);
190
191
192
193
194 /**
195  * Write metadata container to a file.
196  *
197  * @param h handle to open file
198  * @param m metadata to write
199  * @return GNUNET_OK on success, GNUNET_SYSERR on error
200  */
201 int GNUNET_BIO_write_meta_data (struct GNUNET_BIO_WriteHandle *h, 
202                                 const struct GNUNET_CONTAINER_MetaData *m);
203
204
205
206 /**
207  * Write a float.
208  *
209  * @param h hande to open file
210  * @param f float to write (must be a variable)
211  */ 
212 #define GNUNET_BIO_write_float(h, f) (sizeof(float) == GNUNET_BIO_write (h, &f, sizeof(float)))
213
214
215
216 /**
217  * Write a double.
218  *
219  * @param h hande to open file
220  * @param f double to write (must be a variable)
221  */ 
222 #define GNUNET_BIO_write_float(h, f) (sizeof(double) == GNUNET_BIO_write (h, &f, sizeof(double)))
223
224
225 /**
226  * Write an (u)int32_t.
227  *
228  * @param h hande to open file
229  * @param i address of 32-bit integer to write
230  * @return GNUNET_OK on success, GNUNET_SYSERR on error
231  */ 
232 int GNUNET_BIO_write_int32 (struct GNUNET_BIO_ReadHandle *h, 
233                             int32_t i);
234
235
236 /**
237  * Write an (u)int64_t.
238  *
239  * @param h hande to open file
240  * @param i address of 64-bit integer to write
241  * @return GNUNET_OK on success, GNUNET_SYSERR on error
242  */ 
243 int GNUNET_BIO_write_int64 (struct GNUNET_BIO_ReadHandle *h, 
244                             int64_t i);
245
246
247
248
249
250 typedef struct
251 {
252   int fd;
253   unsigned int have;
254   unsigned int size;
255   char *buffer;
256 } WriteBuffer;
257
258 static void
259 write_buffered (WriteBuffer * wb, const void *s, unsigned int size)
260 {
261   const char *src = s;
262   unsigned int min;
263   unsigned int pos;
264   int ret;
265
266   if (wb->fd == -1)
267     return;
268   pos = 0;
269   do
270     {
271       /* first, just use buffer */
272       min = wb->size - wb->have;
273       if (min > size - pos)
274         min = size - pos;
275       memcpy (&wb->buffer[wb->have], &src[pos], min);
276       pos += min;
277       wb->have += min;
278       if (pos == size)
279         return;                 /* done */
280       GNUNET_GE_ASSERT (NULL, wb->have == wb->size);
281       ret = WRITE (wb->fd, wb->buffer, wb->size);
282       if (ret != wb->size)
283         {
284           CLOSE (wb->fd);
285           wb->fd = -1;
286           return;               /* error */
287         }
288       wb->have = 0;
289     }
290   while (pos < size);           /* should always be true */
291 }
292
293
294 static void
295 WRITEINT (WriteBuffer * wb, int val)
296 {
297   int big;
298   big = htonl (val);
299   write_buffered (wb, &big, sizeof (int));
300 }
301
302 static void
303 WRITELONG (WriteBuffer * wb, long long val)
304 {
305   long long big;
306   big = GNUNET_htonll (val);
307   write_buffered (wb, &big, sizeof (long long));
308 }
309
310 static void
311 writeURI (WriteBuffer * wb, const struct GNUNET_ECRS_URI *uri)
312 {
313   char *buf;
314   unsigned int size;
315
316   buf = GNUNET_ECRS_uri_to_string (uri);
317   size = strlen (buf);
318   WRITEINT (wb, size);
319   write_buffered (wb, buf, size);
320   GNUNET_free (buf);
321 }
322
323 static void
324 WRITESTRING (WriteBuffer * wb, const char *name)
325 {
326   GNUNET_GE_BREAK (NULL, name != NULL);
327   WRITEINT (wb, strlen (name));
328   write_buffered (wb, name, strlen (name));
329 }
330
331 static void
332 writeMetaData (struct GNUNET_GE_Context *ectx,
333                WriteBuffer * wb, const struct GNUNET_MetaData *meta)
334 {
335   unsigned int size;
336   char *buf;
337
338   size = GNUNET_meta_data_get_serialized_size (meta,
339                                                GNUNET_SERIALIZE_FULL
340                                                |
341                                                GNUNET_SERIALIZE_NO_COMPRESS);
342   if (size > 1024 * 1024)
343     size = 1024 * 1024;
344   buf = GNUNET_malloc (size);
345   GNUNET_meta_data_serialize (ectx,
346                               meta,
347                               buf,
348                               size,
349                               GNUNET_SERIALIZE_PART |
350                               GNUNET_SERIALIZE_NO_COMPRESS);
351   WRITEINT (wb, size);
352   write_buffered (wb, buf, size);
353   GNUNET_free (buf);
354 }
355
356
357 static void
358 writeFileInfo (struct GNUNET_GE_Context *ectx, WriteBuffer * wb,
359                const GNUNET_ECRS_FileInfo * fi)
360 {
361   writeMetaData (ectx, wb, fi->meta);
362   writeURI (wb, fi->uri);
363 }
364
365
366
367
368 typedef struct
369 {
370   int fd;
371   unsigned int have;
372   unsigned int size;
373   unsigned int pos;
374   char *buffer;
375 } ReadBuffer;
376
377 static int
378 read_buffered (ReadBuffer * rb, void *d, unsigned int size)
379 {
380   char *dst = d;
381   unsigned int min;
382   unsigned int pos;
383   int ret;
384
385   if (rb->fd == -1)
386     return -1;
387   pos = 0;
388   do
389     {
390       /* first, use buffer */
391       min = rb->have - rb->pos;
392       if (min > 0)
393         {
394           if (min > size - pos)
395             min = size - pos;
396           memcpy (&dst[pos], &rb->buffer[rb->pos], min);
397           rb->pos += min;
398           pos += min;
399         }
400       if (pos == size)
401         return pos;             /* done! */
402       GNUNET_GE_ASSERT (NULL, rb->have == rb->pos);
403       /* fill buffer */
404       ret = READ (rb->fd, rb->buffer, rb->size);
405       if (ret == -1)
406         {
407           CLOSE (rb->fd);
408           rb->fd = -1;
409           return -1;
410         }
411       if (ret == 0)
412         return 0;
413       rb->pos = 0;
414       rb->have = ret;
415     }
416   while (pos < size);           /* should always be true */
417   return pos;
418 }
419
420
421 static int
422 read_int (ReadBuffer * rb, int *val)
423 {
424   int big;
425
426   if (sizeof (int) != read_buffered (rb, &big, sizeof (int)))
427     return GNUNET_SYSERR;
428   *val = ntohl (big);
429   return GNUNET_OK;
430 }
431
432 static unsigned int
433 read_uint (ReadBuffer * rb, unsigned int *val)
434 {
435   unsigned int big;
436
437   if (sizeof (unsigned int) !=
438       read_buffered (rb, &big, sizeof (unsigned int)))
439     return GNUNET_SYSERR;
440   *val = ntohl (big);
441   return GNUNET_OK;
442 }
443
444 #define READINT(a) if (GNUNET_OK != read_int(rb, (int*) &a)) return GNUNET_SYSERR;
445
446 static int
447 read_long (ReadBuffer * rb, long long *val)
448 {
449   long long big;
450
451   if (sizeof (long long) != read_buffered (rb, &big, sizeof (long long)))
452     return GNUNET_SYSERR;
453   *val = GNUNET_ntohll (big);
454   return GNUNET_OK;
455 }
456
457 #define READLONG(a) if (GNUNET_OK != read_long(rb, (long long*) &a)) return GNUNET_SYSERR;
458
459 static struct GNUNET_ECRS_URI *
460 read_uri (struct GNUNET_GE_Context *ectx, ReadBuffer * rb)
461 {
462   char *buf;
463   struct GNUNET_ECRS_URI *ret;
464   unsigned int size;
465
466   if (GNUNET_OK != read_uint (rb, &size))
467     return NULL;
468   buf = GNUNET_malloc (size + 1);
469   buf[size] = '\0';
470   if (size != read_buffered (rb, buf, size))
471     {
472       GNUNET_free (buf);
473       return NULL;
474     }
475   ret = GNUNET_ECRS_string_to_uri (ectx, buf);
476   GNUNET_GE_BREAK (ectx, ret != NULL);
477   GNUNET_free (buf);
478   return ret;
479 }
480
481 #define READURI(u) if (NULL == (u = read_uri(ectx, rb))) return GNUNET_SYSERR;
482
483 static char *
484 read_string (ReadBuffer * rb, unsigned int maxLen)
485 {
486   char *buf;
487   unsigned int big;
488
489   if (GNUNET_OK != read_uint (rb, &big))
490     return NULL;
491   if (big > maxLen)
492     return NULL;
493   buf = GNUNET_malloc (big + 1);
494   buf[big] = '\0';
495   if (big != read_buffered (rb, buf, big))
496     {
497       GNUNET_free (buf);
498       return NULL;
499     }
500   return buf;
501 }
502
503 #define READSTRING(c, max) if (NULL == (c = read_string(rb, max))) return GNUNET_SYSERR;
504
505 /**
506  * Read file info from file.
507  *
508  * @return GNUNET_OK on success, GNUNET_SYSERR on error
509  */
510 static struct GNUNET_MetaData *
511 read_meta (struct GNUNET_GE_Context *ectx, ReadBuffer * rb)
512 {
513   unsigned int size;
514   char *buf;
515   struct GNUNET_MetaData *meta;
516
517   if (read_uint (rb, &size) != GNUNET_OK)
518     {
519       GNUNET_GE_BREAK (ectx, 0);
520       return NULL;
521     }
522   if (size > 1024 * 1024)
523     {
524       GNUNET_GE_BREAK (ectx, 0);
525       return NULL;
526     }
527   buf = GNUNET_malloc (size);
528   if (size != read_buffered (rb, buf, size))
529     {
530       GNUNET_free (buf);
531       GNUNET_GE_BREAK (ectx, 0);
532       return NULL;
533     }
534   meta = GNUNET_meta_data_deserialize (ectx, buf, size);
535   if (meta == NULL)
536     {
537       GNUNET_free (buf);
538       GNUNET_GE_BREAK (ectx, 0);
539       return NULL;
540     }
541   GNUNET_free (buf);
542   return meta;
543 }
544
545 /* end of bio.c */