1 /*
2 * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 #include <windows.h>
27 #include <winsock2.h>
28 #include <ctype.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <malloc.h>
32 #include <sys/types.h>
33 #include <process.h>
34
35 #include "java_net_InetAddress.h"
36 #include "java_net_Inet4AddressImpl.h"
37 #include "net_util.h"
38 #include "icmp.h"
39
40
41 /*
42 * Returns true if hostname is in dotted IP address format. Note that this
43 * function performs a syntax check only. For each octet it just checks that
44 * the octet is at most 3 digits.
45 */
46 jboolean isDottedIPAddress(const char *hostname, unsigned int *addrp) {
47 char *c = (char *)hostname;
48 int octets = 0;
49 unsigned int cur = 0;
50 int digit_cnt = 0;
51
52 while (*c) {
53 if (*c == '.') {
54 if (digit_cnt == 0) {
55 return JNI_FALSE;
56 } else {
57 if (octets < 4) {
58 addrp[octets++] = cur;
59 cur = 0;
60 digit_cnt = 0;
61 } else {
62 return JNI_FALSE;
63 }
64 }
65 c++;
66 continue;
67 }
68
69 if ((*c < '0') || (*c > '9')) {
70 return JNI_FALSE;
71 }
72
73 digit_cnt++;
74 if (digit_cnt > 3) {
75 return JNI_FALSE;
76 }
77
78 /* don't check if current octet > 255 */
79 cur = cur*10 + (*c - '0');
80
81 /* Move onto next character and check for EOF */
82 c++;
83 if (*c == '\0') {
84 if (octets < 4) {
85 addrp[octets++] = cur;
86 } else {
87 return JNI_FALSE;
88 }
89 }
90 }
91
92 return (jboolean)(octets == 4);
93 }
94
95 /*
96 * Inet4AddressImpl
97 */
98
99 /*
100 * Class: java_net_Inet4AddressImpl
101 * Method: getLocalHostName
102 * Signature: ()Ljava/lang/String;
103 */
104 JNIEXPORT jstring JNICALL
105 Java_java_net_Inet4AddressImpl_getLocalHostName (JNIEnv *env, jobject this) {
106 char hostname[256];
107
108 if (gethostname(hostname, sizeof hostname) == -1) {
109 strcpy(hostname, "localhost");
110 }
111 return JNU_NewStringPlatform(env, hostname);
112 }
113
114 /*
115 * Find an internet address for a given hostname. Not this this
116 * code only works for addresses of type INET. The translation
117 * of %d.%d.%d.%d to an address (int) occurs in java now, so the
118 * String "host" shouldn't be a %d.%d.%d.%d string. The only
119 * exception should be when any of the %d are out of range and
120 * we fallback to a lookup.
121 *
122 * Class: java_net_Inet4AddressImpl
123 * Method: lookupAllHostAddr
124 * Signature: (Ljava/lang/String;)[[B
125 *
126 * This is almost shared code
127 */
128
129 JNIEXPORT jobjectArray JNICALL
130 Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
131 jstring host) {
132 const char *hostname;
133 struct hostent *hp;
134 unsigned int addr[4];
135
136 jobjectArray ret = NULL;
137
138 initInetAddressIDs(env);
139 JNU_CHECK_EXCEPTION_RETURN(env, NULL);
140
141 if (IS_NULL(host)) {
142 JNU_ThrowNullPointerException(env, "host argument");
143 return NULL;
144 }
145 hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE);
146 CHECK_NULL_RETURN(hostname, NULL);
147
148 /*
149 * The NT/2000 resolver tolerates a space in front of localhost. This
150 * is not consistent with other implementations of gethostbyname.
151 * In addition we must do a white space check on Solaris to avoid a
152 * bug whereby 0.0.0.0 is returned if any host name has a white space.
153 */
154 if (isspace(hostname[0])) {
155 JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", hostname);
156 goto cleanupAndReturn;
157 }
158
159 /*
160 * If the format is x.x.x.x then don't use gethostbyname as Windows
161 * is unable to handle octets which are out of range.
162 */
163 if (isDottedIPAddress(hostname, &addr[0])) {
164 unsigned int address;
165 jobject iaObj;
166
167 /*
168 * Are any of the octets out of range?
169 */
170 if (addr[0] > 255 || addr[1] > 255 || addr[2] > 255 || addr[3] > 255) {
171 JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", hostname);
172 goto cleanupAndReturn;
173 }
174
175 /*
176 * Return an byte array with the populated address.
177 */
178 address = (addr[3]<<24) & 0xff000000;
179 address |= (addr[2]<<16) & 0xff0000;
180 address |= (addr[1]<<8) & 0xff00;
181 address |= addr[0];
182
183 ret = (*env)->NewObjectArray(env, 1, ia_class, NULL);
184
185 if (IS_NULL(ret)) {
186 goto cleanupAndReturn;
187 }
188
189 iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
190 if (IS_NULL(iaObj)) {
191 ret = NULL;
192 goto cleanupAndReturn;
193 }
194 setInetAddress_addr(env, iaObj, ntohl(address));
195 (*env)->SetObjectArrayElement(env, ret, 0, iaObj);
196 JNU_ReleaseStringPlatformChars(env, host, hostname);
197 return ret;
198 }
199
200 /*
201 * Perform the lookup
202 */
203 if ((hp = gethostbyname((char*)hostname)) != NULL) {
204 struct in_addr **addrp = (struct in_addr **) hp->h_addr_list;
205 int len = sizeof(struct in_addr);
206 int i = 0;
207
208 while (*addrp != (struct in_addr *) 0) {
209 i++;
210 addrp++;
211 }
212
213 ret = (*env)->NewObjectArray(env, i, ia_class, NULL);
214
215 if (IS_NULL(ret)) {
216 goto cleanupAndReturn;
217 }
218
219 addrp = (struct in_addr **) hp->h_addr_list;
220 i = 0;
221 while (*addrp != (struct in_addr *) 0) {
222 jobject iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
223 if (IS_NULL(iaObj)) {
224 ret = NULL;
225 goto cleanupAndReturn;
226 }
227 setInetAddress_addr(env, iaObj, ntohl((*addrp)->s_addr));
228 setInetAddress_hostName(env, iaObj, host);
229 (*env)->SetObjectArrayElement(env, ret, i, iaObj);
230 addrp++;
231 i++;
232 }
233 } else if (WSAGetLastError() == WSATRY_AGAIN) {
234 NET_ThrowByNameWithLastError(env,
235 JNU_JAVANETPKG "UnknownHostException",
236 hostname);
237 } else {
238 JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", hostname);
239 }
240
241 cleanupAndReturn:
242 JNU_ReleaseStringPlatformChars(env, host, hostname);
243 return ret;
244 }
245
246 /*
247 * Class: java_net_Inet4AddressImpl
248 * Method: getHostByAddr
249 * Signature: (I)Ljava/lang/String;
250 */
251 JNIEXPORT jstring JNICALL
252 Java_java_net_Inet4AddressImpl_getHostByAddr(JNIEnv *env, jobject this,
253 jbyteArray addrArray) {
254 struct hostent *hp;
255 jbyte caddr[4];
256 jint addr;
257 (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
258 addr = ((caddr[0]<<24) & 0xff000000);
259 addr |= ((caddr[1] <<16) & 0xff0000);
260 addr |= ((caddr[2] <<8) & 0xff00);
261 addr |= (caddr[3] & 0xff);
262 addr = htonl(addr);
263
264 hp = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET);
265 if (hp == NULL) {
266 JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", 0);
267 return NULL;
268 }
269 if (hp->h_name == NULL) { /* Deal with bug in Windows XP */
270 JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", 0);
271 return NULL;
272 }
273 return JNU_NewStringPlatform(env, hp->h_name);
274 }
275
276
277 /**
278 * ping implementation.
279 * Send a ICMP_ECHO_REQUEST packet every second until either the timeout
280 * expires or a answer is received.
281 * Returns true is an ECHO_REPLY is received, otherwise, false.
282 */
283 static jboolean
284 ping4(JNIEnv *env, jint fd, struct sockaddr_in* him, jint timeout,
285 struct sockaddr_in* netif, jint ttl) {
286 jint size;
287 jint n, len, hlen1, icmplen;
288 char sendbuf[1500];
289 char recvbuf[1500];
290 struct icmp *icmp;
291 struct ip *ip;
292 WSAEVENT hEvent;
293 struct sockaddr sa_recv;
294 jint tmout2;
295 u_short pid, seq;
296 int read_rv = 0;
297
298 /* Initialize the sequence number to a suitable random number and
299 shift right one place to allow sufficient room for increamenting. */
300 seq = ((unsigned short)rand()) >> 1;
301
302 /* icmp_id is a 16 bit data type, therefore down cast the pid */
303 pid = (u_short) _getpid();
304 size = 60*1024;
305 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char *) &size, sizeof(size));
306 /**
307 * A TTL was specified, let's set the socket option.
308 */
309 if (ttl > 0) {
310 setsockopt(fd, IPPROTO_IP, IP_TTL, (const char *) &ttl, sizeof(ttl));
311 }
312
313 /**
314 * A network interface was specified, let's bind to it.
315 */
316 if (netif != NULL) {
317 if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in)) < 0) {
318 NET_ThrowNew(env, WSAGetLastError(), "Can't bind socket");
319 closesocket(fd);
320 return JNI_FALSE;
321 }
322 }
323
324 /**
325 * Let's make the socket non blocking
326 */
327 hEvent = WSACreateEvent();
328 WSAEventSelect(fd, hEvent, FD_READ|FD_CONNECT|FD_CLOSE);
329
330 /**
331 * send 1 ICMP REQUEST every second until either we get a valid reply
332 * or the timeout expired.
333 */
334 do {
335 /**
336 * construct the ICMP header
337 */
338 memset(sendbuf, 0, 1500);
339 icmp = (struct icmp *) sendbuf;
340 icmp->icmp_type = ICMP_ECHO;
341 icmp->icmp_code = 0;
342 icmp->icmp_id = htons(pid);
343 icmp->icmp_seq = htons(seq);
344 /**
345 * checksum has to be set to zero before we can calculate the
346 * real checksum!
347 */
348 icmp->icmp_cksum = 0;
349 icmp->icmp_cksum = in_cksum((u_short *)icmp, 64);
350 /**
351 * Ping!
352 */
353 n = sendto(fd, sendbuf, 64, 0, (struct sockaddr *)him,
354 sizeof(struct sockaddr));
355 if (n < 0 && WSAGetLastError() != WSAEWOULDBLOCK) {
356 NET_ThrowNew(env, WSAGetLastError(), "Can't send ICMP packet");
357 closesocket(fd);
358 WSACloseEvent(hEvent);
359 return JNI_FALSE;
360 }
361
362 /*
363 * wait for 1 second at most
364 */
365 tmout2 = timeout > 1000 ? 1000 : timeout;
366 do {
367 tmout2 = NET_Wait(env, fd, NET_WAIT_READ, tmout2);
368 if (tmout2 >= 0) {
369 len = sizeof(sa_recv);
370 n = recvfrom(fd, recvbuf, sizeof(recvbuf), 0, &sa_recv, &len);
371 ip = (struct ip*) recvbuf;
372 hlen1 = (ip->ip_hl) << 2;
373 icmp = (struct icmp *) (recvbuf + hlen1);
374 icmplen = n - hlen1;
375 /**
376 * Is that a proper ICMP reply?
377 */
378 if (icmplen >= 8 && icmp->icmp_type == ICMP_ECHOREPLY &&
379 (ntohs(icmp->icmp_seq) == seq) && (ntohs(icmp->icmp_id) == pid)) {
380 closesocket(fd);
381 WSACloseEvent(hEvent);
382 return JNI_TRUE;
383 }
384 }
385 } while (tmout2 > 0);
386 timeout -= 1000;
387 seq++;
388 } while (timeout > 0);
389 closesocket(fd);
390 WSACloseEvent(hEvent);
391 return JNI_FALSE;
392 }
393
394 /*
395 * Class: java_net_Inet4AddressImpl
396 * Method: isReachable0
397 * Signature: ([bI[bI)Z
398 */
399 JNIEXPORT jboolean JNICALL
400 Java_java_net_Inet4AddressImpl_isReachable0(JNIEnv *env, jobject this,
401 jbyteArray addrArray,
402 jint timeout,
403 jbyteArray ifArray,
404 jint ttl) {
405 jint addr;
406 jbyte caddr[4];
407 jint fd;
408 struct sockaddr_in him;
409 struct sockaddr_in* netif = NULL;
410 struct sockaddr_in inf;
411 int len = 0;
412 WSAEVENT hEvent;
413 int connect_rv = -1;
414 int sz;
415
416 /**
417 * Convert IP address from byte array to integer
418 */
419 sz = (*env)->GetArrayLength(env, addrArray);
420 if (sz != 4) {
421 return JNI_FALSE;
422 }
423 memset((char *) &him, 0, sizeof(him));
424 memset((char *) caddr, 0, sizeof(caddr));
425 (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
426 addr = ((caddr[0]<<24) & 0xff000000);
427 addr |= ((caddr[1] <<16) & 0xff0000);
428 addr |= ((caddr[2] <<8) & 0xff00);
429 addr |= (caddr[3] & 0xff);
430 addr = htonl(addr);
431 /**
432 * Socket address
433 */
434 him.sin_addr.s_addr = addr;
435 him.sin_family = AF_INET;
436 len = sizeof(him);
437
438 /**
439 * If a network interface was specified, let's convert its address
440 * as well.
441 */
442 if (!(IS_NULL(ifArray))) {
443 memset((char *) caddr, 0, sizeof(caddr));
444 (*env)->GetByteArrayRegion(env, ifArray, 0, 4, caddr);
445 addr = ((caddr[0]<<24) & 0xff000000);
446 addr |= ((caddr[1] <<16) & 0xff0000);
447 addr |= ((caddr[2] <<8) & 0xff00);
448 addr |= (caddr[3] & 0xff);
449 addr = htonl(addr);
450 inf.sin_addr.s_addr = addr;
451 inf.sin_family = AF_INET;
452 inf.sin_port = 0;
453 netif = &inf;
454 }
455
456 #if 0
457 /*
458 * Windows implementation of ICMP & RAW sockets is too unreliable for now.
459 * Therefore it's best not to try it at all and rely only on TCP
460 * We may revisit and enable this code in the future.
461 */
462
463 /*
464 * Let's try to create a RAW socket to send ICMP packets
465 * This usually requires "root" privileges, so it's likely to fail.
466 */
467 fd = NET_Socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
468 if (fd != -1) {
469 /*
470 * It didn't fail, so we can use ICMP_ECHO requests.
471 */
472 return ping4(env, fd, &him, timeout, netif, ttl);
473 }
474 #endif
475
476 /*
477 * Can't create a raw socket, so let's try a TCP socket
478 */
479 fd = NET_Socket(AF_INET, SOCK_STREAM, 0);
480 if (fd == SOCKET_ERROR) {
481 /* note: if you run out of fds, you may not be able to load
482 * the exception class, and get a NoClassDefFoundError
483 * instead.
484 */
485 NET_ThrowNew(env, WSAGetLastError(), "Can't create socket");
486 return JNI_FALSE;
487 }
488 if (ttl > 0) {
489 setsockopt(fd, IPPROTO_IP, IP_TTL, (const char *)&ttl, sizeof(ttl));
490 }
491 /*
492 * A network interface was specified, so let's bind to it.
493 */
494 if (netif != NULL) {
495 if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in)) < 0) {
496 NET_ThrowNew(env, WSAGetLastError(), "Can't bind socket");
497 closesocket(fd);
498 return JNI_FALSE;
499 }
500 }
501
502 /*
503 * Make the socket non blocking so we can use select/poll.
504 */
505 hEvent = WSACreateEvent();
506 WSAEventSelect(fd, hEvent, FD_READ|FD_CONNECT|FD_CLOSE);
507
508 /* no need to use NET_Connect as non-blocking */
509 him.sin_port = htons(7); /* Echo */
510 connect_rv = connect(fd, (struct sockaddr *)&him, len);
511
512 /**
513 * connection established or refused immediately, either way it means
514 * we were able to reach the host!
515 */
516 if (connect_rv == 0 || WSAGetLastError() == WSAECONNREFUSED) {
517 WSACloseEvent(hEvent);
518 closesocket(fd);
519 return JNI_TRUE;
520 } else {
521 int optlen;
522
523 switch (WSAGetLastError()) {
524 case WSAEHOSTUNREACH: /* Host Unreachable */
525 case WSAENETUNREACH: /* Network Unreachable */
526 case WSAENETDOWN: /* Network is down */
527 case WSAEPFNOSUPPORT: /* Protocol Family unsupported */
528 WSACloseEvent(hEvent);
529 closesocket(fd);
530 return JNI_FALSE;
531 }
532
533 if (WSAGetLastError() != WSAEWOULDBLOCK) {
534 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
535 "connect failed");
536 WSACloseEvent(hEvent);
537 closesocket(fd);
538 return JNI_FALSE;
539 }
540
541 timeout = NET_Wait(env, fd, NET_WAIT_CONNECT, timeout);
542
543 /* has connection been established */
544
545 if (timeout >= 0) {
546 optlen = sizeof(connect_rv);
547 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv,
548 &optlen) <0) {
549 connect_rv = WSAGetLastError();
550 }
551
552 if (connect_rv == 0 || connect_rv == WSAECONNREFUSED) {
553 WSACloseEvent(hEvent);
554 closesocket(fd);
555 return JNI_TRUE;
556 }
557 }
558 }
559 WSACloseEvent(hEvent);
560 closesocket(fd);
561 return JNI_FALSE;
562 }
--- EOF ---