+ struct GNUNET_MESH_Handle *h = cls;
+ struct GNUNET_MESH_TransmitHandle *th;
+ struct GNUNET_MESH_TransmitHandle *next;
+ struct GNUNET_MESH_Tunnel *t;
+ char *cbuf = buf;
+ size_t tsize;
+ size_t psize;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Send packet() Buffer %u\n", size);
+ if ((0 == size) || (NULL == buf))
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Received NULL send callback on %p\n", h);
+ reconnect (h);
+ h->th = NULL;
+ return 0;
+ }
+ tsize = 0;
+ next = h->th_head;
+ while ((NULL != (th = next)) && (size >= th->size))
+ {
+ t = th->tunnel;
+ if (GNUNET_YES == th_is_payload (th))
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " payload\n");
+ if (t->max_pid < t->pid && GNUNET_NO == PID_OVERFLOW (t->pid, t->max_pid))
+ {
+ /* This tunnel is not ready to transmit yet, try next message */
+ next = th->next;
+ continue;
+ }
+ t->packet_size = 0;
+ if (t->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);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " to origin, type %s\n",
+ GNUNET_MESH_DEBUG_M2S (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 (t->tid);
+ // FIXME pid?
+ 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);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " multicast, type %s\n",
+ GNUNET_MESH_DEBUG_M2S (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 (t->tid);
+ mc.pid = htonl (t->pid);
+ 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);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " unicast, type %s\n",
+ GNUNET_MESH_DEBUG_M2S (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 (t->tid);
+ uc.pid = htonl (t->pid);
+ memset (&uc.oid, 0, sizeof (struct GNUNET_PeerIdentity));
+ GNUNET_PEER_resolve (th->target, &uc.destination);
+ memcpy (cbuf, &uc, sizeof (uc));
+ }
+ }
+ t->pid++;
+ }
+ else
+ {
+ struct GNUNET_MessageHeader *mh = (struct GNUNET_MessageHeader *) &th[1];
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " mesh traffic, type %s\n",
+ GNUNET_MESH_DEBUG_M2S (ntohs (mh->type)));
+ memcpy (cbuf, &th[1], th->size);
+ psize = th->size;
+ }
+ if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (th->timeout_task);
+ GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th);
+ GNUNET_free (th);
+ next = h->th_head;
+ cbuf += psize;
+ size -= psize;
+ tsize += psize;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " total size: %u\n", tsize);
+ h->th = NULL;
+ size = message_ready_size (h);
+ if (0 != size)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " next size: %u\n", size);
+ h->th =
+ GNUNET_CLIENT_notify_transmit_ready (h->client, size,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_YES, &send_callback, h);
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " nothing left to transmit\n");
+ }
+ if (GNUNET_NO == h->in_receive)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " start receiving from service\n");
+ h->in_receive = GNUNET_YES;
+ GNUNET_CLIENT_receive (h->client, &msg_received, h,
+ GNUNET_TIME_UNIT_FOREVER_REL);
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Send packet() END\n");
+ return tsize;