error handling
[oweals/gnunet.git] / src / curl / curl_reschedule.c
1 /*
2    This file is part of GNUnet
3    Copyright (C) 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      SPDX-License-Identifier: AGPL3.0-or-later
19  */
20 /**
21  * @file curl/curl_reschedule.c
22  * @brief API for event loop integration with GNUnet SCHEDULER.
23  * @author Christian Grothoff
24  */
25 #include "platform.h"
26 #include <jansson.h>
27 #include "gnunet_curl_lib.h"
28 #include "gnunet_util_lib.h"
29
30 extern void *
31 GNUNET_CURL_download_get_result_ (struct GNUNET_CURL_DownloadBuffer *db,
32                                   CURL *eh,
33                                   long *response_code);
34
35 /**
36  * Closure for #GNUNET_CURL_gnunet_scheduler_reschedule().
37  */
38 struct GNUNET_CURL_RescheduleContext
39 {
40   /**
41    * Just the task.
42    */
43   struct GNUNET_SCHEDULER_Task *task;
44
45   /**
46    * Context we manage.
47    */
48   struct GNUNET_CURL_Context *ctx;
49
50   /**
51    * Parser of the raw response.
52    */
53   GNUNET_CURL_RawParser parser;
54
55   /**
56    * Deallocate the response object.
57    */
58   GNUNET_CURL_ResponseCleaner cleaner;
59 };
60
61
62 /**
63  * Initialize reschedule context; with custom response parser
64  *
65  * @param ctx context to manage
66  * @return closure for #GNUNET_CURL_gnunet_scheduler_reschedule().
67  */
68 struct GNUNET_CURL_RescheduleContext *
69 GNUNET_CURL_gnunet_rc_create_with_parser (struct GNUNET_CURL_Context *ctx,
70                                           GNUNET_CURL_RawParser rp,
71                                           GNUNET_CURL_ResponseCleaner rc)
72 {
73   struct GNUNET_CURL_RescheduleContext *rctx;
74
75   rctx = GNUNET_new (struct GNUNET_CURL_RescheduleContext);
76   rctx->ctx = ctx;
77   rctx->parser = rp;
78   rctx->cleaner = rc;
79
80   return rctx;
81 }
82
83
84 /**
85  * Just a wrapper to avoid casting of function pointers.
86  *
87  * @param response the (JSON) response to clean.
88  */
89 static void
90 clean_result (void *response)
91 {
92   json_decref (response);
93 }
94
95
96 /**
97  * Initialize reschedule context.
98  *
99  * @param ctx context to manage
100  * @return closure for #GNUNET_CURL_gnunet_scheduler_reschedule().
101  */
102 struct GNUNET_CURL_RescheduleContext *
103 GNUNET_CURL_gnunet_rc_create (struct GNUNET_CURL_Context *ctx)
104 {
105   struct GNUNET_CURL_RescheduleContext *rc;
106
107   rc = GNUNET_new (struct GNUNET_CURL_RescheduleContext);
108   rc->ctx = ctx;
109   rc->parser = &GNUNET_CURL_download_get_result_;
110   rc->cleaner = &clean_result;
111   return rc;
112 }
113
114
115 /**
116  * Destroy reschedule context.
117  *
118  * @param rc context to destroy
119  */
120 void
121 GNUNET_CURL_gnunet_rc_destroy (struct GNUNET_CURL_RescheduleContext *rc)
122 {
123   if (NULL != rc->task)
124     GNUNET_SCHEDULER_cancel (rc->task);
125   GNUNET_free (rc);
126 }
127
128
129 /**
130  * Task that runs the context's event loop with the GNUnet scheduler.
131  *
132  * @param cls a `struct GNUNET_CURL_RescheduleContext *`
133  */
134 static void
135 context_task (void *cls)
136 {
137   struct GNUNET_CURL_RescheduleContext *rc = cls;
138   long timeout;
139   int max_fd;
140   fd_set read_fd_set;
141   fd_set write_fd_set;
142   fd_set except_fd_set;
143   struct GNUNET_NETWORK_FDSet *rs;
144   struct GNUNET_NETWORK_FDSet *ws;
145   struct GNUNET_TIME_Relative delay;
146
147   rc->task = NULL;
148   GNUNET_CURL_perform2 (rc->ctx, rc->parser, rc->cleaner);
149   max_fd = -1;
150   timeout = -1;
151   FD_ZERO (&read_fd_set);
152   FD_ZERO (&write_fd_set);
153   FD_ZERO (&except_fd_set);
154   GNUNET_CURL_get_select_info (rc->ctx,
155                                &read_fd_set,
156                                &write_fd_set,
157                                &except_fd_set,
158                                &max_fd,
159                                &timeout);
160   if (timeout >= 0)
161     delay =
162       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, timeout);
163   else
164     delay = GNUNET_TIME_UNIT_FOREVER_REL;
165   rs = GNUNET_NETWORK_fdset_create ();
166   GNUNET_NETWORK_fdset_copy_native (rs, &read_fd_set, max_fd + 1);
167   ws = GNUNET_NETWORK_fdset_create ();
168   GNUNET_NETWORK_fdset_copy_native (ws, &write_fd_set, max_fd + 1);
169   if (NULL == rc->task)
170     rc->task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
171                                             delay,
172                                             rs,
173                                             ws,
174                                             &context_task,
175                                             rc);
176   GNUNET_NETWORK_fdset_destroy (rs);
177   GNUNET_NETWORK_fdset_destroy (ws);
178 }
179
180
181 /**
182  * Implementation of the #GNUNET_CURL_RescheduleCallback for GNUnet's
183  * scheduler.  Will run the CURL context using GNUnet's scheduler.
184  * Note that you MUST immediately destroy the reschedule context after
185  * calling #GNUNET_CURL_fini().
186  *
187  * @param cls must point to a `struct GNUNET_CURL_RescheduleContext *`
188  *           (pointer to a pointer!)
189  */
190 void
191 GNUNET_CURL_gnunet_scheduler_reschedule (void *cls)
192 {
193   struct GNUNET_CURL_RescheduleContext *rc = *(void **) cls;
194
195   if (NULL != rc->task)
196     GNUNET_SCHEDULER_cancel (rc->task);
197   rc->task = GNUNET_SCHEDULER_add_now (&context_task, rc);
198 }
199
200
201 /* end of curl_reschedule.c */