4d158ab2fbd26a8ce8645540717a409f5b08cd25
[oweals/gnunet.git] / src / util / client.c
1 /*
2      This file is part of GNUnet.
3      (C) 2001, 2002, 2006, 2008, 2009 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 util/client.c
23  * @brief code for access to services
24  * @author Christian Grothoff
25  *
26  * Generic TCP code for reliable, record-oriented TCP
27  * connections between clients and service providers.
28  */
29
30 #include "platform.h"
31 #include "gnunet_common.h"
32 #include "gnunet_client_lib.h"
33 #include "gnunet_protocols.h"
34 #include "gnunet_server_lib.h"
35 #include "gnunet_scheduler_lib.h"
36
37 #define DEBUG_CLIENT GNUNET_NO
38
39
40 /**
41  * How often do we re-try tranmsitting requests before giving up?
42  * Note that if we succeeded transmitting a request but failed to read
43  * a response, we do NOT re-try.
44  */
45 #define MAX_ATTEMPTS 10
46
47
48 /**
49  * Handle for a transmission request.
50  */
51 struct GNUNET_CLIENT_TransmitHandle
52 {
53   /**
54    * Connection state.
55    */
56   struct GNUNET_CLIENT_Connection *sock;
57
58   /**
59    * Function to call to get the data for transmission.
60    */
61   GNUNET_CONNECTION_TransmitReadyNotify notify;
62
63   /**
64    * Closure for notify.
65    */
66   void *notify_cls;
67
68   /**
69    * Handle to the transmission with the underlying
70    * connection.
71    */
72   struct GNUNET_CONNECTION_TransmitHandle *th;
73
74   /**
75    * If we are re-trying and are delaying to do so,
76    * handle to the scheduled task managing the delay.
77    */
78   GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
79
80   /**
81    * Timeout.
82    */
83   struct GNUNET_TIME_Absolute timeout;
84
85   /**
86    * Number of bytes requested.
87    */
88   size_t size;
89
90   /**
91    * Are we allowed to re-try to connect without telling
92    * the user (of this API) about the connection troubles?
93    */
94   int auto_retry;
95
96   /**
97    * Number of attempts left for transmitting the request.  We may
98    * fail the first time (say because the service is not yet up), in
99    * which case (if auto_retry is set) we wait a bit and re-try
100    * (timeout permitting).
101    */
102   unsigned int attempts_left;
103
104 };
105
106
107 /**
108  * Context for processing 
109  * "GNUNET_CLIENT_transmit_and_get_response" requests.
110  */
111 struct TransmitGetResponseContext
112 {
113   /**
114    * Client handle.
115    */
116   struct GNUNET_CLIENT_Connection *sock;
117
118   /**
119    * Message to transmit; do not free, allocated
120    * right after this struct.
121    */
122   const struct GNUNET_MessageHeader *hdr;
123
124   /**
125    * Timeout to use.
126    */
127   struct GNUNET_TIME_Absolute timeout;
128
129   /**
130    * Function to call when done.
131    */
132   GNUNET_CLIENT_MessageHandler rn;
133
134   /**
135    * Closure for "rn".
136    */
137   void *rn_cls;
138 };
139
140
141 /**
142  * Struct to refer to a GNUnet TCP connection.
143  * This is more than just a socket because if the server
144  * drops the connection, the client automatically tries
145  * to reconnect (and for that needs connection information).
146  */
147 struct GNUNET_CLIENT_Connection
148 {
149
150   /**
151    * the socket handle, NULL if not live
152    */
153   struct GNUNET_CONNECTION_Handle *sock;
154
155   /**
156    * Our scheduler.
157    */
158   struct GNUNET_SCHEDULER_Handle *sched;
159
160   /**
161    * Our configuration.
162    */
163   struct GNUNET_CONFIGURATION_Handle *cfg;
164
165   /**
166    * Name of the service we interact with.
167    */
168   char *service_name;
169
170   /**
171    * Context of a transmit_and_get_response operation, NULL
172    * if no such operation is pending.
173    */
174   struct TransmitGetResponseContext *tag;
175
176   /**
177    * Handler for current receiver task.
178    */
179   GNUNET_CLIENT_MessageHandler receiver_handler;
180
181   /**
182    * Closure for receiver_handler.
183    */
184   void *receiver_handler_cls;
185
186   /**
187    * Handle for a pending transmission request, NULL if there is
188    * none pending.
189    */
190   struct GNUNET_CLIENT_TransmitHandle *th;
191
192   /**
193    * Handler for service test completion (NULL unless in service_test)
194    */
195   GNUNET_SCHEDULER_Task test_cb;
196
197   /**
198    * If we are re-trying and are delaying to do so,
199    * handle to the scheduled task managing the delay.
200    */
201   GNUNET_SCHEDULER_TaskIdentifier receive_task;
202
203   /**
204    * Closure for test_cb (NULL unless in service_test)
205    */
206   void *test_cb_cls;
207
208   /**
209    * Buffer for received message.
210    */
211   char *received_buf;
212
213   /**
214    * Timeout for receiving a response (absolute time).
215    */
216   struct GNUNET_TIME_Absolute receive_timeout;
217
218   /**
219    * Number of bytes in received_buf that are valid.
220    */
221   size_t received_pos;
222
223   /**
224    * Size of received_buf.
225    */
226   unsigned int received_size;
227
228   /**
229    * Do we have a complete response in received_buf?
230    */
231   int msg_complete;
232
233   /**
234    * Are we currently busy doing receive-processing?
235    * GNUNET_YES if so, GNUNET_NO if not.
236    */
237   int in_receive;
238
239 };
240
241
242 static struct GNUNET_CONNECTION_Handle *
243 do_connect (struct GNUNET_SCHEDULER_Handle *sched,
244             const char *service_name,
245             const struct GNUNET_CONFIGURATION_Handle *cfg)
246 {
247   struct GNUNET_CONNECTION_Handle *sock;
248   char *hostname;
249   unsigned long long port;
250
251   if ((GNUNET_OK !=
252        GNUNET_CONFIGURATION_get_value_number (cfg,
253                                               service_name,
254                                               "PORT",
255                                               &port)) ||
256       (port > 65535) ||
257       (GNUNET_OK !=
258        GNUNET_CONFIGURATION_get_value_string (cfg,
259                                               service_name,
260                                               "HOSTNAME", &hostname)))
261     {
262       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
263                   _
264                   ("Could not determine valid hostname and port for service `%s' from configuration.\n"),
265                   service_name);
266       return NULL;
267     }
268   if (0 == strlen (hostname))
269     {
270       GNUNET_free (hostname);
271       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
272                   _("Need a non-empty hostname for service `%s'.\n"),
273                   service_name);
274       return NULL;
275     }
276   sock = GNUNET_CONNECTION_create_from_connect (sched,
277                                                 cfg,
278                                                 hostname,
279                                                 port,
280                                                 GNUNET_SERVER_MAX_MESSAGE_SIZE);
281   GNUNET_free (hostname);
282   return sock;
283 }
284
285
286 /**
287  * Get a connection with a service.
288  *
289  * @param sched scheduler to use
290  * @param service_name name of the service
291  * @param cfg configuration to use
292  * @return NULL on error (service unknown to configuration)
293  */
294 struct GNUNET_CLIENT_Connection *
295 GNUNET_CLIENT_connect (struct GNUNET_SCHEDULER_Handle *sched,
296                        const char *service_name,
297                        const struct GNUNET_CONFIGURATION_Handle *cfg)
298 {
299   struct GNUNET_CLIENT_Connection *ret;
300   struct GNUNET_CONNECTION_Handle *sock;
301
302   sock = do_connect (sched, service_name, cfg);
303   if (sock == NULL)
304     return NULL;
305   ret = GNUNET_malloc (sizeof (struct GNUNET_CLIENT_Connection));
306   ret->sock = sock;
307   ret->sched = sched;
308   ret->service_name = GNUNET_strdup (service_name);
309   ret->cfg = GNUNET_CONFIGURATION_dup (cfg);
310   return ret;
311 }
312
313
314 /**
315  * Destroy connection with the service.  This will automatically
316  * cancel any pending "receive" request (however, the handler will
317  * *NOT* be called, not even with a NULL message).  Any pending
318  * transmission request will also be cancelled UNLESS the callback for
319  * the transmission request has already been called, in which case the
320  * transmission is guaranteed to complete before the socket is fully
321  * destroyed (unless, of course, there is an error with the server
322  * in which case the message may still be lost).
323  *
324  * @param sock handle to the service connection
325  */
326 void
327 GNUNET_CLIENT_disconnect (struct GNUNET_CLIENT_Connection *sock)
328 {
329   GNUNET_assert (sock->sock != NULL);
330   if (sock->in_receive == GNUNET_YES)
331     {
332       GNUNET_CONNECTION_receive_cancel (sock->sock);
333       sock->in_receive = GNUNET_NO;
334     }
335   GNUNET_CONNECTION_destroy (sock->sock);
336   sock->sock = NULL;
337   if (sock->tag != NULL)
338     {
339       GNUNET_free (sock->tag);
340       sock->tag = NULL;
341     }
342   sock->receiver_handler = NULL;
343   if (sock->th != NULL)
344     GNUNET_CLIENT_notify_transmit_ready_cancel (sock->th);
345   if (sock->receive_task != GNUNET_SCHEDULER_NO_TASK)
346     {
347       GNUNET_SCHEDULER_cancel (sock->sched, sock->receive_task);
348       sock->receive_task = GNUNET_SCHEDULER_NO_TASK;
349     }
350   GNUNET_array_grow (sock->received_buf, sock->received_size, 0);
351   GNUNET_free (sock->service_name);
352   GNUNET_CONFIGURATION_destroy (sock->cfg);
353   GNUNET_free (sock);
354 }
355
356
357 /**
358  * Check if message is complete
359  */
360 static void
361 check_complete (struct GNUNET_CLIENT_Connection *conn)
362 {
363   if ((conn->received_pos >= sizeof (struct GNUNET_MessageHeader)) &&
364       (conn->received_pos >=
365        ntohs (((const struct GNUNET_MessageHeader *) conn->
366                received_buf)->size)))
367     conn->msg_complete = GNUNET_YES;
368 }
369
370
371 /**
372  * Callback function for data received from the network.  Note that
373  * both "available" and "errCode" would be 0 if the read simply timed out.
374  *
375  * @param cls closure
376  * @param buf pointer to received data
377  * @param available number of bytes availabe in "buf",
378  *        possibly 0 (on errors)
379  * @param addr address of the sender
380  * @param addrlen size of addr
381  * @param errCode value of errno (on errors receiving)
382  */
383 static void
384 receive_helper (void *cls,
385                 const void *buf,
386                 size_t available,
387                 const struct sockaddr *addr, socklen_t addrlen, int errCode)
388 {
389   struct GNUNET_CLIENT_Connection *conn = cls;
390   struct GNUNET_TIME_Relative remaining;
391   GNUNET_CLIENT_MessageHandler receive_handler;
392   void *receive_handler_cls;
393
394   GNUNET_assert (conn->msg_complete == GNUNET_NO);
395   conn->in_receive = GNUNET_NO;
396   if ((available == 0) || (conn->sock == NULL) || (errCode != 0))
397     {
398       /* signal timeout! */
399       if (NULL != (receive_handler = conn->receiver_handler))
400         {
401           receive_handler_cls = conn->receiver_handler_cls;
402           conn->receiver_handler = NULL;
403           receive_handler (receive_handler_cls, NULL);
404         }
405       return;
406     }
407
408   /* FIXME: optimize for common fast case where buf contains the
409      entire message and we need no copying... */
410
411
412   /* slow path: append to array */
413   if (conn->received_size < conn->received_pos + available)
414     GNUNET_array_grow (conn->received_buf,
415                        conn->received_size, conn->received_pos + available);
416   memcpy (&conn->received_buf[conn->received_pos], buf, available);
417   conn->received_pos += available;
418   check_complete (conn);
419   /* check for timeout */
420   remaining = GNUNET_TIME_absolute_get_remaining (conn->receive_timeout);
421   if (remaining.value == 0)
422     {
423       /* signal timeout! */
424       conn->receiver_handler (conn->receiver_handler_cls, NULL);
425       return;
426     }
427   /* back to receive -- either for more data or to call callback! */
428   GNUNET_CLIENT_receive (conn,
429                          conn->receiver_handler,
430                          conn->receiver_handler_cls, remaining);
431 }
432
433
434 /**
435  * Continuation to call the receive callback.
436  *
437  * @param cls  our handle to the client connection
438  * @param tc scheduler context
439  */
440 static void
441 receive_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
442 {
443   struct GNUNET_CLIENT_Connection *sock = cls;
444   GNUNET_CLIENT_MessageHandler handler = sock->receiver_handler;
445   const struct GNUNET_MessageHeader *cmsg =
446     (const struct GNUNET_MessageHeader *) sock->received_buf;
447   void *handler_cls = sock->receiver_handler_cls;
448   uint16_t msize = ntohs (cmsg->size);
449   char mbuf[msize];
450   struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) mbuf;
451
452   sock->receive_task = GNUNET_SCHEDULER_NO_TASK;
453   GNUNET_assert (GNUNET_YES == sock->msg_complete);
454   GNUNET_assert (sock->received_pos >= msize);
455   memcpy (msg, cmsg, msize);
456   memmove (sock->received_buf,
457            &sock->received_buf[msize], sock->received_pos - msize);
458   sock->received_pos -= msize;
459   sock->msg_complete = GNUNET_NO;
460   sock->receiver_handler = NULL;
461   check_complete (sock);
462   if (handler != NULL)
463     handler (handler_cls, msg);
464 }
465
466
467 /**
468  * Read from the service.
469  *
470  * @param sock the service
471  * @param handler function to call with the message
472  * @param handler_cls closure for handler
473  * @param timeout how long to wait until timing out
474  */
475 void
476 GNUNET_CLIENT_receive (struct GNUNET_CLIENT_Connection *sock,
477                        GNUNET_CLIENT_MessageHandler handler,
478                        void *handler_cls, struct GNUNET_TIME_Relative timeout)
479 {
480   if (sock->sock == NULL)
481     {
482       /* already disconnected, fail instantly! */
483       GNUNET_break (0);         /* this should not happen in well-written code! */
484       handler (handler_cls, NULL);
485       return;
486     }
487   sock->receiver_handler = handler;
488   sock->receiver_handler_cls = handler_cls;
489   sock->receive_timeout = GNUNET_TIME_relative_to_absolute (timeout);
490   if (GNUNET_YES == sock->msg_complete)
491     {
492       sock->receive_task = GNUNET_SCHEDULER_add_after (sock->sched,
493                                                        GNUNET_SCHEDULER_NO_TASK,
494                                                        &receive_task, sock);
495     }
496   else
497     {
498       sock->in_receive = GNUNET_YES;
499       GNUNET_CONNECTION_receive (sock->sock,
500                                  GNUNET_SERVER_MAX_MESSAGE_SIZE,
501                                  timeout, &receive_helper, sock);
502     }
503 }
504
505
506 /**
507  * If possible, write a shutdown message to the target
508  * buffer and destroy the client connection.
509  *
510  * @param cls the "struct GNUNET_CLIENT_Connection" to destroy
511  * @param size number of bytes available in buf
512  * @param buf NULL on error, otherwise target buffer
513  * @return number of bytes written to buf
514  */
515 static size_t
516 write_shutdown (void *cls, size_t size, void *buf)
517 {
518   struct GNUNET_MessageHeader *msg;
519   struct GNUNET_CLIENT_Connection *sock = cls;
520
521   GNUNET_CLIENT_disconnect (sock);
522   if (size < sizeof (struct GNUNET_MessageHeader))
523     {
524       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
525                   _("Failed to transmit shutdown request to client.\n"));
526       return 0;                 /* client disconnected */
527     }
528   msg = (struct GNUNET_MessageHeader *) buf;
529   msg->type = htons (GNUNET_MESSAGE_TYPE_SHUTDOWN);
530   msg->size = htons (sizeof (struct GNUNET_MessageHeader));
531   return sizeof (struct GNUNET_MessageHeader);
532 }
533
534
535 /**
536  * Request that the service should shutdown.
537  * Afterwards, the connection should be disconnected.
538  *
539  * @param sock the socket connected to the service
540  */
541 void
542 GNUNET_CLIENT_service_shutdown (struct GNUNET_CLIENT_Connection *sock)
543 {
544   GNUNET_CONNECTION_notify_transmit_ready (sock->sock,
545                                            sizeof (struct
546                                                    GNUNET_MessageHeader),
547                                            GNUNET_TIME_UNIT_FOREVER_REL,
548                                            &write_shutdown, sock);
549 }
550
551
552 /**
553  * Report service unavailable.
554  */
555 static void
556 service_test_error (struct GNUNET_SCHEDULER_Handle *s,
557                     GNUNET_SCHEDULER_Task task, void *task_cls)
558 {
559   GNUNET_SCHEDULER_add_continuation (s,
560                                      task,
561                                      task_cls,
562                                      GNUNET_SCHEDULER_REASON_TIMEOUT);
563 }
564
565
566 /**
567  * Receive confirmation from test, service is up.
568  *
569  * @param cls closure
570  * @param msg message received, NULL on timeout or fatal error
571  */
572 static void
573 confirm_handler (void *cls, const struct GNUNET_MessageHeader *msg)
574 {
575   struct GNUNET_CLIENT_Connection *conn = cls;
576   /* We may want to consider looking at the reply in more
577      detail in the future, for example, is this the
578      correct service? FIXME! */
579   if (msg != NULL)
580     {
581 #if DEBUG_CLIENT
582       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
583                   "Received confirmation that service is running.\n");
584 #endif
585       GNUNET_SCHEDULER_add_continuation (conn->sched,
586                                          conn->test_cb,
587                                          conn->test_cb_cls,
588                                          GNUNET_SCHEDULER_REASON_PREREQ_DONE);
589     }
590   else
591     {
592       service_test_error (conn->sched, conn->test_cb, conn->test_cb_cls);
593     }
594   GNUNET_CLIENT_disconnect (conn);
595 }
596
597
598 static size_t
599 write_test (void *cls, size_t size, void *buf)
600 {
601   struct GNUNET_MessageHeader *msg;
602
603   if (size < sizeof (struct GNUNET_MessageHeader))
604     {
605 #if DEBUG_CLIENT
606       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
607                   _("Failure to transmit TEST request.\n"));
608 #endif
609       return 0;                 /* client disconnected */
610     }
611 #if DEBUG_CLIENT
612   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
613               "Transmitting `%s' request.\n", "TEST");
614 #endif
615   msg = (struct GNUNET_MessageHeader *) buf;
616   msg->type = htons (GNUNET_MESSAGE_TYPE_TEST);
617   msg->size = htons (sizeof (struct GNUNET_MessageHeader));
618   return sizeof (struct GNUNET_MessageHeader);
619 }
620
621
622 /**
623  * Wait until the service is running.
624  *
625  * @param sched scheduler to use
626  * @param service name of the service to wait for
627  * @param cfg configuration to use
628  * @param timeout how long to wait at most in ms
629  * @param task task to run if service is running
630  *        (reason will be "PREREQ_DONE" (service running)
631  *         or "TIMEOUT" (service not known to be running))
632  * @param task_cls closure for task
633  */
634 void
635 GNUNET_CLIENT_service_test (struct GNUNET_SCHEDULER_Handle *sched,
636                             const char *service,
637                             const struct GNUNET_CONFIGURATION_Handle *cfg,
638                             struct GNUNET_TIME_Relative timeout,
639                             GNUNET_SCHEDULER_Task task, void *task_cls)
640 {
641   struct GNUNET_CLIENT_Connection *conn;
642
643 #if DEBUG_CLIENT
644   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
645               "Testing if service `%s' is running.\n", service);
646 #endif
647   conn = GNUNET_CLIENT_connect (sched, service, cfg);
648   if (conn == NULL)
649     {
650       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
651                   _
652                   ("Could not connect to service `%s', must not be running.\n"),
653                   service);
654       service_test_error (sched, task, task_cls);
655       return;
656     }
657   conn->test_cb = task;
658   conn->test_cb_cls = task_cls;
659   if (NULL ==
660       GNUNET_CONNECTION_notify_transmit_ready (conn->sock,
661                                                sizeof (struct
662                                                        GNUNET_MessageHeader),
663                                                timeout, &write_test, NULL))
664     {
665       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
666                   _("Failure to transmit request to service `%s'\n"),
667                   service);
668       service_test_error (sched, task, task_cls);
669       GNUNET_CLIENT_disconnect (conn);
670       return;
671     }
672   GNUNET_CLIENT_receive (conn, &confirm_handler, conn, timeout);
673 }
674
675
676 /**
677  * Connection notifies us about failure or success of
678  * a transmission request.  Either pass it on to our
679  * user or, if possible, retry.
680  *
681  * @param cls our "struct GNUNET_CLIENT_TransmissionHandle"
682  * @param size number of bytes available for transmission
683  * @param buf where to write them
684  * @return number of bytes written to buf
685  */
686 static size_t client_notify (void *cls, size_t size, void *buf);
687
688
689 /**
690  * This task is run if we should re-try connection to the
691  * service after a while.
692  *
693  * @param cls our "struct GNUNET_CLIENT_TransmitHandle" of the request
694  * @param tc unused
695  */
696 static void
697 client_delayed_retry (void *cls,
698                       const struct GNUNET_SCHEDULER_TaskContext *tc)
699 {
700   struct GNUNET_CLIENT_TransmitHandle *th = cls;
701
702   th->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
703   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
704     {
705 #if DEBUG_CLIENT
706       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
707                   "Transmission failed due to shutdown.\n");
708 #endif
709       th->sock->th = NULL;
710       th->notify (th->notify_cls, 0, NULL);
711       GNUNET_free (th);
712       return;
713     }
714   th->th = GNUNET_CONNECTION_notify_transmit_ready (th->sock->sock,
715                                                     th->size,
716                                                     GNUNET_TIME_absolute_get_remaining
717                                                     (th->timeout),
718                                                     &client_notify, th);
719   if (th->th == NULL)
720     {
721       GNUNET_break (0);
722       th->notify (th->notify_cls, 0, NULL);
723       GNUNET_free (th);
724       return;
725     }
726 }
727
728
729 /**
730  * Connection notifies us about failure or success of
731  * a transmission request.  Either pass it on to our
732  * user or, if possible, retry.
733  *
734  * @param cls our "struct GNUNET_CLIENT_TransmissionHandle"
735  * @param size number of bytes available for transmission
736  * @param buf where to write them
737  * @return number of bytes written to buf
738  */
739 static size_t
740 client_notify (void *cls, size_t size, void *buf)
741 {
742   struct GNUNET_CLIENT_TransmitHandle *th = cls;
743   size_t ret;
744   struct GNUNET_TIME_Relative delay;
745
746   th->th = NULL;
747   th->sock->th = NULL;
748   if (buf == NULL)
749     {
750       // FIXME: need a way to check if the
751       // reason is SHUTDOWN (not timeout) and
752       // if so NOT retry!
753       delay = GNUNET_TIME_absolute_get_remaining (th->timeout);
754       delay.value /= 2;
755       if ((GNUNET_YES != th->auto_retry) ||
756           (0 == --th->attempts_left) || (delay.value < 1))
757         {
758 #if DEBUG_CLIENT
759           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
760                       "Transmission failed %u times, giving up.\n",
761                       MAX_ATTEMPTS - th->attempts_left);
762 #endif
763           GNUNET_break (0 == th->notify (th->notify_cls, 0, NULL));
764           GNUNET_free (th);
765           return 0;
766         }
767       /* auto-retry */
768       GNUNET_CONNECTION_destroy (th->sock->sock);
769       th->sock->sock = do_connect (th->sock->sched,
770                                    th->sock->service_name, th->sock->cfg);
771       GNUNET_assert (NULL != th->sock->sock);
772       delay = GNUNET_TIME_relative_min (delay, GNUNET_TIME_UNIT_SECONDS);
773 #if DEBUG_CLIENT
774       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
775                   "Transmission failed %u times, trying again in %llums.\n",
776                   MAX_ATTEMPTS - th->attempts_left,
777                   (unsigned long long) delay.value);
778 #endif
779       th->reconnect_task = GNUNET_SCHEDULER_add_delayed (th->sock->sched,
780                                                          delay,
781                                                          &client_delayed_retry,
782                                                          th);
783       th->sock->th = th;
784       return 0;
785     }
786   GNUNET_assert (size >= th->size);
787   ret = th->notify (th->notify_cls, size, buf);
788   GNUNET_free (th);
789   return ret;
790 }
791
792
793 /**
794  * Ask the client to call us once the specified number of bytes
795  * are free in the transmission buffer.  May call the notify
796  * method immediately if enough space is available.
797  *
798  * @param sock connection to the service
799  * @param size number of bytes to send
800  * @param timeout after how long should we give up (and call
801  *        notify with buf NULL and size 0)?
802  * @param auto_retry if the connection to the service dies, should we
803  *        automatically re-connect and retry (within the timeout period)
804  *        or should we immediately fail in this case?  Pass GNUNET_YES
805  *        if the caller does not care about temporary connection errors,
806  *        for example because the protocol is stateless
807  * @param notify function to call
808  * @param notify_cls closure for notify
809  * @return NULL if our buffer will never hold size bytes,
810  *         a handle if the notify callback was queued (can be used to cancel)
811  */
812 struct GNUNET_CLIENT_TransmitHandle *
813 GNUNET_CLIENT_notify_transmit_ready (struct GNUNET_CLIENT_Connection *sock,
814                                      size_t size,
815                                      struct GNUNET_TIME_Relative timeout,
816                                      int auto_retry,
817                                      GNUNET_CONNECTION_TransmitReadyNotify
818                                      notify, void *notify_cls)
819 {
820   struct GNUNET_CLIENT_TransmitHandle *th;
821
822   if (NULL != sock->th)
823     return NULL;
824   th = GNUNET_malloc (sizeof (struct GNUNET_CLIENT_TransmitHandle));
825   th->sock = sock;
826   th->size = size;
827   th->timeout = GNUNET_TIME_relative_to_absolute (timeout);
828   th->auto_retry = auto_retry;
829   th->notify = notify;
830   th->notify_cls = notify_cls;
831   th->attempts_left = MAX_ATTEMPTS;
832   th->th = GNUNET_CONNECTION_notify_transmit_ready (sock->sock,
833                                                     size,
834                                                     timeout,
835                                                     &client_notify, th);
836   if (NULL == th->th)
837     {
838       GNUNET_break (0);
839       GNUNET_free (th);
840       return NULL;
841     }
842   sock->th = th;
843   return th;
844 }
845
846
847 /**
848  * Cancel a request for notification.
849  * 
850  * @param th handle from the original request.
851  */
852 void
853 GNUNET_CLIENT_notify_transmit_ready_cancel (struct
854                                             GNUNET_CLIENT_TransmitHandle *th)
855 {
856   if (th->reconnect_task != GNUNET_SCHEDULER_NO_TASK)
857     {
858       GNUNET_break (NULL == th->th);
859       GNUNET_SCHEDULER_cancel (th->sock->sched, th->reconnect_task);
860       th->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
861     }
862   else
863     {
864       GNUNET_break (NULL != th->th);
865       GNUNET_CONNECTION_notify_transmit_ready_cancel (th->th);
866     }
867   th->sock->th = NULL;
868   GNUNET_free (th);
869 }
870
871
872 /**
873  * Function called to notify a client about the socket
874  * begin ready to queue the message.  "buf" will be
875  * NULL and "size" zero if the socket was closed for
876  * writing in the meantime.
877  *
878  * @param cls closure of type "struct TransmitGetResponseContext*"
879  * @param size number of bytes available in buf
880  * @param buf where the callee should write the message
881  * @return number of bytes written to buf
882  */
883 static size_t
884 transmit_for_response (void *cls, size_t size, void *buf)
885 {
886   struct TransmitGetResponseContext *tc = cls;
887   uint16_t msize;
888
889   tc->sock->tag = NULL;
890   msize = ntohs (tc->hdr->size);
891   if (NULL == buf)
892     {
893       tc->rn (tc->rn_cls, NULL);
894       GNUNET_free (tc);
895       return 0;
896     }
897   GNUNET_assert (size >= msize);
898   memcpy (buf, tc->hdr, msize);
899   GNUNET_CLIENT_receive (tc->sock,
900                          tc->rn,
901                          tc->rn_cls,
902                          GNUNET_TIME_absolute_get_remaining (tc->timeout));
903   GNUNET_free (tc);
904   return msize;
905 }
906
907
908 /**
909  * Convenience API that combines sending a request
910  * to the service and waiting for a response.
911  * If either operation times out, the callback
912  * will be called with a "NULL" response (in which
913  * case the connection should probably be destroyed).
914  *
915  * @param sock connection to use
916  * @param hdr message to transmit
917  * @param timeout when to give up (for both transmission
918  *         and for waiting for a response)
919  * @param auto_retry if the connection to the service dies, should we
920  *        automatically re-connect and retry (within the timeout period)
921  *        or should we immediately fail in this case?  Pass GNUNET_YES
922  *        if the caller does not care about temporary connection errors,
923  *        for example because the protocol is stateless
924  * @param rn function to call with the response
925  * @param rn_cls closure for rn 
926  * @return GNUNET_OK on success, GNUNET_SYSERR if a request
927  *         is already pending
928  */
929 int
930 GNUNET_CLIENT_transmit_and_get_response (struct GNUNET_CLIENT_Connection
931                                          *sock,
932                                          const struct GNUNET_MessageHeader
933                                          *hdr,
934                                          struct GNUNET_TIME_Relative timeout,
935                                          int auto_retry,
936                                          GNUNET_CLIENT_MessageHandler rn,
937                                          void *rn_cls)
938 {
939   struct TransmitGetResponseContext *tc;
940   uint16_t msize;
941
942   if (NULL != sock->th)
943     return GNUNET_SYSERR;
944   GNUNET_assert (sock->tag == NULL);
945   msize = ntohs (hdr->size);
946   tc = GNUNET_malloc (sizeof (struct TransmitGetResponseContext) + msize);
947   tc->sock = sock;
948   tc->hdr = (const struct GNUNET_MessageHeader *) &tc[1];
949   memcpy (&tc[1], hdr, msize);
950   tc->timeout = GNUNET_TIME_relative_to_absolute (timeout);
951   tc->rn = rn;
952   tc->rn_cls = rn_cls;
953   if (NULL == GNUNET_CLIENT_notify_transmit_ready (sock,
954                                                    msize,
955                                                    timeout,
956                                                    auto_retry,
957                                                    &transmit_for_response,
958                                                    tc))
959     {
960       GNUNET_break (0);
961       GNUNET_free (tc);
962       return GNUNET_SYSERR;
963     }
964   sock->tag = tc;
965   return GNUNET_OK;
966 }
967
968
969
970 /*  end of client.c */