add implementation of scheduler integration of curl context
[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 under the
6   terms of the GNU General Public License as published by the Free Software
7   Foundation; either version 3, or (at your option) any later version.
8
9   GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY
10   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
12
13   You should have received a copy of the GNU General Public License along with
14   GNUnet; see the file COPYING.  If not, If not, see
15   <http://www.gnu.org/licenses/>
16 */
17 /**
18  * @file curl/curl_reschedule.c
19  * @brief API for event loop integration with GNUnet SCHEDULER.
20  * @author Christian Grothoff
21  */
22 #include "platform.h"
23 #include "gnunet_curl_lib.h"
24 #include "gnunet_util_lib.h"
25
26
27 /**
28  * Closure for #GNUNET_CURL_gnunet_scheduler_reschedule().
29  */
30 struct GNUNET_CURL_RescheduleContext
31 {
32   /**
33    * Just the task.
34    */
35   struct GNUNET_SCHEDULER_Task *task;
36
37   /**
38    * Context we manage.
39    */
40   struct GNUNET_CURL_Context *ctx;
41 };
42
43
44 /**
45  * Initialize reschedule context.
46  *
47  * @param ctx context to manage
48  * @return closure for #GNUNET_CURL_gnunet_scheduler_reschedule().
49  */
50 struct GNUNET_CURL_RescheduleContext *
51 GNUNET_CURL_gnunet_rc_create (struct GNUNET_CURL_Context *ctx)
52 {
53   struct GNUNET_CURL_RescheduleContext *rc;
54
55   rc = GNUNET_new (struct GNUNET_CURL_RescheduleContext);
56   rc->ctx = ctx;
57   return rc;
58 }
59
60
61 /**
62  * Destroy reschedule context.
63  *
64  * @param rc context to destroy
65  */
66 void
67 GNUNET_CURL_gnunet_rc_destroy (struct GNUNET_CURL_RescheduleContext *rc)
68 {
69   if (NULL != rc->task)
70     GNUNET_SCHEDULER_cancel (rc->task);
71   GNUNET_free (rc);
72 }
73
74
75 /**
76  * Task that runs the context's event loop with the GNUnet scheduler.
77  *
78  * @param cls the `struct GNUNET_CURL_RescheduleContext`
79  */
80 static void
81 context_task (void *cls)
82 {
83   struct GNUNET_CURL_RescheduleContext *rc = cls;
84   long timeout;
85   int max_fd;
86   fd_set read_fd_set;
87   fd_set write_fd_set;
88   fd_set except_fd_set;
89   struct GNUNET_NETWORK_FDSet *rs;
90   struct GNUNET_NETWORK_FDSet *ws;
91   struct GNUNET_TIME_Relative delay;
92
93   rc->task = NULL;
94   GNUNET_CURL_perform (rc->ctx);
95   max_fd = -1;
96   timeout = -1;
97   FD_ZERO (&read_fd_set);
98   FD_ZERO (&write_fd_set);
99   FD_ZERO (&except_fd_set);
100   GNUNET_CURL_get_select_info (rc->ctx,
101                                &read_fd_set,
102                                &write_fd_set,
103                                &except_fd_set,
104                                &max_fd,
105                                &timeout);
106   if (timeout >= 0)
107     delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
108                                            timeout);
109   else
110     delay = GNUNET_TIME_UNIT_FOREVER_REL;
111   rs = GNUNET_NETWORK_fdset_create ();
112   GNUNET_NETWORK_fdset_copy_native (rs,
113                                     &read_fd_set,
114                                     max_fd + 1);
115   ws = GNUNET_NETWORK_fdset_create ();
116   GNUNET_NETWORK_fdset_copy_native (ws,
117                                     &write_fd_set,
118                                     max_fd + 1);
119   rc->task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
120                                           delay,
121                                           rs,
122                                           ws,
123                                           &context_task,
124                                           rc);
125   GNUNET_NETWORK_fdset_destroy (rs);
126   GNUNET_NETWORK_fdset_destroy (ws);
127 }
128
129
130 /**
131  * Implementation of the #GNUNET_CURL_RescheduleCallback for GNUnet's
132  * scheduler.  Will run the CURL context using GNUnet's scheduler.
133  * Note that you MUST immediately destroy the reschedule context after
134  * calling #GNUNET_CURL_fini().
135  *
136  * @param cls must point to a `struct GNUNET_CURL_RescheduleContext`
137  */
138 void
139 GNUNET_CURL_gnunet_scheduler_reschedule (void *cls)
140 {
141   struct GNUNET_CURL_RescheduleContext *rc = cls;
142
143   if (NULL != rc->task)
144     GNUNET_SCHEDULER_cancel (rc->task);
145   rc->task = GNUNET_SCHEDULER_add_now (&context_task,
146                                        rc);
147 }
148
149 /* end of curl_reschedule.c */