diff options
author | Nathan S. Evans <evans@in.tum.de> | 2010-03-11 10:38:11 +0000 |
---|---|---|
committer | Nathan S. Evans <evans@in.tum.de> | 2010-03-11 10:38:11 +0000 |
commit | 49da466bce647497cfc034db9e9761804e9d1a36 (patch) | |
tree | 65e289dcdb8c985ffa9ff4d243af6daeb83a6477 /src/dv/dv_api.c | |
parent | e927f9bbf828bfc5038323c39aa3046ef948afe5 (diff) | |
download | gnunet-49da466bce647497cfc034db9e9761804e9d1a36.tar.gz gnunet-49da466bce647497cfc034db9e9761804e9d1a36.zip |
shell for dv plugin and service, not yet working
Diffstat (limited to 'src/dv/dv_api.c')
-rw-r--r-- | src/dv/dv_api.c | 392 |
1 files changed, 392 insertions, 0 deletions
diff --git a/src/dv/dv_api.c b/src/dv/dv_api.c new file mode 100644 index 000000000..8c536b207 --- /dev/null +++ b/src/dv/dv_api.c | |||
@@ -0,0 +1,392 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2009, 2010 Christian Grothoff (and other contributing authors) | ||
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 2, 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 transport/dv_api.c | ||
23 | * @brief library to access the DV service | ||
24 | * @author Christian Grothoff | ||
25 | * @author Not Nathan Evans | ||
26 | */ | ||
27 | #include "platform.h" | ||
28 | #include "gnunet_bandwidth_lib.h" | ||
29 | #include "gnunet_client_lib.h" | ||
30 | #include "gnunet_constants.h" | ||
31 | #include "gnunet_container_lib.h" | ||
32 | #include "gnunet_arm_service.h" | ||
33 | #include "gnunet_hello_lib.h" | ||
34 | #include "gnunet_protocols.h" | ||
35 | #include "gnunet_server_lib.h" | ||
36 | #include "gnunet_time_lib.h" | ||
37 | #include "gnunet_dv_service.h" | ||
38 | #include "dv.h" | ||
39 | |||
40 | |||
41 | struct PendingMessages | ||
42 | { | ||
43 | /** | ||
44 | * Linked list of pending messages | ||
45 | */ | ||
46 | struct PendingMessages *next; | ||
47 | |||
48 | /** | ||
49 | * Message that is pending | ||
50 | */ | ||
51 | struct GNUNET_DV_SendMessage *msg; | ||
52 | |||
53 | /** | ||
54 | * Timeout for this message | ||
55 | */ | ||
56 | struct GNUNET_TIME_Absolute timeout; | ||
57 | |||
58 | }; | ||
59 | |||
60 | /** | ||
61 | * Handle for the service. | ||
62 | */ | ||
63 | struct GNUNET_DV_Handle | ||
64 | { | ||
65 | /** | ||
66 | * Our scheduler. | ||
67 | */ | ||
68 | struct GNUNET_SCHEDULER_Handle *sched; | ||
69 | |||
70 | /** | ||
71 | * Configuration to use. | ||
72 | */ | ||
73 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
74 | |||
75 | /** | ||
76 | * Socket (if available). | ||
77 | */ | ||
78 | struct GNUNET_CLIENT_Connection *client; | ||
79 | |||
80 | /** | ||
81 | * Currently pending transmission request. | ||
82 | */ | ||
83 | struct GNUNET_CLIENT_TransmitHandle *th; | ||
84 | |||
85 | /** | ||
86 | * List of the currently pending messages for the DV service. | ||
87 | */ | ||
88 | struct PendingMessages *pending_list; | ||
89 | |||
90 | /** | ||
91 | * Message we are currently sending. | ||
92 | */ | ||
93 | struct PendingMessages *current; | ||
94 | |||
95 | /** | ||
96 | * Kill off the connection and any pending messages. | ||
97 | */ | ||
98 | int do_destroy; | ||
99 | |||
100 | /** | ||
101 | * Handler for messages we receive from the DV service | ||
102 | */ | ||
103 | GNUNET_DV_MessageReceivedHandler receive_handler; | ||
104 | |||
105 | /** | ||
106 | * Closure for the receive handler | ||
107 | */ | ||
108 | void *receive_cls; | ||
109 | |||
110 | }; | ||
111 | |||
112 | |||
113 | /** | ||
114 | * Try to (re)connect to the dv service. | ||
115 | * | ||
116 | * @return GNUNET_YES on success, GNUNET_NO on failure. | ||
117 | */ | ||
118 | static int | ||
119 | try_connect (struct GNUNET_DV_Handle *ret) | ||
120 | { | ||
121 | if (ret->client != NULL) | ||
122 | return GNUNET_OK; | ||
123 | ret->client = GNUNET_CLIENT_connect (ret->sched, "dv", ret->cfg); | ||
124 | if (ret->client != NULL) | ||
125 | return GNUNET_YES; | ||
126 | #if DEBUG_STATISTICS | ||
127 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
128 | _("Failed to connect to the dv service!\n")); | ||
129 | #endif | ||
130 | return GNUNET_NO; | ||
131 | } | ||
132 | |||
133 | static void process_pending_message(struct GNUNET_DV_Handle *handle); | ||
134 | |||
135 | /** | ||
136 | * Send complete, schedule next | ||
137 | */ | ||
138 | static void | ||
139 | finish (struct GNUNET_DV_Handle *handle, int code) | ||
140 | { | ||
141 | struct PendingMessages *pos = handle->current; | ||
142 | handle->current = NULL; | ||
143 | process_pending_message (handle); | ||
144 | |||
145 | GNUNET_free (pos); | ||
146 | } | ||
147 | |||
148 | |||
149 | static size_t | ||
150 | transmit_pending (void *cls, size_t size, void *buf) | ||
151 | { | ||
152 | struct GNUNET_DV_Handle *handle = cls; | ||
153 | size_t ret; | ||
154 | |||
155 | if (buf == NULL) | ||
156 | { | ||
157 | finish(handle, GNUNET_SYSERR); | ||
158 | return 0; | ||
159 | } | ||
160 | handle->th = NULL; | ||
161 | |||
162 | return ret; | ||
163 | } | ||
164 | |||
165 | /** | ||
166 | * Try to send messages from list of messages to send | ||
167 | */ | ||
168 | static void process_pending_message(struct GNUNET_DV_Handle *handle) | ||
169 | { | ||
170 | struct GNUNET_TIME_Relative timeout; | ||
171 | |||
172 | if (handle->current != NULL) | ||
173 | return; /* action already pending */ | ||
174 | if (GNUNET_YES != try_connect (handle)) | ||
175 | { | ||
176 | finish (handle, GNUNET_SYSERR); | ||
177 | return; | ||
178 | } | ||
179 | |||
180 | /* schedule next action */ | ||
181 | handle->current = handle->pending_list; | ||
182 | if (NULL == handle->current) | ||
183 | { | ||
184 | if (handle->do_destroy) | ||
185 | { | ||
186 | handle->do_destroy = GNUNET_NO; | ||
187 | //GNUNET_DV_disconnect (handle); /* FIXME: replace with proper disconnect stuffs */ | ||
188 | } | ||
189 | return; | ||
190 | } | ||
191 | handle->pending_list = handle->pending_list->next; | ||
192 | handle->current->next = NULL; | ||
193 | |||
194 | timeout = GNUNET_TIME_absolute_get_remaining (handle->current->timeout); | ||
195 | if (NULL == | ||
196 | (handle->th = GNUNET_CLIENT_notify_transmit_ready (handle->client, | ||
197 | ntohs(handle->current->msg->msgbuf_size), | ||
198 | timeout, | ||
199 | GNUNET_YES, | ||
200 | &transmit_pending, handle))) | ||
201 | { | ||
202 | #if DEBUG_STATISTICS | ||
203 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
204 | "Failed to transmit request to dv service.\n"); | ||
205 | #endif | ||
206 | finish (handle, GNUNET_SYSERR); | ||
207 | } | ||
208 | } | ||
209 | |||
210 | /** | ||
211 | * Add a pending message to the linked list | ||
212 | * | ||
213 | * @param handle handle to the specified DV api | ||
214 | * @param msg the message to add to the list | ||
215 | */ | ||
216 | static void add_pending(struct GNUNET_DV_Handle *handle, struct GNUNET_DV_SendMessage *msg) | ||
217 | { | ||
218 | struct PendingMessages *new_message; | ||
219 | struct PendingMessages *pos; | ||
220 | struct PendingMessages *last; | ||
221 | |||
222 | new_message = GNUNET_malloc(sizeof(struct PendingMessages)); | ||
223 | new_message->msg = msg; | ||
224 | |||
225 | if (handle->pending_list != NULL) | ||
226 | { | ||
227 | pos = handle->pending_list; | ||
228 | while(pos != NULL) | ||
229 | { | ||
230 | last = pos; | ||
231 | pos = pos->next; | ||
232 | } | ||
233 | new_message->next = last->next; /* Should always be null */ | ||
234 | last->next = new_message; | ||
235 | } | ||
236 | else | ||
237 | { | ||
238 | new_message->next = handle->pending_list; /* Will always be null */ | ||
239 | handle->pending_list = new_message; | ||
240 | } | ||
241 | |||
242 | process_pending_message(handle); | ||
243 | } | ||
244 | |||
245 | |||
246 | |||
247 | |||
248 | void handle_message_receipt (void *cls, | ||
249 | const struct GNUNET_MessageHeader * msg) | ||
250 | { | ||
251 | struct GNUNET_DV_Handle *handle = cls; | ||
252 | struct GNUNET_DV_MessageReceived *received_msg; | ||
253 | char *sender_address; | ||
254 | |||
255 | GNUNET_assert(ntohs(msg->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_DV_RECEIVE); | ||
256 | |||
257 | if (ntohs(msg->size) < sizeof(struct GNUNET_DV_MessageReceived)) | ||
258 | return; | ||
259 | |||
260 | received_msg = (struct GNUNET_DV_MessageReceived *)msg; | ||
261 | GNUNET_assert(ntohs(msg->size) == (sizeof(struct GNUNET_DV_MessageReceived) + ntohs(received_msg->msg->size) + ntohs(received_msg->sender_address_len))); | ||
262 | |||
263 | sender_address = GNUNET_malloc(ntohs(received_msg->sender_address_len)); | ||
264 | sender_address = memcpy(sender_address, &received_msg[1], ntohs(received_msg->sender_address_len)); | ||
265 | |||
266 | handle->receive_handler(handle->receive_cls, | ||
267 | received_msg->sender, | ||
268 | received_msg->msg, | ||
269 | ntohl(received_msg->distance), | ||
270 | sender_address, | ||
271 | ntohs(received_msg->sender_address_len)); | ||
272 | |||
273 | GNUNET_free(sender_address); | ||
274 | |||
275 | GNUNET_CLIENT_receive (handle->client, | ||
276 | &handle_message_receipt, | ||
277 | handle, GNUNET_TIME_UNIT_FOREVER_REL); | ||
278 | } | ||
279 | |||
280 | /** | ||
281 | * Send a message from the plugin to the DV service indicating that | ||
282 | * a message should be sent via DV to some peer. | ||
283 | * | ||
284 | * @target the final target of the message | ||
285 | * @msgbuf the msg(s) to send | ||
286 | * @msgbuf_size the size of msgbuf | ||
287 | * @priority priority to pass on to core when sending the message | ||
288 | * @timeout how long can this message be delayed (pass through to core) | ||
289 | * @addr the address of this peer (internally known to DV) | ||
290 | * @addrlen the length of the peer address | ||
291 | * | ||
292 | */ | ||
293 | int GNUNET_DV_send (struct GNUNET_DV_Handle *dv_handle, | ||
294 | const struct GNUNET_PeerIdentity *target, | ||
295 | const char *msgbuf, | ||
296 | size_t msgbuf_size, | ||
297 | unsigned int priority, | ||
298 | struct GNUNET_TIME_Relative timeout, | ||
299 | const void *addr, | ||
300 | size_t addrlen) | ||
301 | { | ||
302 | struct GNUNET_DV_SendMessage *msg; | ||
303 | |||
304 | msg = GNUNET_malloc(sizeof(struct GNUNET_DV_SendMessage) + msgbuf_size + addrlen); | ||
305 | msg->header.size = htons(sizeof(struct GNUNET_DV_SendMessage) + msgbuf_size + addrlen); | ||
306 | msg->header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_DV_SEND); | ||
307 | memcpy(&msg->target, target, sizeof(struct GNUNET_PeerIdentity)); | ||
308 | msg->msgbuf = GNUNET_malloc(msgbuf_size); | ||
309 | memcpy(msg->msgbuf, msgbuf, msgbuf_size); | ||
310 | msg->msgbuf_size = htons(msgbuf_size); | ||
311 | msg->priority = htonl(priority); | ||
312 | msg->timeout = timeout; | ||
313 | msg->addrlen = htons(addrlen); | ||
314 | memcpy(&msg[1], addr, addrlen); | ||
315 | |||
316 | add_pending(dv_handle, msg); | ||
317 | process_pending_message(dv_handle); | ||
318 | |||
319 | return GNUNET_OK; | ||
320 | } | ||
321 | |||
322 | /** | ||
323 | * Connect to the DV service | ||
324 | * | ||
325 | * @param sched the scheduler to use | ||
326 | * @param cfg the configuration to use | ||
327 | * | ||
328 | * @return handle to the DV service | ||
329 | */ | ||
330 | struct GNUNET_DV_Handle * | ||
331 | GNUNET_DV_connect (struct GNUNET_SCHEDULER_Handle *sched, | ||
332 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
333 | GNUNET_DV_MessageReceivedHandler receive_handler, | ||
334 | void *receive_handler_cls) | ||
335 | { | ||
336 | struct GNUNET_DV_Handle *handle; | ||
337 | |||
338 | handle = GNUNET_malloc(sizeof(struct GNUNET_DV_Handle)); | ||
339 | |||
340 | handle->cfg = cfg; | ||
341 | handle->sched = sched; | ||
342 | handle->pending_list = NULL; | ||
343 | handle->current = NULL; | ||
344 | handle->do_destroy = GNUNET_NO; | ||
345 | handle->th = NULL; | ||
346 | handle->client = GNUNET_CLIENT_connect(sched, "dv", cfg); | ||
347 | handle->receive_handler = receive_handler; | ||
348 | handle->receive_cls = receive_handler_cls; | ||
349 | |||
350 | if (handle->client == NULL) | ||
351 | return NULL; | ||
352 | |||
353 | GNUNET_CLIENT_receive (handle->client, | ||
354 | &handle_message_receipt, | ||
355 | handle, GNUNET_TIME_UNIT_FOREVER_REL); | ||
356 | |||
357 | return handle; | ||
358 | } | ||
359 | |||
360 | /** | ||
361 | * Disconnect from the DV service | ||
362 | * | ||
363 | * @param handle the current handle to the service to disconnect | ||
364 | */ | ||
365 | void GNUNET_DV_disconnect(struct GNUNET_DV_Handle *handle) | ||
366 | { | ||
367 | struct PendingMessages *pos; | ||
368 | |||
369 | GNUNET_assert(handle != NULL); | ||
370 | |||
371 | if (handle->th != NULL) /* We have a live transmit request in the Aether */ | ||
372 | { | ||
373 | GNUNET_CLIENT_notify_transmit_ready_cancel (handle->th); | ||
374 | handle->th = NULL; | ||
375 | } | ||
376 | if (handle->current != NULL) /* We are trying to send something now, clean it up */ | ||
377 | GNUNET_free(handle->current); | ||
378 | while (NULL != (pos = handle->pending_list)) /* Remove all pending sends from the list */ | ||
379 | { | ||
380 | handle->pending_list = pos->next; | ||
381 | GNUNET_free(pos); | ||
382 | } | ||
383 | if (handle->client != NULL) /* Finally, disconnect from the service */ | ||
384 | { | ||
385 | GNUNET_CLIENT_disconnect (handle->client); | ||
386 | handle->client = NULL; | ||
387 | } | ||
388 | |||
389 | GNUNET_free (handle); | ||
390 | } | ||
391 | |||
392 | /* end of dv_api.c */ | ||