+/**
+ * Function called to send a message to the service.
+ * "buf" will be NULL and "size" zero if the socket was closed for writing in
+ * the meantime.
+ *
+ * @param cls closure, the mesh handle
+ * @param size number of bytes available in buf
+ * @param buf where the callee should write the connect message
+ * @return number of bytes written to buf
+ */
+static size_t
+send_callback (void *cls, size_t size, void *buf)
+{
+ struct GNUNET_MESH_Handle *h = cls;
+ struct GNUNET_MESH_TransmitHandle *th;
+ char *cbuf = buf;
+ size_t tsize;
+ size_t psize;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: Send packet() Buffer %u\n", size);
+ h->th = NULL;
+ if ((0 == size) || (NULL == buf))
+ {
+ reconnect (h);
+ return 0;
+ }
+ tsize = 0;
+ while ((NULL != (th = h->th_head)) && (size >= th->size))
+ {
+ if (NULL != th->notify)
+ {
+ if (th->tunnel->tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV)
+ {
+ /* traffic to origin */
+ struct GNUNET_MESH_ToOrigin to;
+ struct GNUNET_MessageHeader *mh;
+
+ GNUNET_assert (size >= th->size);
+ mh = (struct GNUNET_MessageHeader *) &cbuf[sizeof (to)];
+ psize = th->notify (th->notify_cls, size - sizeof (to), mh);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: to origin, type %u\n",
+ ntohs (mh->type));
+ if (psize > 0)
+ {
+ psize += sizeof (to);
+ GNUNET_assert (size >= psize);
+ to.header.size = htons (psize);
+ to.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN);
+ to.tid = htonl (th->tunnel->tid);
+ memset (&to.oid, 0, sizeof (struct GNUNET_PeerIdentity));
+ memset (&to.sender, 0, sizeof (struct GNUNET_PeerIdentity));
+ memcpy (cbuf, &to, sizeof (to));
+ }
+ }
+ else if (th->target == 0)
+ {
+ /* multicast */
+ struct GNUNET_MESH_Multicast mc;
+ struct GNUNET_MessageHeader *mh;
+
+ GNUNET_assert (size >= th->size);
+ mh = (struct GNUNET_MessageHeader *) &cbuf[sizeof (mc)];
+ psize = th->notify (th->notify_cls, size - sizeof (mc), mh);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: multicast, type %u\n",
+ ntohs (mh->type));
+ if (psize > 0)
+ {
+ psize += sizeof (mc);
+ GNUNET_assert (size >= psize);
+ mc.header.size = htons (psize);
+ mc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_MULTICAST);
+ mc.tid = htonl (th->tunnel->tid);
+ mc.mid = 0;
+ mc.ttl = 0;
+ memset (&mc.oid, 0, sizeof (struct GNUNET_PeerIdentity));
+ memcpy (cbuf, &mc, sizeof (mc));
+ }
+ }
+ else
+ {
+ /* unicast */
+ struct GNUNET_MESH_Unicast uc;
+ struct GNUNET_MessageHeader *mh;
+
+ GNUNET_assert (size >= th->size);
+ mh = (struct GNUNET_MessageHeader *) &cbuf[sizeof (uc)];
+ psize = th->notify (th->notify_cls, size - sizeof (uc), mh);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mesh: unicast, type %u\n",
+ ntohs (mh->type));
+ if (psize > 0)
+ {
+ psize += sizeof (uc);
+ GNUNET_assert (size >= psize);
+ uc.header.size = htons (psize);
+ uc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_UNICAST);
+ uc.tid = htonl (th->tunnel->tid);
+ memset (&uc.oid, 0, sizeof (struct GNUNET_PeerIdentity));
+ GNUNET_PEER_resolve (th->target, &uc.destination);
+ memcpy (cbuf, &uc, sizeof (uc));
+ }
+ }
+ }
+ else
+ {
+ memcpy (cbuf, &th[1], th->size);
+ psize = th->size;
+ }
+ if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (th->timeout_task);
+ if (NULL != th->tunnel)
+ {
+ th->tunnel->mesh->npackets--;
+ th->tunnel->npackets--;
+ }
+ GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th);
+ GNUNET_free (th);
+ cbuf += psize;
+ size -= psize;
+ tsize += psize;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: total size: %u\n", tsize);
+ if (NULL != (th = h->th_head))
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: next size: %u\n", th->size);
+ h->th =
+ GNUNET_CLIENT_notify_transmit_ready (h->client, th->size,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_YES, &send_callback, h);
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "mesh: Send packet() END\n");
+ if (GNUNET_NO == h->in_receive)
+ {
+ h->in_receive = GNUNET_YES;
+ GNUNET_CLIENT_receive (h->client, &msg_received, h,
+ GNUNET_TIME_UNIT_FOREVER_REL);
+ }
+ return tsize;
+}