1 /*
2 * Copyright (c) 2001, 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 <sys/types.h>
27 #include <sys/socket.h>
28 #include <string.h>
29 #include <netinet/in.h>
30 #include <netinet/tcp.h>
31
32 #include "jni.h"
33 #include "jni_util.h"
34 #include "jvm.h"
35 #include "jlong.h"
36 #include "sun_nio_ch_Net.h"
37 #include "net_util.h"
38 #include "net_util_md.h"
39 #include "nio_util.h"
40 #include "nio.h"
41
42 #include "JNIHelp.h"
43
44 #define NATIVE_METHOD(className, functionName, signature) \
45 { #functionName, signature, (void*)(Java_sun_nio_ch_ ## className ## _ ## functionName) }
46
47 #ifdef _ALLBSD_SOURCE
48
49 #ifndef IP_BLOCK_SOURCE
50
51 #define IP_ADD_SOURCE_MEMBERSHIP 70 /* join a source-specific group */
52 #define IP_DROP_SOURCE_MEMBERSHIP 71 /* drop a single source */
53 #define IP_BLOCK_SOURCE 72 /* block a source */
54 #define IP_UNBLOCK_SOURCE 73 /* unblock a source */
55
56 #endif /* IP_BLOCK_SOURCE */
57
58 #ifndef MCAST_BLOCK_SOURCE
59
60 #define MCAST_JOIN_SOURCE_GROUP 82 /* join a source-specific group */
61 #define MCAST_LEAVE_SOURCE_GROUP 83 /* leave a single source */
62 #define MCAST_BLOCK_SOURCE 84 /* block a source */
63 #define MCAST_UNBLOCK_SOURCE 85 /* unblock a source */
64
65 #endif /* MCAST_BLOCK_SOURCE */
66
67 #ifndef IPV6_ADD_MEMBERSHIP
68
69 #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
70 #define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
71
72 #endif /* IPV6_ADD_MEMBERSHIP */
73
74 struct my_ip_mreq_source {
75 struct in_addr imr_multiaddr;
76 struct in_addr imr_interface;
77 struct in_addr imr_sourceaddr;
78 };
79
80 struct my_group_source_req {
81 uint32_t gsr_interface; /* interface index */
82 struct sockaddr_storage gsr_group; /* group address */
83 struct sockaddr_storage gsr_source; /* source address */
84 };
85
86 #else /* _ALLBSD_SOURCE */
87
88 #define my_ip_mreq_source ip_mreq_source
89 #define my_group_source_req group_source_req
90
91 #endif
92
93
94 #define COPY_INET6_ADDRESS(env, source, target) \
95 (*env)->GetByteArrayRegion(env, source, 0, 16, target)
96
97 /*
98 * Copy IPv6 group, interface index, and IPv6 source address
99 * into group_source_req structure.
100 */
101 #ifdef AF_INET6
initGroupSourceReq(JNIEnv * env,jbyteArray group,jint index,jbyteArray source,struct my_group_source_req * req)102 static void initGroupSourceReq(JNIEnv* env, jbyteArray group, jint index,
103 jbyteArray source, struct my_group_source_req* req)
104 {
105 struct sockaddr_in6* sin6;
106
107 req->gsr_interface = (uint32_t)index;
108
109 sin6 = (struct sockaddr_in6*)&(req->gsr_group);
110 sin6->sin6_family = AF_INET6;
111 COPY_INET6_ADDRESS(env, group, (jbyte*)&(sin6->sin6_addr));
112
113 sin6 = (struct sockaddr_in6*)&(req->gsr_source);
114 sin6->sin6_family = AF_INET6;
115 COPY_INET6_ADDRESS(env, source, (jbyte*)&(sin6->sin6_addr));
116 }
117 #endif
118
119 JNIEXPORT jboolean JNICALL
Java_sun_nio_ch_Net_isIPv6Available0(JNIEnv * env,jclass cl)120 Java_sun_nio_ch_Net_isIPv6Available0(JNIEnv* env, jclass cl)
121 {
122 return (ipv6_available()) ? JNI_TRUE : JNI_FALSE;
123 }
124
125 JNIEXPORT jint JNICALL
Java_sun_nio_ch_Net_isExclusiveBindAvailable(JNIEnv * env,jclass clazz)126 Java_sun_nio_ch_Net_isExclusiveBindAvailable(JNIEnv *env, jclass clazz) {
127 return -1;
128 }
129
130 JNIEXPORT jboolean JNICALL
Java_sun_nio_ch_Net_canIPv6SocketJoinIPv4Group0(JNIEnv * env,jclass cl)131 Java_sun_nio_ch_Net_canIPv6SocketJoinIPv4Group0(JNIEnv* env, jclass cl)
132 {
133 #ifdef MACOSX
134 /* for now IPv6 sockets cannot join IPv4 multicast groups */
135 return JNI_FALSE;
136 #else
137 return JNI_TRUE;
138 #endif
139 }
140
141 JNIEXPORT jboolean JNICALL
Java_sun_nio_ch_Net_canJoin6WithIPv4Group0(JNIEnv * env,jclass cl)142 Java_sun_nio_ch_Net_canJoin6WithIPv4Group0(JNIEnv* env, jclass cl)
143 {
144 #ifdef __solaris__
145 return JNI_TRUE;
146 #else
147 return JNI_FALSE;
148 #endif
149 }
150
151 JNIEXPORT int JNICALL
Java_sun_nio_ch_Net_socket0(JNIEnv * env,jclass cl,jboolean preferIPv6,jboolean stream,jboolean reuse)152 Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6,
153 jboolean stream, jboolean reuse)
154 {
155 int fd;
156 int type = (stream ? SOCK_STREAM : SOCK_DGRAM);
157 #ifdef AF_INET6
158 int domain = (ipv6_available() && preferIPv6) ? AF_INET6 : AF_INET;
159 #else
160 int domain = AF_INET;
161 #endif
162
163 fd = socket(domain, type, 0);
164 tagSocket(env, fd);
165 if (fd < 0) {
166 return handleSocketError(env, errno);
167 }
168
169 #ifdef AF_INET6
170 /* Disable IPV6_V6ONLY to ensure dual-socket support */
171 if (domain == AF_INET6) {
172 int arg = 0;
173 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg,
174 sizeof(int)) < 0) {
175 JNU_ThrowByNameWithLastError(env,
176 JNU_JAVANETPKG "SocketException",
177 "sun.nio.ch.Net.setIntOption");
178 untagSocket(env, fd);
179 close(fd);
180 return -1;
181 }
182 }
183 #endif
184
185 if (reuse) {
186 int arg = 1;
187 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg,
188 sizeof(arg)) < 0) {
189 JNU_ThrowByNameWithLastError(env,
190 JNU_JAVANETPKG "SocketException",
191 "sun.nio.ch.Net.setIntOption");
192 untagSocket(env, fd);
193 close(fd);
194 return -1;
195 }
196 }
197 #if defined(__linux__) && defined(AF_INET6)
198 /* By default, Linux uses the route default */
199 if (domain == AF_INET6 && type == SOCK_DGRAM) {
200 int arg = 1;
201 if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &arg,
202 sizeof(arg)) < 0) {
203 JNU_ThrowByNameWithLastError(env,
204 JNU_JAVANETPKG "SocketException",
205 "sun.nio.ch.Net.setIntOption");
206 untagSocket(env, fd);
207 close(fd);
208 return -1;
209 }
210 }
211 #endif
212 return fd;
213 }
214
215 JNIEXPORT void JNICALL
Java_sun_nio_ch_Net_bind0(JNIEnv * env,jclass clazz,jobject fdo,jboolean preferIPv6,jboolean useExclBind,jobject iao,int port)216 Java_sun_nio_ch_Net_bind0(JNIEnv *env, jclass clazz, jobject fdo, jboolean preferIPv6,
217 jboolean useExclBind, jobject iao, int port)
218 {
219 SOCKADDR sa;
220 int sa_len = SOCKADDR_LEN;
221 int rv = 0;
222
223 if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, preferIPv6) != 0) {
224 return;
225 }
226
227 rv = NET_Bind(fdval(env, fdo), (struct sockaddr *)&sa, sa_len);
228 if (rv != 0) {
229 handleSocketError(env, errno);
230 }
231 }
232
233 JNIEXPORT void JNICALL
Java_sun_nio_ch_Net_listen(JNIEnv * env,jclass cl,jobject fdo,jint backlog)234 Java_sun_nio_ch_Net_listen(JNIEnv *env, jclass cl, jobject fdo, jint backlog)
235 {
236 if (listen(fdval(env, fdo), backlog) < 0)
237 handleSocketError(env, errno);
238 }
239
240 JNIEXPORT jint JNICALL
Java_sun_nio_ch_Net_connect0(JNIEnv * env,jclass clazz,jboolean preferIPv6,jobject fdo,jobject iao,jint port)241 Java_sun_nio_ch_Net_connect0(JNIEnv *env, jclass clazz, jboolean preferIPv6,
242 jobject fdo, jobject iao, jint port)
243 {
244 SOCKADDR sa;
245 int sa_len = SOCKADDR_LEN;
246 int rv;
247
248 if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *) &sa,
249 &sa_len, preferIPv6) != 0)
250 {
251 return IOS_THROWN;
252 }
253
254 rv = connect(fdval(env, fdo), (struct sockaddr *)&sa, sa_len);
255 if (rv != 0) {
256 if (errno == EINPROGRESS) {
257 return IOS_UNAVAILABLE;
258 } else if (errno == EINTR) {
259 return IOS_INTERRUPTED;
260 }
261 return handleSocketErrorWithDefault(env, errno, JNU_JAVANETPKG "ConnectException");
262 }
263 return 1;
264 }
265
266 JNIEXPORT jint JNICALL
Java_sun_nio_ch_Net_localPort(JNIEnv * env,jclass clazz,jobject fdo)267 Java_sun_nio_ch_Net_localPort(JNIEnv *env, jclass clazz, jobject fdo)
268 {
269 SOCKADDR sa;
270 socklen_t sa_len = SOCKADDR_LEN;
271 if (getsockname(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) {
272 #ifdef _ALLBSD_SOURCE
273 /*
274 * XXXBSD:
275 * ECONNRESET is specific to the BSDs. We can not return an error,
276 * as the calling Java code with raise a java.lang.Error given the expectation
277 * that getsockname() will never fail. According to the Single UNIX Specification,
278 * it shouldn't fail. As such, we just fill in generic Linux-compatible values.
279 */
280 if (errno == ECONNRESET) {
281 struct sockaddr_in *sin;
282 sin = (struct sockaddr_in *) &sa;
283 bzero(sin, sizeof(*sin));
284 sin->sin_len = sizeof(struct sockaddr_in);
285 sin->sin_family = AF_INET;
286 sin->sin_port = htonl(0);
287 sin->sin_addr.s_addr = INADDR_ANY;
288 } else {
289 handleSocketError(env, errno);
290 return -1;
291 }
292 #else /* _ALLBSD_SOURCE */
293 handleSocketError(env, errno);
294 return -1;
295 #endif /* _ALLBSD_SOURCE */
296 }
297 return NET_GetPortFromSockaddr((struct sockaddr *)&sa);
298 }
299
300 JNIEXPORT jobject JNICALL
Java_sun_nio_ch_Net_localInetAddress(JNIEnv * env,jclass clazz,jobject fdo)301 Java_sun_nio_ch_Net_localInetAddress(JNIEnv *env, jclass clazz, jobject fdo)
302 {
303 SOCKADDR sa;
304 socklen_t sa_len = SOCKADDR_LEN;
305 int port;
306 if (getsockname(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) {
307 #ifdef _ALLBSD_SOURCE
308 /*
309 * XXXBSD:
310 * ECONNRESET is specific to the BSDs. We can not return an error,
311 * as the calling Java code with raise a java.lang.Error with the expectation
312 * that getsockname() will never fail. According to the Single UNIX Specification,
313 * it shouldn't fail. As such, we just fill in generic Linux-compatible values.
314 */
315 if (errno == ECONNRESET) {
316 struct sockaddr_in *sin;
317 sin = (struct sockaddr_in *) &sa;
318 bzero(sin, sizeof(*sin));
319 sin->sin_len = sizeof(struct sockaddr_in);
320 sin->sin_family = AF_INET;
321 sin->sin_port = htonl(0);
322 sin->sin_addr.s_addr = INADDR_ANY;
323 } else {
324 handleSocketError(env, errno);
325 return NULL;
326 }
327 #else /* _ALLBSD_SOURCE */
328 handleSocketError(env, errno);
329 return NULL;
330 #endif /* _ALLBSD_SOURCE */
331 }
332 return NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port);
333 }
334
335 JNIEXPORT jint JNICALL
Java_sun_nio_ch_Net_getIntOption0(JNIEnv * env,jclass clazz,jobject fdo,jboolean mayNeedConversion,jint level,jint opt)336 Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, jobject fdo,
337 jboolean mayNeedConversion, jint level, jint opt)
338 {
339 int result;
340 struct linger linger;
341 u_char carg;
342 void *arg;
343 socklen_t arglen;
344 int n;
345
346 /* Option value is an int except for a few specific cases */
347
348 arg = (void *)&result;
349 arglen = sizeof(result);
350
351 if (level == IPPROTO_IP &&
352 (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) {
353 arg = (void*)&carg;
354 arglen = sizeof(carg);
355 }
356
357 if (level == SOL_SOCKET && opt == SO_LINGER) {
358 arg = (void *)&linger;
359 arglen = sizeof(linger);
360 }
361
362 if (mayNeedConversion) {
363 n = NET_GetSockOpt(fdval(env, fdo), level, opt, arg, (int*)&arglen);
364 } else {
365 n = getsockopt(fdval(env, fdo), level, opt, arg, &arglen);
366 }
367 if (n < 0) {
368 JNU_ThrowByNameWithLastError(env,
369 JNU_JAVANETPKG "SocketException",
370 "sun.nio.ch.Net.getIntOption");
371 return -1;
372 }
373
374 if (level == IPPROTO_IP &&
375 (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP))
376 {
377 return (jint)carg;
378 }
379
380 if (level == SOL_SOCKET && opt == SO_LINGER)
381 return linger.l_onoff ? (jint)linger.l_linger : (jint)-1;
382
383 return (jint)result;
384 }
385
386 JNIEXPORT void JNICALL
Java_sun_nio_ch_Net_setIntOption0(JNIEnv * env,jclass clazz,jobject fdo,jboolean mayNeedConversion,jint level,jint opt,jint arg)387 Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, jobject fdo,
388 jboolean mayNeedConversion, jint level, jint opt, jint arg)
389 {
390 int result;
391 struct linger linger;
392 u_char carg;
393 void *parg;
394 socklen_t arglen;
395 int n;
396
397 /* Option value is an int except for a few specific cases */
398
399 parg = (void*)&arg;
400 arglen = sizeof(arg);
401
402 if (level == IPPROTO_IP &&
403 (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) {
404 parg = (void*)&carg;
405 arglen = sizeof(carg);
406 carg = (u_char)arg;
407 }
408
409 if (level == SOL_SOCKET && opt == SO_LINGER) {
410 parg = (void *)&linger;
411 arglen = sizeof(linger);
412 if (arg >= 0) {
413 linger.l_onoff = 1;
414 linger.l_linger = arg;
415 } else {
416 linger.l_onoff = 0;
417 linger.l_linger = 0;
418 }
419 }
420
421 if (mayNeedConversion) {
422 n = NET_SetSockOpt(fdval(env, fdo), level, opt, parg, arglen);
423 } else {
424 n = setsockopt(fdval(env, fdo), level, opt, parg, arglen);
425 }
426 if (n < 0) {
427 JNU_ThrowByNameWithLastError(env,
428 JNU_JAVANETPKG "SocketException",
429 "sun.nio.ch.Net.setIntOption");
430 }
431 }
432
433 JNIEXPORT jint JNICALL
Java_sun_nio_ch_Net_joinOrDrop4(JNIEnv * env,jobject this,jboolean join,jobject fdo,jint group,jint interf,jint source)434 Java_sun_nio_ch_Net_joinOrDrop4(JNIEnv *env, jobject this, jboolean join, jobject fdo,
435 jint group, jint interf, jint source)
436 {
437 struct ip_mreq mreq;
438 struct my_ip_mreq_source mreq_source;
439 int opt, n, optlen;
440 void* optval;
441
442 if (source == 0) {
443 mreq.imr_multiaddr.s_addr = htonl(group);
444 mreq.imr_interface.s_addr = htonl(interf);
445 opt = (join) ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
446 optval = (void*)&mreq;
447 optlen = sizeof(mreq);
448 } else {
449 #ifdef MACOSX
450 /* no IPv4 include-mode filtering for now */
451 return IOS_UNAVAILABLE;
452 #else
453 // Begin Android changed.
454 #if defined(__GLIBC__)
455 mreq_source.imr_multiaddr.s_addr = htonl(group);
456 mreq_source.imr_sourceaddr.s_addr = htonl(source);
457 mreq_source.imr_interface.s_addr = htonl(interf);
458 #else
459 mreq_source.imr_multiaddr = htonl(group);
460 mreq_source.imr_sourceaddr = htonl(source);
461 mreq_source.imr_interface = htonl(interf);
462 #endif
463 // End Android changed.
464 opt = (join) ? IP_ADD_SOURCE_MEMBERSHIP : IP_DROP_SOURCE_MEMBERSHIP;
465 optval = (void*)&mreq_source;
466 optlen = sizeof(mreq_source);
467 #endif
468 }
469
470 n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, optval, optlen);
471 if (n < 0) {
472 if (join && (errno == ENOPROTOOPT))
473 return IOS_UNAVAILABLE;
474 handleSocketError(env, errno);
475 }
476 return 0;
477 }
478
479 JNIEXPORT jint JNICALL
Java_sun_nio_ch_Net_blockOrUnblock4(JNIEnv * env,jobject this,jboolean block,jobject fdo,jint group,jint interf,jint source)480 Java_sun_nio_ch_Net_blockOrUnblock4(JNIEnv *env, jobject this, jboolean block, jobject fdo,
481 jint group, jint interf, jint source)
482 {
483 #ifdef MACOSX
484 /* no IPv4 exclude-mode filtering for now */
485 return IOS_UNAVAILABLE;
486 #else
487 struct my_ip_mreq_source mreq_source;
488 int n;
489 int opt = (block) ? IP_BLOCK_SOURCE : IP_UNBLOCK_SOURCE;
490
491 // Begin Android changed.
492 #if defined(__GLIBC__)
493 mreq_source.imr_multiaddr.s_addr = htonl(group);
494 mreq_source.imr_sourceaddr.s_addr = htonl(source);
495 mreq_source.imr_interface.s_addr = htonl(interf);
496 #else
497 mreq_source.imr_multiaddr = htonl(group);
498 mreq_source.imr_sourceaddr = htonl(source);
499 mreq_source.imr_interface = htonl(interf);
500 #endif
501
502 n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt,
503 (void*)&mreq_source, sizeof(mreq_source));
504 if (n < 0) {
505 if (block && (errno == ENOPROTOOPT))
506 return IOS_UNAVAILABLE;
507 handleSocketError(env, errno);
508 }
509 return 0;
510 #endif
511 }
512
513 JNIEXPORT jint JNICALL
Java_sun_nio_ch_Net_joinOrDrop6(JNIEnv * env,jobject this,jboolean join,jobject fdo,jbyteArray group,jint index,jbyteArray source)514 Java_sun_nio_ch_Net_joinOrDrop6(JNIEnv *env, jobject this, jboolean join, jobject fdo,
515 jbyteArray group, jint index, jbyteArray source)
516 {
517 #ifdef AF_INET6
518 struct ipv6_mreq mreq6;
519 struct my_group_source_req req;
520 int opt, n, optlen;
521 void* optval;
522
523 if (source == NULL) {
524 COPY_INET6_ADDRESS(env, group, (jbyte*)&(mreq6.ipv6mr_multiaddr));
525 mreq6.ipv6mr_interface = (int)index;
526 opt = (join) ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP;
527 optval = (void*)&mreq6;
528 optlen = sizeof(mreq6);
529 } else {
530 #ifdef MACOSX
531 /* no IPv6 include-mode filtering for now */
532 return IOS_UNAVAILABLE;
533 #else
534 initGroupSourceReq(env, group, index, source, &req);
535 opt = (join) ? MCAST_JOIN_SOURCE_GROUP : MCAST_LEAVE_SOURCE_GROUP;
536 optval = (void*)&req;
537 optlen = sizeof(req);
538 #endif
539 }
540
541 n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, optval, optlen);
542 if (n < 0) {
543 if (join && (errno == ENOPROTOOPT))
544 return IOS_UNAVAILABLE;
545 handleSocketError(env, errno);
546 }
547 return 0;
548 #else
549 JNU_ThrowInternalError(env, "Should not get here");
550 return IOS_THROWN;
551 #endif /* AF_INET6 */
552 }
553
554 JNIEXPORT jint JNICALL
Java_sun_nio_ch_Net_blockOrUnblock6(JNIEnv * env,jobject this,jboolean block,jobject fdo,jbyteArray group,jint index,jbyteArray source)555 Java_sun_nio_ch_Net_blockOrUnblock6(JNIEnv *env, jobject this, jboolean block, jobject fdo,
556 jbyteArray group, jint index, jbyteArray source)
557 {
558 #ifdef AF_INET6
559 #ifdef MACOSX
560 /* no IPv6 exclude-mode filtering for now */
561 return IOS_UNAVAILABLE;
562 #else
563 struct my_group_source_req req;
564 int n;
565 int opt = (block) ? MCAST_BLOCK_SOURCE : MCAST_UNBLOCK_SOURCE;
566
567 initGroupSourceReq(env, group, index, source, &req);
568
569 n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt,
570 (void*)&req, sizeof(req));
571 if (n < 0) {
572 if (block && (errno == ENOPROTOOPT))
573 return IOS_UNAVAILABLE;
574 handleSocketError(env, errno);
575 }
576 return 0;
577 #endif
578 #else
579 JNU_ThrowInternalError(env, "Should not get here");
580 return IOS_THROWN;
581 #endif
582 }
583
584 JNIEXPORT void JNICALL
Java_sun_nio_ch_Net_setInterface4(JNIEnv * env,jobject this,jobject fdo,jint interf)585 Java_sun_nio_ch_Net_setInterface4(JNIEnv* env, jobject this, jobject fdo, jint interf)
586 {
587 struct in_addr in;
588 socklen_t arglen = sizeof(struct in_addr);
589 int n;
590
591 in.s_addr = htonl(interf);
592
593 n = setsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF,
594 (void*)&(in.s_addr), arglen);
595 if (n < 0) {
596 handleSocketError(env, errno);
597 }
598 }
599
600 JNIEXPORT jint JNICALL
Java_sun_nio_ch_Net_getInterface4(JNIEnv * env,jobject this,jobject fdo)601 Java_sun_nio_ch_Net_getInterface4(JNIEnv* env, jobject this, jobject fdo)
602 {
603 struct in_addr in;
604 socklen_t arglen = sizeof(struct in_addr);
605 int n;
606
607 n = getsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, (void*)&in, &arglen);
608 if (n < 0) {
609 handleSocketError(env, errno);
610 return -1;
611 }
612 return ntohl(in.s_addr);
613 }
614
615 JNIEXPORT void JNICALL
Java_sun_nio_ch_Net_setInterface6(JNIEnv * env,jobject this,jobject fdo,jint index)616 Java_sun_nio_ch_Net_setInterface6(JNIEnv* env, jobject this, jobject fdo, jint index)
617 {
618 int value = (jint)index;
619 socklen_t arglen = sizeof(value);
620 int n;
621
622 n = setsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF,
623 (void*)&(index), arglen);
624 if (n < 0) {
625 handleSocketError(env, errno);
626 }
627 }
628
629 JNIEXPORT jint JNICALL
Java_sun_nio_ch_Net_getInterface6(JNIEnv * env,jobject this,jobject fdo)630 Java_sun_nio_ch_Net_getInterface6(JNIEnv* env, jobject this, jobject fdo)
631 {
632 int index;
633 socklen_t arglen = sizeof(index);
634 int n;
635
636 n = getsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, (void*)&index, &arglen);
637 if (n < 0) {
638 handleSocketError(env, errno);
639 return -1;
640 }
641 return (jint)index;
642 }
643
644 JNIEXPORT void JNICALL
Java_sun_nio_ch_Net_shutdown(JNIEnv * env,jclass cl,jobject fdo,jint jhow)645 Java_sun_nio_ch_Net_shutdown(JNIEnv *env, jclass cl, jobject fdo, jint jhow)
646 {
647 int how = (jhow == sun_nio_ch_Net_SHUT_RD) ? SHUT_RD :
648 (jhow == sun_nio_ch_Net_SHUT_WR) ? SHUT_WR : SHUT_RDWR;
649 if ((shutdown(fdval(env, fdo), how) < 0) && (errno != ENOTCONN))
650 handleSocketError(env, errno);
651 }
652
653 /* Declared in nio_util.h */
654
655 jint
handleSocketErrorWithDefault(JNIEnv * env,jint errorValue,const char * defaultException)656 handleSocketErrorWithDefault(JNIEnv *env, jint errorValue, const char *defaultException)
657 {
658 const char *xn;
659 switch (errorValue) {
660 case EINPROGRESS: /* Non-blocking connect */
661 return 0;
662 #ifdef EPROTO
663 case EPROTO:
664 xn = JNU_JAVANETPKG "ProtocolException";
665 break;
666 #endif
667 case ECONNREFUSED:
668 xn = JNU_JAVANETPKG "ConnectException";
669 break;
670 case ETIMEDOUT:
671 xn = JNU_JAVANETPKG "ConnectException";
672 break;
673 case EHOSTUNREACH:
674 xn = JNU_JAVANETPKG "NoRouteToHostException";
675 break;
676 case EADDRINUSE: /* Fall through */
677 case EADDRNOTAVAIL:
678 xn = JNU_JAVANETPKG "BindException";
679 break;
680 default:
681 xn = defaultException;
682 break;
683 }
684 errno = errorValue;
685 JNU_ThrowByNameWithLastError(env, xn, "NioSocketError");
686 return IOS_THROWN;
687 }
688
689 /* Declared in nio_util.h */
690
691 jint
handleSocketError(JNIEnv * env,jint errorValue)692 handleSocketError(JNIEnv *env, jint errorValue) {
693 return handleSocketErrorWithDefault(env, errorValue,
694 JNU_JAVANETPKG "SocketException");
695 }
696
697
698 static JNINativeMethod gMethods[] = {
699 NATIVE_METHOD(Net, isIPv6Available0, "()Z"),
700 NATIVE_METHOD(Net, isExclusiveBindAvailable, "()I"),
701 NATIVE_METHOD(Net, canIPv6SocketJoinIPv4Group0, "()Z"),
702 NATIVE_METHOD(Net, canJoin6WithIPv4Group0, "()Z"),
703 NATIVE_METHOD(Net, socket0, "(ZZZ)I"),
704 NATIVE_METHOD(Net, bind0, "(Ljava/io/FileDescriptor;ZZLjava/net/InetAddress;I)V"),
705 NATIVE_METHOD(Net, listen, "(Ljava/io/FileDescriptor;I)V"),
706 NATIVE_METHOD(Net, connect0, "(ZLjava/io/FileDescriptor;Ljava/net/InetAddress;I)I"),
707 NATIVE_METHOD(Net, shutdown, "(Ljava/io/FileDescriptor;I)V"),
708 NATIVE_METHOD(Net, localPort, "(Ljava/io/FileDescriptor;)I"),
709 NATIVE_METHOD(Net, localInetAddress, "(Ljava/io/FileDescriptor;)Ljava/net/InetAddress;"),
710 NATIVE_METHOD(Net, getIntOption0, "(Ljava/io/FileDescriptor;ZII)I"),
711 NATIVE_METHOD(Net, setIntOption0, "(Ljava/io/FileDescriptor;ZIII)V"),
712 NATIVE_METHOD(Net, joinOrDrop4, "(ZLjava/io/FileDescriptor;III)I"),
713 NATIVE_METHOD(Net, blockOrUnblock4, "(ZLjava/io/FileDescriptor;III)I"),
714 NATIVE_METHOD(Net, joinOrDrop6, "(ZLjava/io/FileDescriptor;[BI[B)I"),
715 NATIVE_METHOD(Net, blockOrUnblock6, "(ZLjava/io/FileDescriptor;[BI[B)I"),
716 NATIVE_METHOD(Net, setInterface4, "(Ljava/io/FileDescriptor;I)V"),
717 NATIVE_METHOD(Net, getInterface4, "(Ljava/io/FileDescriptor;)I"),
718 NATIVE_METHOD(Net, setInterface6, "(Ljava/io/FileDescriptor;I)V"),
719 NATIVE_METHOD(Net, getInterface6, "(Ljava/io/FileDescriptor;)I"),
720 };
721
register_sun_nio_ch_Net(JNIEnv * env)722 void register_sun_nio_ch_Net(JNIEnv* env) {
723 jniRegisterNativeMethods(env, "sun/nio/ch/Net", gMethods, NELEM(gMethods));
724 }
725