The problem is that, as of Mono 1.2.6, IPEndPoint.LocalEndPoint and IPEndPoint.RemoteEndPoint return null for a socket that was connected non-blocking. (In versions prior to 1.2.6, these properties returned the correct endpoint.)
One could argue that this is not a bug because .NET does the same thing
If you look in Network.cs, around line 1320, you will find a number of DllImport statements. You need to replace these with the name of your C library, for example
Code:
#if __MonoCS__
[DllImport("libc-2.3.6.so")]
#else
[DllImport("wsock32.dll")]
#endif
private static extern int getsockname(IntPtr s, ref sockaddr name, ref int namelen);
Do the same for the getpeername, inet_ntoa, and ntohs imports.
Then change the definitions of getLocalAddress and getRemoteAddress as follows:
Code:
public static IPEndPoint
getLocalAddress(Socket socket)
{
//
// .Net BUG: The LocalEndPoint and RemoteEndPoint properties
// are null for a socket that was connected in non-blocking
// mode. As of Mono 1.2.6, Mono behaves the same way.
// The only way to make this work is to step down to
// the native API and use platform invoke :-(
//
IPEndPoint localEndpoint;
sockaddr addr = new sockaddr();
int addrLen = 16;
if(getsockname(socket.Handle, ref addr, ref addrLen) != 0)
{
throw new Ice.SyscallException();
}
string ip = Marshal.PtrToStringAnsi(inet_ntoa(addr.sin_addr));
int port = ntohs(addr.sin_port);
localEndpoint = new IPEndPoint(IPAddress.Parse(ip), port);
return localEndpoint;
}
public static IPEndPoint
getRemoteAddress(Socket socket)
{
//
// .Net BUG: The LocalEndPoint and RemoteEndPoint properties
// are null for a socket that was connected in non-blocking
// mode. As of Mono 1.2.6, Mono behaves the same way.
// The only way to make this work is to step down to
// the native API and use platform invoke :-(
//
IPEndPoint remoteEndpoint = null;
sockaddr addr = new sockaddr();
int addrLen = 16;
if(getpeername(socket.Handle, ref addr, ref addrLen) == 0)
{
string ip = Marshal.PtrToStringAnsi(inet_ntoa(addr.sin_addr));
int port = ntohs(addr.sin_port);
remoteEndpoint = new IPEndPoint(IPAddress.Parse(ip), port);
}
return remoteEndpoint;
}
This fixes the problem. I'm not entirely happy with this P/Invoke fix though because the library name is platform dependent
For the moment, this fix should get you off the hook. I'll talk to the Mono people to see whether there is a better way to do this.
Cheers,
Michi.