aboutsummaryrefslogtreecommitdiff
path: root/src/lib/common/watch.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/common/watch.c')
-rw-r--r--src/lib/common/watch.c235
1 files changed, 235 insertions, 0 deletions
diff --git a/src/lib/common/watch.c b/src/lib/common/watch.c
new file mode 100644
index 0000000..e6b5317
--- /dev/null
+++ b/src/lib/common/watch.c
@@ -0,0 +1,235 @@
1#include "watch.h"
2
3#include <stdbool.h>
4
5#define LOG(kind, ...) GNUNET_log_from (kind, "dbus-watch", __VA_ARGS__)
6
7/*
8 * Wraps a file descriptor that needs to be watched
9 * for activity with select()
10 */
11struct Watch
12{
13 /*
14 * DBus watch data. Contains the actual file descritor wrapped by libdbus
15 */
16 DBusWatch *watch;
17
18 /*
19 * Have we asked the scheduler to watch this?
20 * Will be false if the associated task has not been
21 * re-scheduled yet after execution or because dbus has asked
22 * us to disable this watch.
23 */
24 bool scheduled;
25
26 /*
27 * The task that is watching our file descriptor.
28 * Only valid if scheduled is true.
29 */
30 struct GNUNET_SCHEDULER_Task *task;
31
32 struct GNUNET_NETWORK_Handle *net_handle;
33 struct GNUNET_DISK_FileHandle *file_handle;
34
35 unsigned ref_count;
36};
37
38struct Watch *
39watch_create (
40 DBusWatch *watch)
41{
42 struct Watch *w = GNUNET_new (struct Watch);
43
44 w->watch = watch;
45 w->scheduled = false;
46 w->net_handle = NULL;
47 w->file_handle = NULL;
48 w->ref_count = 1;
49
50 SOCKTYPE sock = dbus_watch_get_socket (watch);
51 if (-1 != sock)
52 {
53 w->net_handle = GNUNET_NETWORK_socket_box_native (sock);
54 if (NULL == w->net_handle)
55 {
56 LOG (GNUNET_ERROR_TYPE_ERROR, "Failed to box network socket passed in from dbus.\n");
57 GNUNET_abort_ ();
58 };
59 }
60 else {
61 int fd = dbus_watch_get_unix_fd (watch);
62 if (-1 != fd)
63 {
64 w->file_handle = GNUNET_DISK_get_handle_from_int_fd (fd);
65 if (NULL == w->file_handle)
66 {
67 LOG (GNUNET_ERROR_TYPE_ERROR, "Failed to box file handle passed in from dbus.\n");
68 GNUNET_abort_ ();
69 };
70 };
71 };
72
73 if (! w->net_handle && ! w->file_handle)
74 {
75 LOG (GNUNET_ERROR_TYPE_ERROR, "Failed to create watch. dbus_watch_get_socket returned %d\n", (int)sock);
76 GNUNET_abort_ ();
77 };
78
79 return w;
80};
81
82void
83watch_ref (
84 struct Watch *w)
85{
86 w->ref_count++;
87};
88
89void
90watch_unref (
91 struct Watch *w)
92{
93 if (0 == w->ref_count)
94 {
95 LOG (GNUNET_ERROR_TYPE_ERROR, "Tried to unref watch with ref_count == 0\n");
96 GNUNET_abort_ ();
97 };
98
99 if (0 == --w->ref_count)
100 {
101 if (w->net_handle)
102 GNUNET_free (w->net_handle);
103 if (w->file_handle)
104 GNUNET_free (w->file_handle);
105
106 GNUNET_free (w);
107 }
108};
109
110/*
111 * Callback called by the scheduler to tell libdbus that there is activity on
112 * one of its file descriptors.
113 *
114 * @param cls The watch
115 * @param tc the context given to us by the scheduler for this execution
116 */
117void
118handle_watch (
119 void *cls,
120 const struct GNUNET_SCHEDULER_TaskContext *tc)
121{
122 struct Watch *w = (struct Watch *)cls;
123
124 w->scheduled = false;
125
126 unsigned flags = 0;
127 if (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)
128 flags |= DBUS_WATCH_READABLE;
129 if (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)
130 flags |= DBUS_WATCH_WRITABLE;
131 if (flags)
132 {
133 dbus_watch_handle(w->watch, flags);
134 };
135
136 if(w->ref_count > 1 && ! (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
137 watch_schedule (w);
138 watch_unref (w);
139};
140
141/*
142 * Ask the scheduler to watch this watch for activity.
143 *
144 * @param w The watch
145 * @return GNUNET_OK or GNUNET_SYSERR
146 */
147void
148watch_schedule (
149 struct Watch *w)
150{
151 unsigned flags = dbus_watch_get_flags (w->watch);
152
153 if (! dbus_watch_get_enabled (w->watch))
154 {
155 LOG (GNUNET_ERROR_TYPE_WARNING, "Tried to schedule watch that is disabled!\n");
156 return;
157 };
158
159 if (w->scheduled)
160 return;
161
162 if (w->net_handle)
163 {
164 w->task = GNUNET_SCHEDULER_add_net_with_priority(
165 GNUNET_TIME_UNIT_FOREVER_REL,
166 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
167 w->net_handle,
168 flags & DBUS_WATCH_READABLE,
169 flags & DBUS_WATCH_WRITABLE,
170 handle_watch,
171 w);
172 w->scheduled = true;
173 watch_ref (w);
174 return;
175 };
176
177 if (w->file_handle)
178 {
179 w->task = GNUNET_SCHEDULER_add_file_with_priority(
180 GNUNET_TIME_UNIT_FOREVER_REL,
181 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
182 w->file_handle,
183 flags & DBUS_WATCH_READABLE,
184 flags & DBUS_WATCH_WRITABLE,
185 handle_watch,
186 w);
187 w->scheduled = true;
188 watch_ref (w);
189 return;
190 };
191
192 LOG (GNUNET_ERROR_TYPE_ERROR, "Failed to schedule watch.\n");
193 GNUNET_abort_ ();
194};
195
196/*
197 * Ask the scheduler to stop monitoring a watch either because we are shutting
198 * down or dbus has asked us to disable this watch.
199 *
200 * @param w The watch
201 * @return GNUNET_OK or GNUNET_SYSERR
202 */
203void
204do_watch_unschedule (
205 void *cls,
206 const struct GNUNET_SCHEDULER_TaskContext *tc)
207{
208 (void)tc;
209 struct Watch *w = (struct Watch *)cls;
210
211 if (! w->scheduled)
212 return;
213
214 void *ret = GNUNET_SCHEDULER_cancel (w->task);
215 if ((struct Watch *)ret != w)
216 LOG (GNUNET_ERROR_TYPE_WARNING, "Weird result unscheduling task. w == %p, GNUNET_SCHEDULER_cancel returned %p\n", w, ret);
217
218 watch_unref (w);
219};
220
221void
222watch_unschedule (
223 struct Watch *w)
224{
225 GNUNET_SCHEDULER_add_now (do_watch_unschedule, w);
226};
227
228struct WatchIter *
229watch_find (struct WatchIter *wi, DBusWatch *watch)
230{
231 while (wi && wi->w->watch != watch)
232 wi = wi->next;
233 return wi;
234};
235