You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@mina.apache.org by Greg Duffy <gd...@gmail.com> on 2006/03/08 22:27:07 UTC

Datagram connector local port

So here's the scenario:

I need to tell a DatagramConnector what local port to use when sending
datagrams to a remote address/port, but I also need to preserve the
local address in the process. I use the specific local address (which
is chosen internally by Java from the routing table, I guess, and can
vary in a machine with multiple NICs) in my protocol implementation.

It seems like I should be able to set the local port without changing
the local address. Is there a way to accomplish this? I couldn't even
find a way using the standard Java APIs, but maybe I'm missing
something.

Thanks,
Greg

Re: Datagram connector local port

Posted by Greg Duffy <gd...@gmail.com>.
Here is my workaround, if you could use it in MINA please feel free to
do so. It's pretty general, and my initial tests show that it scales
to 1, 10, and 100 threads and stays at about 10,000 calls per second
total with each number of threads. If you don't synchronize and
instead create and close new sockets each time, it drops to 1,000 ...
so I think this way is best.

It's better than waiting for Sun at least :)

-Greg

---------- BEGIN SOURCE ----------

	private DatagramSocket localAddressResolverSocket;

	public synchronized InetAddress getLocalAddress(InetAddress
remoteAddress) throws IOException
	{
		if(localAddressResolverSocket == null)
		{
			localAddressResolverSocket = new DatagramSocket(new
InetSocketAddress(AvailablePortFinder.getNextAvailable()));
		}
		
		SocketAddress remoteSocketAddress = new InetSocketAddress(remoteAddress, 0);

		InetAddress localAddress = null;

		localAddressResolverSocket.connect(remoteSocketAddress);

		localAddress = localAddressResolverSocket.getLocalAddress();

		localAddressResolverSocket.disconnect();

		return localAddress;
	}

---------- END SOURCE ----------

On 3/8/06, Greg Duffy <gd...@gmail.com> wrote:
> Yeah that's my current problem :(
>
> I noticed that the Sun bug (for SocketChannel) was marked fixed in a
> mustang beta, so I downloaded the latest mustang build and tried it
> out. It turns out that the issue is fixed in mustang for
> SocketChannel, but not for DatagramChannel.
>
> So I filed a bug with Sun about DatagramChannel, but I don't think
> that this will be a very expedient method of dealing with the problem,
> though.
>
> My only possible workaround at this point is to use a DatagramSocket
> (which behaves correctly, and changes the local address from the
> wildcard after connect) to scope out the local address before I
> connect. Otherwise, this is a showstopper for me since the protocol
> I'm working with requires the local address to be sent in-payload for
> routing purposes. Also, our particular use case requires multihomed
> hosts, which means I can't just query the local host address via the
> InetAddress class. When the message goes out, I need to know the bound
> address of the interface it is actually travelling through.
>
> Well, thanks for looking into this Trustin, and if you think of
> anything else please do let me know.
>
> -Greg
>
> PS: Here's the test case I submitted to Sun, just in case it helps
> anyone else out:
>
> ---------- BEGIN SOURCE ----------
> import java.io.IOException;
> import java.net.DatagramSocket;
> import java.net.InetSocketAddress;
> import java.nio.channels.DatagramChannel;
>
> public class DatagramChannelTest
> {
>         public static void main(String[] args) throws IOException
>         {
>                 final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", 0);
>                 InetSocketAddress localAddress = null;
>
>                 DatagramSocket socket = new DatagramSocket(8888);
>                 socket.connect(remoteAddress);
>                 localAddress = (InetSocketAddress) socket.getLocalSocketAddress();
>
>                 // Expected: DatagramSocket local address: localhost:8888
>                 System.out.println("DatagramSocket local address: " +
> localAddress.getHostName() + ":" + localAddress.getPort());
>                 socket.close();
>
>                 DatagramChannel channel1 = DatagramChannel.open();
>                 channel1.connect(remoteAddress);
>                 localAddress = (InetSocketAddress) channel1.socket().getLocalSocketAddress();
>
>                 // Expected: DatagramChannel #1 local address: localhost:?
>                 System.out.println("DatagramChannel #1 local address: " +
> localAddress.getHostName() + ":" + localAddress.getPort());
>
>                 channel1.close();
>
>                 DatagramChannel channel2 = DatagramChannel.open();
>                 channel2.socket().bind(new InetSocketAddress(9999));
>                 channel2.connect(remoteAddress);
>                 localAddress = (InetSocketAddress) channel2.socket().getLocalSocketAddress();
>
>                 // Expected: DatagramChannel #2 local address: localhost:9999
>                 System.out.println("DatagramChannel #2 local address: " +
> localAddress.getHostName() + ":" + localAddress.getPort());
>
>                 channel2.close();
>         }
> }
> ---------- END SOURCE ----------
>
> On 3/8/06, Trustin Lee <tr...@gmail.com> wrote:
> > On 3/9/06, Trustin Lee <tr...@gmail.com> wrote:
> > >
> > > I think we can work around this issue by caching local address, too.
> > > Please let me know which transport type is a problem.  Is DatagramChannel
> > > the only issue?
> > >
> >
> > No it's not possible if a user binds to 0.0.0.0 (all devices).  So it's a
> > JDK issue unfortunately.
> >
> > Trustin
> > --
> > what we call human nature is actually human habit
> > --
> > http://gleamynode.net/
> > --
> > PGP key fingerprints:
> > * E167 E6AF E73A CBCE EE41  4A29 544D DE48 FE95 4E7E
> > * B693 628E 6047 4F8F CFA4  455E 1C62 A7DC 0255 ECA6
> >
> >
>

