package net.i2p.router.transport.udp; import java.util.List; import net.i2p.router.RouterContext; import net.i2p.util.I2PThread; import net.i2p.util.Log; /** * Blocking thread to grab new packets off the outbound fragment * pool and toss 'em onto the outbound packet queues. * * Here we select which UDPEndpoint/UDPSender to send it out. */ class PacketPusher implements Runnable { // private RouterContext _context; private final Log _log; private final OutboundMessageFragments _fragments; private final List<UDPEndpoint> _endpoints; private volatile boolean _alive; public PacketPusher(RouterContext ctx, OutboundMessageFragments fragments, List<UDPEndpoint> endpoints) { // _context = ctx; _log = ctx.logManager().getLog(PacketPusher.class); _fragments = fragments; _endpoints = endpoints; } public synchronized void startup() { _alive = true; I2PThread t = new I2PThread(this, "UDP packet pusher", true); t.start(); } public synchronized void shutdown() { _alive = false; } public void run() { while (_alive) { try { List<UDPPacket> packets = _fragments.getNextVolley(); if (packets != null) { for (int i = 0; i < packets.size(); i++) { send(packets.get(i)); } } } catch (RuntimeException e) { _log.error("SSU Output Queue Error", e); } } } /** * This sends it directly out, bypassing OutboundMessageFragments * and the PacketPusher. The only queueing is for the bandwidth limiter. * BLOCKING if OB queue is full. * * @param packet non-null * @since IPv6 */ public void send(UDPPacket packet) { boolean isIPv4 = packet.getPacket().getAddress().getAddress().length == 4; for (int j = 0; j < _endpoints.size(); j++) { // Find the best endpoint (socket) to send this out. // TODO if we have multiple IPv4, or multiple IPv6 endpoints, // we have to track which one we're using in the PeerState and // somehow set that in the UDPPacket so we're consistent UDPEndpoint ep; try { ep = _endpoints.get(j); } catch (IndexOutOfBoundsException ioobe) { // whups, list changed break; } if ((isIPv4 && ep.isIPv4()) || ((!isIPv4) && ep.isIPv6())) { // BLOCKING if queue is full ep.getSender().add(packet); return; } } // not handled _log.error("No endpoint to send " + packet); packet.release(); } }