error handling
[oweals/gnunet.git] / src / fs / fs_publish_ksk.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009, 2010, 2012, 2013 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      SPDX-License-Identifier: AGPL3.0-or-later
19  */
20
21 /**
22  * @file fs/fs_publish_ksk.c
23  * @brief publish a URI under a keyword in GNUnet
24  * @see https://gnunet.org/encoding and #2564
25  * @author Krista Bennett
26  * @author Christian Grothoff
27  */
28
29 #include "platform.h"
30 #include "gnunet_constants.h"
31 #include "gnunet_signatures.h"
32 #include "gnunet_util_lib.h"
33 #include "gnunet_fs_service.h"
34 #include "fs_api.h"
35 #include "fs_tree.h"
36 #include "fs_publish_ublock.h"
37
38 /**
39  * Context for the KSK publication.
40  */
41 struct GNUNET_FS_PublishKskContext
42 {
43   /**
44    * Keywords to use.
45    */
46   struct GNUNET_FS_Uri *ksk_uri;
47
48   /**
49    * URI to publish.
50    */
51   struct GNUNET_FS_Uri *uri;
52
53   /**
54    * Metadata to use.
55    */
56   struct GNUNET_CONTAINER_MetaData *meta;
57
58   /**
59    * Global FS context.
60    */
61   struct GNUNET_FS_Handle *h;
62
63   /**
64    * UBlock publishing operation that is active.
65    */
66   struct GNUNET_FS_PublishUblockContext *uc;
67
68   /**
69    * Handle to the datastore, NULL if we are just simulating.
70    */
71   struct GNUNET_DATASTORE_Handle *dsh;
72
73   /**
74    * Current task.
75    */
76   struct GNUNET_SCHEDULER_Task *ksk_task;
77
78   /**
79    * Function to call once we're done.
80    */
81   GNUNET_FS_PublishContinuation cont;
82
83   /**
84    * Closure for cont.
85    */
86   void *cont_cls;
87
88   /**
89    * When should the KBlocks expire?
90    */
91   struct GNUNET_FS_BlockOptions bo;
92
93   /**
94    * Options to use.
95    */
96   enum GNUNET_FS_PublishOptions options;
97
98   /**
99    * Keyword that we are currently processing.
100    */
101   unsigned int i;
102 };
103
104
105 /**
106  * Continuation of #GNUNET_FS_publish_ksk() that performs
107  * the actual publishing operation (iterating over all
108  * of the keywords).
109  *
110  * @param cls closure of type `struct PublishKskContext *`
111  */
112 static void
113 publish_ksk_cont (void *cls);
114
115
116 /**
117  * Function called by the datastore API with
118  * the result from the PUT request.
119  *
120  * @param cls closure of type `struct GNUNET_FS_PublishKskContext *`
121  * @param msg error message (or NULL)
122  */
123 static void
124 kb_put_cont (void *cls,
125              const char *msg)
126 {
127   struct GNUNET_FS_PublishKskContext *pkc = cls;
128
129   pkc->uc = NULL;
130   if (NULL != msg)
131   {
132     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
133                 "KBlock PUT operation failed: %s\n", msg);
134     pkc->cont (pkc->cont_cls, NULL, msg);
135     GNUNET_FS_publish_ksk_cancel (pkc);
136     return;
137   }
138   pkc->ksk_task = GNUNET_SCHEDULER_add_now (&publish_ksk_cont, pkc);
139 }
140
141
142 /**
143  * Continuation of #GNUNET_FS_publish_ksk() that performs the actual
144  * publishing operation (iterating over all of the keywords).
145  *
146  * @param cls closure of type `struct GNUNET_FS_PublishKskContext *`
147  */
148 static void
149 publish_ksk_cont (void *cls)
150 {
151   struct GNUNET_FS_PublishKskContext *pkc = cls;
152   const char *keyword;
153
154   pkc->ksk_task = NULL;
155   if ((pkc->i == pkc->ksk_uri->data.ksk.keywordCount) ||
156       (NULL == pkc->dsh))
157   {
158     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
159                 "KSK PUT operation complete\n");
160     pkc->cont (pkc->cont_cls, pkc->ksk_uri,
161                NULL);
162     GNUNET_FS_publish_ksk_cancel (pkc);
163     return;
164   }
165   keyword = pkc->ksk_uri->data.ksk.keywords[pkc->i++];
166   pkc->uc = GNUNET_FS_publish_ublock_ (pkc->h,
167                                        pkc->dsh,
168                                        keyword + 1 /* skip '+' */,
169                                        NULL,
170                                        GNUNET_CRYPTO_ecdsa_key_get_anonymous (),
171                                        pkc->meta,
172                                        pkc->uri,
173                                        &pkc->bo,
174                                        pkc->options,
175                                        &kb_put_cont, pkc);
176 }
177
178
179 /**
180  * Publish a CHK under various keywords on GNUnet.
181  *
182  * @param h handle to the file sharing subsystem
183  * @param ksk_uri keywords to use
184  * @param meta metadata to use
185  * @param uri URI to refer to in the KBlock
186  * @param bo per-block options
187  * @param options publication options
188  * @param cont continuation
189  * @param cont_cls closure for cont
190  * @return NULL on error ('cont' will still be called)
191  */
192 struct GNUNET_FS_PublishKskContext *
193 GNUNET_FS_publish_ksk (struct GNUNET_FS_Handle *h,
194                        const struct GNUNET_FS_Uri *ksk_uri,
195                        const struct GNUNET_CONTAINER_MetaData *meta,
196                        const struct GNUNET_FS_Uri *uri,
197                        const struct GNUNET_FS_BlockOptions *bo,
198                        enum GNUNET_FS_PublishOptions options,
199                        GNUNET_FS_PublishContinuation cont, void *cont_cls)
200 {
201   struct GNUNET_FS_PublishKskContext *pkc;
202
203   GNUNET_assert (NULL != uri);
204   pkc = GNUNET_new (struct GNUNET_FS_PublishKskContext);
205   pkc->h = h;
206   pkc->bo = *bo;
207   pkc->options = options;
208   pkc->cont = cont;
209   pkc->cont_cls = cont_cls;
210   pkc->meta = GNUNET_CONTAINER_meta_data_duplicate (meta);
211   if (0 == (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY))
212   {
213     pkc->dsh = GNUNET_DATASTORE_connect (h->cfg);
214     if (NULL == pkc->dsh)
215     {
216       cont (cont_cls,
217             NULL,
218             _ ("Could not connect to datastore."));
219       GNUNET_free (pkc);
220       return NULL;
221     }
222   }
223   pkc->uri = GNUNET_FS_uri_dup (uri);
224   pkc->ksk_uri = GNUNET_FS_uri_dup (ksk_uri);
225   pkc->ksk_task = GNUNET_SCHEDULER_add_now (&publish_ksk_cont, pkc);
226   return pkc;
227 }
228
229
230 /**
231  * Abort the KSK publishing operation.
232  *
233  * @param pkc context of the operation to abort.
234  */
235 void
236 GNUNET_FS_publish_ksk_cancel (struct GNUNET_FS_PublishKskContext *pkc)
237 {
238   if (NULL != pkc->ksk_task)
239   {
240     GNUNET_SCHEDULER_cancel (pkc->ksk_task);
241     pkc->ksk_task = NULL;
242   }
243   if (NULL != pkc->uc)
244   {
245     GNUNET_FS_publish_ublock_cancel_ (pkc->uc);
246     pkc->uc = NULL;
247   }
248   if (NULL != pkc->dsh)
249   {
250     GNUNET_DATASTORE_disconnect (pkc->dsh, GNUNET_NO);
251     pkc->dsh = NULL;
252   }
253   GNUNET_CONTAINER_meta_data_destroy (pkc->meta);
254   GNUNET_FS_uri_destroy (pkc->ksk_uri);
255   GNUNET_FS_uri_destroy (pkc->uri);
256   GNUNET_free (pkc);
257 }
258
259
260 /* end of fs_publish_ksk.c */