+/**
+ * Re-establish the connection to the ATS service.
+ *
+ * @param sh handle to use to re-connect.
+ */
+static void
+reconnect (struct GNUNET_ATS_PerformanceHandle *ph);
+
+
+/**
+ * Transmit messages from the message queue to the service
+ * (if there are any, and if we are not already trying).
+ *
+ * @param sh handle to use
+ */
+static void
+do_transmit (struct GNUNET_ATS_PerformanceHandle *ph);
+
+
+/**
+ * We can now transmit a message to ATS. Do it.
+ *
+ * @param cls the 'struct GNUNET_ATS_SchedulingHandle'
+ * @param size number of bytes we can transmit to ATS
+ * @param buf where to copy the messages
+ * @return number of bytes copied into buf
+ */
+static size_t
+transmit_message_to_ats (void *cls,
+ size_t size,
+ void *buf)
+{
+ struct GNUNET_ATS_PerformanceHandle *ph = cls;
+ struct PendingMessage *p;
+ size_t ret;
+ char *cbuf;
+
+ ph->th = NULL;
+ ret = 0;
+ cbuf = buf;
+ while ( (NULL != (p = ph->pending_head)) &&
+ (p->size <= size) )
+ {
+ memcpy (&cbuf[ret], &p[1], p->size);
+ ret += p->size;
+ GNUNET_CONTAINER_DLL_remove (ph->pending_head,
+ ph->pending_tail,
+ p);
+ GNUNET_free (p);
+ }
+ do_transmit (ph);
+ return ret;
+}
+
+
+/**
+ * Transmit messages from the message queue to the service
+ * (if there are any, and if we are not already trying).
+ *
+ * @param ph handle to use
+ */
+static void
+do_transmit (struct GNUNET_ATS_PerformanceHandle *ph)
+{
+ struct PendingMessage *p;
+
+ if (NULL != ph->th)
+ return;
+ if (NULL == (p = ph->pending_head))
+ return;
+ ph->th = GNUNET_CLIENT_notify_transmit_ready (ph->client,
+ p->size,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_YES,
+ &transmit_message_to_ats, ph);
+}
+
+
+/**
+ * Type of a function to call when we receive a message
+ * from the service.
+ *
+ * @param cls the 'struct GNUNET_ATS_SchedulingHandle'
+ * @param msg message received, NULL on timeout or fatal error
+ */
+static void
+process_ats_message (void *cls,
+ const struct GNUNET_MessageHeader *msg)
+{
+ struct GNUNET_ATS_PerformanceHandle *ph = cls;
+
+ if (NULL == msg)
+ {
+ GNUNET_CLIENT_disconnect (ph->client, GNUNET_NO);
+ ph->client = NULL;
+ reconnect (ph);
+ return;
+ }
+ switch (ntohs (msg->type))
+ {
+ // FIXME
+ default:
+ GNUNET_break (0);
+ GNUNET_CLIENT_disconnect (ph->client, GNUNET_NO);
+ ph->client = NULL;
+ reconnect (ph);
+ return;
+ }
+ GNUNET_CLIENT_receive (ph->client,
+ &process_ats_message, ph,
+ GNUNET_TIME_UNIT_FOREVER_REL);
+}
+
+
+/**
+ * Re-establish the connection to the ATS service.
+ *
+ * @param ph handle to use to re-connect.
+ */
+static void
+reconnect (struct GNUNET_ATS_PerformanceHandle *ph)
+{
+ struct PendingMessage *p;
+ struct ClientStartMessage *init;
+
+ GNUNET_assert (NULL == ph->client);
+ ph->client = GNUNET_CLIENT_connect ("ats", ph->cfg);
+ GNUNET_assert (NULL != ph->client);
+ GNUNET_CLIENT_receive (ph->client,
+ &process_ats_message, ph,
+ GNUNET_TIME_UNIT_FOREVER_REL);
+ if ( (NULL == (p = ph->pending_head)) ||
+ (GNUNET_YES != p->is_init) )
+ {
+ p = GNUNET_malloc (sizeof (struct PendingMessage) +
+ sizeof (struct ClientStartMessage));
+ p->size = sizeof (struct ClientStartMessage);
+ p->is_init = GNUNET_YES;
+ init = (struct ClientStartMessage *) &p[1];
+ init->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_START);
+ init->header.size = htons (sizeof (struct ClientStartMessage));
+ init->start_flag = htonl ((ph->infocb == NULL)
+ ? START_FLAG_PERFORMANCE_NO_PIC
+ : START_FLAG_PERFORMANCE_WITH_PIC);
+ GNUNET_CONTAINER_DLL_insert (ph->pending_head,
+ ph->pending_tail,
+ p);
+ }
+ do_transmit (ph);
+}
+
+
+