Re: Datagram connector local port

Posted by Greg Duffy <gd...@gmail.com>.
Yeah that's my current problem :(

I noticed that the Sun bug (for SocketChannel) was marked fixed in a
mustang beta, so I downloaded the latest mustang build and tried it
out. It turns out that the issue is fixed in mustang for
SocketChannel, but not for DatagramChannel.

So I filed a bug with Sun about DatagramChannel, but I don't think
that this will be a very expedient method of dealing with the problem,
though.

My only possible workaround at this point is to use a DatagramSocket
(which behaves correctly, and changes the local address from the
wildcard after connect) to scope out the local address before I
connect. Otherwise, this is a showstopper for me since the protocol
I'm working with requires the local address to be sent in-payload for
routing purposes. Also, our particular use case requires multihomed
hosts, which means I can't just query the local host address via the
InetAddress class. When the message goes out, I need to know the bound
address of the interface it is actually travelling through.

Well, thanks for looking into this Trustin, and if you think of
anything else please do let me know.

-Greg

PS: Here's the test case I submitted to Sun, just in case it helps
anyone else out:

---------- BEGIN SOURCE ----------
import java.io.IOException;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.nio.channels.DatagramChannel;

public class DatagramChannelTest
{
	public static void main(String[] args) throws IOException
	{
		final InetSocketAddress remoteAddress = new InetSocketAddress("localhost", 0);
		InetSocketAddress localAddress = null;

		DatagramSocket socket = new DatagramSocket(8888);
		socket.connect(remoteAddress);
		localAddress = (InetSocketAddress) socket.getLocalSocketAddress();
		
		// Expected: DatagramSocket local address: localhost:8888
		System.out.println("DatagramSocket local address: " +
localAddress.getHostName() + ":" + localAddress.getPort());
		socket.close();

		DatagramChannel channel1 = DatagramChannel.open();
		channel1.connect(remoteAddress);
		localAddress = (InetSocketAddress) channel1.socket().getLocalSocketAddress();

		// Expected: DatagramChannel #1 local address: localhost:?
		System.out.println("DatagramChannel #1 local address: " +
localAddress.getHostName() + ":" + localAddress.getPort());

		channel1.close();

		DatagramChannel channel2 = DatagramChannel.open();
		channel2.socket().bind(new InetSocketAddress(9999));
		channel2.connect(remoteAddress);
		localAddress = (InetSocketAddress) channel2.socket().getLocalSocketAddress();

		// Expected: DatagramChannel #2 local address: localhost:9999
		System.out.println("DatagramChannel #2 local address: " +
localAddress.getHostName() + ":" + localAddress.getPort());

		channel2.close();
	}
}
---------- END SOURCE ----------

