+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "UDP received %u-byte message from `%s' type %i\n", (unsigned int) size,
+ GNUNET_a2s ((const struct sockaddr *) addr, fromlen), ntohs (msg->type));
+
+ if (size != ntohs (msg->size))
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+
+ switch (ntohs (msg->type))
+ {
+ case GNUNET_MESSAGE_TYPE_TRANSPORT_BROADCAST_BEACON:
+ udp_broadcast_receive (plugin, &buf, size, addr, fromlen);
+ return;
+
+ case GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_MESSAGE:
+ read_process_msg (plugin, msg, addr, fromlen);
+ return;
+
+ case GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_ACK:
+ read_process_ack (plugin, msg, addr, fromlen);
+ return;
+
+ case GNUNET_MESSAGE_TYPE_FRAGMENT:
+ read_process_fragment (plugin, msg, addr, fromlen);
+ return;
+
+ default:
+ GNUNET_break_op (0);
+ return;
+ }
+}
+
+
+static size_t
+udp_select_send (struct Plugin *plugin, struct GNUNET_NETWORK_Handle *sock)
+{
+ ssize_t sent;
+ size_t slen;
+ struct GNUNET_TIME_Absolute max;
+ struct UDPMessageWrapper *udpw = NULL;
+ static int network_down_error;
+
+ if (sock == plugin->sockv4)
+ {
+ udpw = plugin->ipv4_queue_head;
+ }
+ else if (sock == plugin->sockv6)
+ {
+ udpw = plugin->ipv6_queue_head;
+ }
+ else
+ {
+ GNUNET_break (0);
+ return 0;
+ }
+
+ const struct sockaddr * sa = udpw->session->sock_addr;
+ slen = udpw->session->addrlen;
+
+ max = GNUNET_TIME_absolute_max(udpw->timeout, GNUNET_TIME_absolute_get());
+
+ while (udpw != NULL)
+ {
+ if (max.abs_value != udpw->timeout.abs_value)
+ {
+ /* Message timed out */
+ call_continuation(udpw, GNUNET_SYSERR);
+ if (udpw->frag_ctx != NULL)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Fragmented message for peer `%s' with size %u timed out\n",
+ GNUNET_i2s(&udpw->session->target), udpw->frag_ctx->bytes_to_send);
+ udpw->session->last_expected_delay = GNUNET_FRAGMENT_context_destroy(udpw->frag_ctx->frag);
+ GNUNET_free (udpw->frag_ctx);
+ udpw->session->frag_ctx = NULL;
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Message for peer `%s' with size %u timed out\n",
+ GNUNET_i2s(&udpw->session->target), udpw->msg_size);
+ }
+
+ if (sock == plugin->sockv4)
+ {
+ GNUNET_CONTAINER_DLL_remove(plugin->ipv4_queue_head, plugin->ipv4_queue_tail, udpw);
+ GNUNET_free (udpw);
+ udpw = plugin->ipv4_queue_head;
+ }
+ else if (sock == plugin->sockv6)
+ {
+ GNUNET_CONTAINER_DLL_remove(plugin->ipv6_queue_head, plugin->ipv6_queue_tail, udpw);
+ GNUNET_free (udpw);
+ udpw = plugin->ipv6_queue_head;
+ }
+ }
+ else
+ {
+ struct GNUNET_TIME_Relative delta = GNUNET_TIME_absolute_get_remaining (udpw->session->flow_delay_from_other_peer);
+ if (delta.rel_value == 0)
+ {
+ /* this message is not delayed */
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Message for peer `%s' (%u bytes) is not delayed \n",
+ GNUNET_i2s(&udpw->session->target), udpw->msg_size);
+ break;
+ }
+ else
+ {
+ /* this message is delayed, try next */
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Message for peer `%s' (%u bytes) is delayed for %llu \n",
+ GNUNET_i2s(&udpw->session->target), udpw->msg_size,
+ delta);
+ udpw = udpw->next;
+ }
+ }
+ }
+
+ if (udpw == NULL)
+ {
+ /* No message left */
+ return 0;
+ }
+
+ sent = GNUNET_NETWORK_socket_sendto (sock, udpw->udp, udpw->msg_size, sa, slen);
+
+ if (GNUNET_SYSERR == sent)
+ {
+ const struct GNUNET_ATS_Information type = plugin->env->get_address_type
+ (plugin->env->cls,sa, slen);
+
+ if (((GNUNET_ATS_NET_LAN == ntohl(type.value)) || (GNUNET_ATS_NET_WAN == ntohl(type.value))) &&
+ ((ENETUNREACH == errno) || (ENETDOWN == errno)))
+ {
+ if ((network_down_error == GNUNET_NO) && (slen == sizeof (struct sockaddr_in)))
+ {
+ /* IPv4: "Network unreachable" or "Network down"
+ *
+ * This indicates we do not have connectivity
+ */
+ LOG (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
+ _("UDP could not transmit message to `%s': "
+ "Network seems down, please check your network configuration\n"),
+ GNUNET_a2s (sa, slen));
+ }
+ if ((network_down_error == GNUNET_NO) && (slen == sizeof (struct sockaddr_in6)))
+ {
+ /* IPv6: "Network unreachable" or "Network down"
+ *
+ * This indicates that this system is IPv6 enabled, but does not
+ * have a valid global IPv6 address assigned or we do not have
+ * connectivity
+ */
+
+ LOG (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
+ _("UDP could not transmit message to `%s': "
+ "Please check your network configuration and disable IPv6 if your "
+ "connection does not have a global IPv6 address\n"),
+ GNUNET_a2s (sa, slen));
+ }
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "UDP could not transmit %u-byte message to `%s': `%s'\n",
+ (unsigned int) (udpw->msg_size), GNUNET_a2s (sa, slen),
+ STRERROR (errno));
+ }
+ call_continuation(udpw, GNUNET_SYSERR);
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "UDP transmitted %u-byte message to `%s' (%d: %s)\n",
+ (unsigned int) (udpw->msg_size), GNUNET_a2s (sa, slen), (int) sent,
+ (sent < 0) ? STRERROR (errno) : "ok");
+ call_continuation(udpw, GNUNET_OK);
+ network_down_error = GNUNET_NO;
+ }
+
+ if (sock == plugin->sockv4)
+ GNUNET_CONTAINER_DLL_remove(plugin->ipv4_queue_head, plugin->ipv4_queue_tail, udpw);
+ else if (sock == plugin->sockv6)
+ GNUNET_CONTAINER_DLL_remove(plugin->ipv6_queue_head, plugin->ipv6_queue_tail, udpw);
+ GNUNET_free (udpw);
+ udpw = NULL;
+
+ return sent;
+}