Here is some code to determine the local host name that is supposed to work on a multi-homed box:
/**
* Work out the first local host name by iterating the network interfaces
*
* #return
* #throws SocketException
*/
private String findFirstLocalHostName() throws SocketException {
Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces();
while (ifaces.hasMoreElements()) {
NetworkInterface iface = ifaces.nextElement();
Enumeration<InetAddress> addresses = iface.getInetAddresses();
while (addresses.hasMoreElements()) {
InetAddress add = addresses.nextElement();
if (!add.isLoopbackAddress() && add.isSiteLocalAddress()) {
return add.getHostName();
}
}
}
throw new RuntimeException("Failed to determine local hostname");
}
Does the call to isSiteLocalAddress introduce a bug? I can't find any useful information about this method, but I have a feeling that it relates to IP v 6 only and is deprecated.
The method is definitely not deprecated and it's definitely not just used in IPv6.
In IPv4 there are 3 network address ranges that are defined for site-local addresses: 10/8, 172.16/12 and 192.168/16.
Reading Inet4Address.isSiteLocalAddress() shows that addresses from exactly those 3 networks will return true on those methods.
IPv6 has a similar concept, here these addresses are called unique local addresses.
Effectively this tells you if the address you have is definitely not a public one (note that even if this method returns false, the address might still not be public).
Looking at the implementation...
For an Inet4Address, it checks to see if it's one of the RFC1918 "unrouteable" addresses: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16.
For an Inet6Address, it checks the first two octets to see if it's a real "site local" address.
'Site local' is a deprecated name for private IP space. (Some nuances, but basically right.) See RFC 1918.
I just came across what I believe is a similar problem: trying to determine what IPv6 I should use for LAN comuncation:
IMHO, Inet6Address.isSiteLocalAddress() is useless. Given that the 0xFEC0 prefix has been depricated by RFC 3879 as #tigz mentioned. I have yet to see any device (android, win, osx) actually have a 0xFEC0 (with limited testing)
//from java.net.Inet6Address (1.8.0_45)
boolean isSiteLocalAddress() {
return ((ipaddress[0] & 0xff) == 0xfe
&& (ipaddress[1] & 0xc0) == 0xc0);
}
0xFE80 address although not supposed be used for traffic (from my understanding and reading (www.cisco.com)) did work for LAN communication with my single router (ping6, curl, http).
My Global Unicast (which is just another name for public IP) 2601::/20 from Comcast worked for my LAN communication. So I would say that this is the correct address to use.
Prefix table: www.iana.org
As far as I know the isSiteLocalAddress method is not deprecated.
isSiteLocalAddress - Explanation
indicating if the InetAddress is a site local address; or false if address is not a site local unicast address.
The InetAddress even have two direct subclasses;
Inet4Address and
Inet6Address
The best bet is to read the JavaDocs.
Which version of the JDK are you using?
Related
If I am not wrong, one can connect to a Cassandra cluster knowing at least one of the nodes that is in the cluster, and then the others can be discovered.
Lets say I have three nodes (1, 2 and 3) and I connect to those nodes like this:
Cluster.builder().addContactPoints("1,2,3".split(",")).build();
Then, if node 3 for example goes down, and the IP cannot be resolved, this line of code will throw an IllegalArgumentException as stated in the docs:
#throws IllegalArgumentException if no IP address for at least one of {#code addresses} could be found
Why would anyone want this behavior? I mean, if one of the nodes is down, I want the app to be able to run, as the Cassandra is still working fine.
I have checked this Cassandra Java driver: how many contact points is reasonable?
but that does not answer my question as it doesn't say anything about hosts than can't be reachable.
How should I handle this? Maybe this is changed in another version of the java driver? I am currently using cassandra-driver-core-3.0.3
This validation is only to make sure that all the provided hosts can be resolved, it doesn't even check if a Cassandra server is running on each host. So it is basically to ensure that you did not do any typos while providing the hosts as indeed it doesn't assume that it could be a normal use case to have a provided host that cannot be resolved.
As workaround in your case (host been removed from the DNS entries), you could simply call the method addContactPoint(String address) explicitly instead of using addContactPoints(String... addresses) (which behind the scene simply call addContactPoint(String address) for each provided address) and manage the exception by yourself.
The code could be something like this:
Cluster.Builder builder = Cluster.builder();
// Boolean used to check if at least one host could be resolved
boolean found = false;
for (String address : "1,2,3".split(",")) {
try {
builder.addContactPoint(address);
// One host could be resolved
found = true;
} catch (IllegalArgumentException e) {
// This host could not be resolved so we log a message and keep going
Log.log(
Level.WARNING,
String.format("The host '%s' is unknown so it will be ignored", address)
);
}
}
if (!found) {
// No host could be resolved so we throw an exception
throw new IllegalStateException("All provided hosts are unknown");
}
Cluster cluster = builder.build();
FYI: I've just created a ticket to propose an improvement in the Java driver https://datastax-oss.atlassian.net/browse/JAVA-1334.
As Nick mentioned, it's based on DNS resolution, not Cassandra server health.
If you remove hosts from your environment more often than you recompile your application, then you should consider not baking your contact points into the code, and instead, feed them in through some other means (environment variable, REST service, a single DNS name that always resolves to one live seed, etc).
The documentation there is just in regards to "resolving" the contact points that are passed in. So converting hostnames to ip addresses. If you are specifying ip addresses to begin with, they will not be resolved, simply checked for validity. If you are using hostnames then each contact point will need to be resolvable. This doesn't mean that the cassandra machine needs to be running, just that a DNS lookup on the hostname returns any ip address. So the case where things would break would be if you removed a DNS entry for one of your contact points and restarted your application.
I am attempting to use the InetSocketAddress that is part of Java.net. Although when I try to actually give it data for its perimeters it does not work. The documentation does not actually specify how to define the IP address and port. It states it goes as follows: InetSocketAddress(InetAddress addr, int port) , addr being the IP address. I have tried the following ways:
InetSocketAddress("0.0.0.0", 0000)
InetSocketAddress(0.0.0.0, 0000)
InetSocketAddress(0.0.0.0:0000)
Obviously none of these work (using arbitrary values), all but the last, the port works cause it's just an int but I can't figure out how to format the IP address correctly. The docs I have read over in search of a solution are as follows:
InetAddress
Inet4Address
InetSocketAddress
None of these actaully have an example of how to format the IP address (unless I'm blind of course).
InetSocketAddress wants an InetAddress object for the first parameter. So you need to send it one with something like:
InetSocketAddress(InetAddress.getByName("0.0.0.0", 0))
I know, getByName() doesn't sound like it should be used with an IP address, but it works with both an address or host name.
You can use this.
InetSocketAddress address=new InetSocketAddress(InetAddress.getByName("0.0.0.0"),0000);
InetSocketAddress has no parameter is String, int constructor
I'm don't understand, why code below prints 0.0.9.229 instead 127.0.0.1. Can anybody tell me, hot to fix that?
String ha = InetAddress.getLocalHost().getHostAddress();
System.out.println(ha);
UPD:
Code running on Ubuntu
/etc/hosts
127.0.0.1 localhost
127.0.1.1 2533
InetAddress.getLocalHost() doesn't do what most people think that it does. It actually returns the hostname of the machine, and the IP address associated with that hostname. This may be the address used to connect to the outside world. It may not. It just depends on how you have your system configured.
On my windowsbox it gets the machine name and the external ip address. On my linux box it returns hostname and 127.0.0.1 because I have it set so in /etc/hosts
The problem is that my hostname will consists only of numbers and could not be resolved.
I change my /etc/hostname with characters at first position and problem has solved.
Use NetworkInterface to enumerate network interfaces; InetAddress.getLocalHost() always returns loopback.If you want to get all IP's associated with your machine use NetworkInterface then you will get 127.0.0.1 also.
Enumeration<NetworkInterface> nInterfaces = NetworkInterface.getNetworkInterfaces();
while (nInterfaces.hasMoreElements()) {
Enumeration<InetAddress> inetAddresses = nInterfaces.nextElement().getInetAddresses();
while (inetAddresses.hasMoreElements()) {
String address = inetAddresses.nextElement().getHostAddress();
System.out.println(address);
}
}
public class InetAddresTest {
public static void main(String ... agrs) {
try {
InetAddress inet = InetAddress.getByName("1.2");
System.out.println("Good ip address");
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
BTW the InetAddress produced ip address comes back as "1.0.0.2" . I could not find a reasonable answer from the javadoc of InetAddress. Can you someone explain this behaviour ?
From the Javadoc (Linked in "Textual representation of IP addresses" in the Javadoc for InetAddress ):
When a two part address is supplied, the last part is interpreted as a 24-bit quantity and placed in the right most three bytes of the network address. This makes the two part address format convenient for specifying Class A network addresses as net.host.
Edit to add: In case the 24bit part is confusing to you:
2 in 24bit would look like: 00000000 00000000 00000010
Which is then mapped to the right 3 octets in the IPv4 address as: .0.0.2
One More: As CoolBeans mentions in the comments to your question, the InetAddressValidator from Apache commons would do the trick. That being said, if you just want to validate IP addresses and not have an external dependency, you can use Regular Expressions to check IP addresses as well
I've tried many examples on web and one of them is this:
http://zerioh.tripod.com/ressources/sockets.html
All of the server-client socket examples work fine when they are tested with 127.0.0.1
BUT it never ever EVAR works on two different computers with actual raw real IP address ("could not connect to host" on telnet and "connection timed out" when tested on java client - the server program just waits for connection)
Note:
Firewall is turned off for sure
IP address from ipconfig didn't work
IP address from myipaddress.com (which is totally different for no reason than that from ipconfig) didn't work
What is it that I'm missing?
If I can only figure this out...
Try binding on 0.0.0.0. This tells your socket to accept connections on every IP your local can accept upon.
Based on the comment where the the following snippet of code is mentioned:
requestSocket = new Socket("10.0.0.5", 2004); // ip from ipconfig
it would be better to use the hostname instead of the IP address in the constructor, as the two-parameter Socket constructor with a String argument expects the hostname as the String, and not an IP address. A lookup of the IP address is then performed on the provided hostname.
If you need to pass in an IP address, use the two-parameter constructor that accepts the InetAddress as an argument. You can then provide a raw IP address to the InetAddress.getByAddress method, as shown in the following snippet:
InetAddress addr = InetAddress.getByAddress(new byte[]{10,0,0,5});
You'll need to be careful when specifying arguments via the byte array, as bytes are signed in Java (-127 through +128), and numbers beyond this range (but valid octets of IP addresses) may have to be specified using Integer.byteValue.
Finally, it should be noted that it is important to specify the IP address of the remote machine, as visible to the client. The IP address listed at myipaddress.com may be the address of a proxy, as that is the public IP of your entire network as visible to the host server at myipaddress.com. Therefore, you ought to be specify the IP address of the remote machine that is visible to your machine and not myipaddress.com.