On 3/8/06, Trustin Lee <tr...@gmail.com> wrote:
> On 3/9/06, Trustin Lee <tr...@gmail.com> wrote:
> >
> > I think we can work around this issue by caching local address, too.
> > Please let me know which transport type is a problem.  Is DatagramChannel
> > the only issue?
> >
>
> No it's not possible if a user binds to 0.0.0.0 (all devices).  So it's a
> JDK issue unfortunately.
>
> Trustin
> --
> what we call human nature is actually human habit
> --
> http://gleamynode.net/
> --
> PGP key fingerprints:
> * E167 E6AF E73A CBCE EE41  4A29 544D DE48 FE95 4E7E
> * B693 628E 6047 4F8F CFA4  455E 1C62 A7DC 0255 ECA6
>
>

Re: Datagram connector local port

Posted by Trustin Lee <tr...@gmail.com>.
On 3/9/06, Trustin Lee <tr...@gmail.com> wrote:
>
> I think we can work around this issue by caching local address, too.
> Please let me know which transport type is a problem.  Is DatagramChannel
> the only issue?
>

No it's not possible if a user binds to 0.0.0.0 (all devices).  So it's a
JDK issue unfortunately.

Trustin
--
what we call human nature is actually human habit
--
http://gleamynode.net/
--
PGP key fingerprints:
* E167 E6AF E73A CBCE EE41  4A29 544D DE48 FE95 4E7E
* B693 628E 6047 4F8F CFA4  455E 1C62 A7DC 0255 ECA6

Re: Datagram connector local port

Posted by Trustin Lee <tr...@gmail.com>.
I think we can work around this issue by caching local address, too.  Please
let me know which transport type is a problem.  Is DatagramChannel the only
issue?

Trustin

On 3/9/06, Greg Duffy <gd...@gmail.com> wrote:
>
> I think this may actually be related to a Java bug.
>
> http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5076965
>
> -Greg
>
> On 3/8/06, Greg Duffy <gd...@gmail.com> wrote:
> > So here's the scenario:
> >
> > I need to tell a DatagramConnector what local port to use when sending
> > datagrams to a remote address/port, but I also need to preserve the
> > local address in the process. I use the specific local address (which
> > is chosen internally by Java from the routing table, I guess, and can
> > vary in a machine with multiple NICs) in my protocol implementation.
> >
> > It seems like I should be able to set the local port without changing
> > the local address. Is there a way to accomplish this? I couldn't even
> > find a way using the standard Java APIs, but maybe I'm missing
> > something.
> >
> > Thanks,
> > Greg
> >
>



--
what we call human nature is actually human habit
--
http://gleamynode.net/
--
PGP key fingerprints:
* E167 E6AF E73A CBCE EE41  4A29 544D DE48 FE95 4E7E
* B693 628E 6047 4F8F CFA4  455E 1C62 A7DC 0255 ECA6

Re: Datagram connector local port

Posted by Greg Duffy <gd...@gmail.com>.
I think this may actually be related to a Java bug.

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5076965

-Greg

On 3/8/06, Greg Duffy <gd...@gmail.com> wrote:
> So here's the scenario:
>
> I need to tell a DatagramConnector what local port to use when sending
> datagrams to a remote address/port, but I also need to preserve the
> local address in the process. I use the specific local address (which
> is chosen internally by Java from the routing table, I guess, and can
> vary in a machine with multiple NICs) in my protocol implementation.
>
> It seems like I should be able to set the local port without changing
> the local address. Is there a way to accomplish this? I couldn't even
> find a way using the standard Java APIs, but maybe I'm missing
> something.
>
> Thanks,
> Greg
>