- htons => htonl
[oweals/gnunet.git] / src / topology / friends.c
1 /*
2      This file is part of GNUnet.
3      (C) 2013 Christian Grothoff
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 3, 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 topology/friends.c
23  * @brief library to read and write the FRIENDS file
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_friends_lib.h"
28
29
30 /**
31  * Parse the FRIENDS file.
32  *
33  * @param cfg our configuration
34  * @param cb function to call on each friend found
35  * @param cb_cls closure for @a cb
36  * @return #GNUNET_OK on success, #GNUNET_SYSERR on parsing errors
37  */
38 int
39 GNUNET_FRIENDS_parse (const struct GNUNET_CONFIGURATION_Handle *cfg,
40                       GNUNET_FRIENDS_Callback cb,
41                       void *cb_cls)
42 {
43   char *fn;
44   char *data;
45   size_t pos;
46   size_t start;
47   struct GNUNET_PeerIdentity pid;
48   uint64_t fsize;
49
50   if (GNUNET_OK !=
51       GNUNET_CONFIGURATION_get_value_filename (cfg,
52                                                "TOPOLOGY",
53                                                "FRIENDS",
54                                                &fn))
55   {
56     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
57                                "topology", "FRIENDS");
58     return GNUNET_SYSERR;
59   }
60   if ( (GNUNET_OK != GNUNET_DISK_file_test (fn)) &&
61        (GNUNET_OK != GNUNET_DISK_fn_write (fn, NULL, 0,
62                                            GNUNET_DISK_PERM_USER_READ |
63                                            GNUNET_DISK_PERM_USER_WRITE)) )
64       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "write", fn);
65   if ( (GNUNET_OK !=
66         GNUNET_DISK_file_size (fn,
67                                &fsize,
68                                GNUNET_NO, GNUNET_YES)) ||
69        (0 == fsize) )
70   {
71     GNUNET_free (fn);
72     return GNUNET_OK;
73   }
74   data = GNUNET_malloc_large (fsize);
75   if (NULL == data)
76   {
77     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "malloc");
78     GNUNET_free (fn);
79     return GNUNET_SYSERR;
80   }
81   if (fsize != GNUNET_DISK_fn_read (fn, data, fsize))
82   {
83     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "read", "fn");
84     GNUNET_free (fn);
85     GNUNET_free (data);
86     return GNUNET_SYSERR;
87   }
88   start = 0;
89   pos = 0;
90   while (pos < fsize)
91   {
92     while ((pos < fsize) && (! isspace ((int) data[pos])))
93       pos++;
94     if (GNUNET_OK !=
95         GNUNET_CRYPTO_eddsa_public_key_from_string (&data[start],
96                                                        pos - start,
97                                                        &pid.public_key))
98     {
99       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
100                   _("Syntax error in FRIENDS file at offset %llu, skipping bytes `%.*s'.\n"),
101                   (unsigned long long) pos,
102                   (int) (pos - start),
103                   &data[start]);
104       pos++;
105       start = pos;
106       continue;
107     }
108     pos++;
109     start = pos;
110     cb (cb_cls, &pid);
111   }
112   GNUNET_free (data);
113   GNUNET_free (fn);
114   return GNUNET_OK;
115 }
116
117
118 /**
119  * Handle for writing a friends file.
120  */
121 struct GNUNET_FRIENDS_Writer
122 {
123   /**
124    * Handle to the file.
125    */
126   struct GNUNET_DISK_FileHandle *fh;
127 };
128
129
130 /**
131  * Start writing a fresh FRIENDS file.  Will make a backup of the
132  * old one.
133  *
134  * @param cfg configuration to use.
135  * @return NULL on error
136  */
137 struct GNUNET_FRIENDS_Writer *
138 GNUNET_FRIENDS_write_start (const struct GNUNET_CONFIGURATION_Handle *cfg)
139 {
140   struct GNUNET_FRIENDS_Writer *w;
141   char *fn;
142
143   if (GNUNET_OK !=
144       GNUNET_CONFIGURATION_get_value_filename (cfg, "TOPOLOGY", "FRIENDS", &fn))
145   {
146     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
147                                "topology", "FRIENDS");
148     return NULL;
149   }
150   if (GNUNET_OK == GNUNET_DISK_file_test (fn))
151     GNUNET_DISK_file_backup (fn);
152   w = GNUNET_new (struct GNUNET_FRIENDS_Writer);
153   w->fh = GNUNET_DISK_file_open  (fn,
154                                   GNUNET_DISK_OPEN_CREATE |
155                                   GNUNET_DISK_OPEN_WRITE |
156                                   GNUNET_DISK_OPEN_FAILIFEXISTS,
157                                   GNUNET_DISK_PERM_USER_READ);
158   GNUNET_free (fn);
159   if (NULL == w->fh)
160   {
161     GNUNET_free (w);
162     return NULL;
163   }
164   return w;
165 }
166
167
168 /**
169  * Finish writing out the friends file.
170  *
171  * @param w write handle
172  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
173  */
174 int
175 GNUNET_FRIENDS_write_stop (struct GNUNET_FRIENDS_Writer *w)
176 {
177   int ret;
178
179   ret = GNUNET_DISK_file_close (w->fh);
180   GNUNET_free (w);
181   return ret;
182 }
183
184
185 /**
186  * Add a friend to the friends file.
187  *
188  * @param w write handle
189  * @param friend friend to add
190  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
191  */
192 int
193 GNUNET_FRIENDS_write (struct GNUNET_FRIENDS_Writer *w,
194                       const struct GNUNET_PeerIdentity *friend)
195 {
196   char *buf;
197   char *ret;
198   size_t slen;
199
200   ret = GNUNET_CRYPTO_eddsa_public_key_to_string (&friend->public_key);
201   GNUNET_asprintf (&buf,
202                    "%s\n",
203                    ret);
204   GNUNET_free (ret);
205   slen = strlen (buf);
206   if (slen !=
207       GNUNET_DISK_file_write (w->fh,
208                               buf,
209                               slen))
210   {
211     GNUNET_free (buf);
212     return GNUNET_SYSERR;
213   }
214   GNUNET_free (buf);
215   return GNUNET_OK;
216 }
217
218
219 /* end of friends.c */