void send(UdpHeader header, OutputStream output) throws IOException {
        short localPort = header.getSourcePort();
        UdpVATunnel tunnel = mTunnels.get(localPort);
        try {
            if (tunnel == null) {
                Session session = mSessionProvider.query(localPort);
                if (session == null) {
                    throw new IOException("No session saved with key: " + localPort);
                }

                IpHeader ipHeader = header.getIpHeader();
                NioTunnel remoteTunnel = new UdpRemoteTunnel(mVpnService, DatagramChannel.open(),
                        mSelector, NetBareUtils.convertIp(session.remoteIp), session.remotePort);
                tunnel = new UdpVATunnel(session, remoteTunnel, output, mMtu);
                tunnel.connect(new InetSocketAddress(NetBareUtils.convertIp(ipHeader.getDestinationIp()),
                        NetBareUtils.convertPort(header.getDestinationPort())));
                mTunnels.put(header.getSourcePort(), tunnel);
            }
            tunnel.send(header);
        } catch (IOException e) {
            mTunnels.remove(localPort);
            NetBareUtils.closeQuietly(tunnel);
            throw e;
        }
    }
The UDP proxy server is a virtual server, every packet from {@link UdpProxyServerForwarder} is
saw as a connection. It use {@link UdpVATunnel} to bind {@link VirtualGateway} and
{@link NioTunnel} together. Not like TCP, UDP only use {@link UdpRemoteTunnel} to communicate with
real remote server.

@author Megatron King
@since 2018-10-11 17:35
netbare-core/src/main/java/com/github/megatronking/netbare/proxy/UdpProxyServer.java