35 #include "jlong.h" |
35 #include "jlong.h" |
36 #include "sun_nio_ch_Net.h" |
36 #include "sun_nio_ch_Net.h" |
37 #include "net_util.h" |
37 #include "net_util.h" |
38 #include "net_util_md.h" |
38 #include "net_util_md.h" |
39 #include "nio_util.h" |
39 #include "nio_util.h" |
40 #include "java_net_SocketOptions.h" |
|
41 #include "nio.h" |
40 #include "nio.h" |
42 |
41 |
|
42 /** |
|
43 * Definitions for source-specific multicast to allow for building |
|
44 * with older header files. |
|
45 */ |
|
46 |
|
47 #ifdef __solaris__ |
|
48 |
|
49 #ifndef IP_BLOCK_SOURCE |
|
50 |
|
51 #define IP_BLOCK_SOURCE 0x15 |
|
52 #define IP_UNBLOCK_SOURCE 0x16 |
|
53 #define IP_ADD_SOURCE_MEMBERSHIP 0x17 |
|
54 #define IP_DROP_SOURCE_MEMBERSHIP 0x18 |
|
55 |
|
56 #define MCAST_BLOCK_SOURCE 0x2b |
|
57 #define MCAST_UNBLOCK_SOURCE 0x2c |
|
58 #define MCAST_JOIN_SOURCE_GROUP 0x2d |
|
59 #define MCAST_LEAVE_SOURCE_GROUP 0x2e |
|
60 |
|
61 #endif /* IP_BLOCK_SOURCE */ |
|
62 |
|
63 struct my_ip_mreq_source { |
|
64 struct in_addr imr_multiaddr; |
|
65 struct in_addr imr_sourceaddr; |
|
66 struct in_addr imr_interface; |
|
67 }; |
|
68 |
|
69 /* |
|
70 * Use #pragma pack() construct to force 32-bit alignment on amd64. |
|
71 */ |
|
72 #if defined(amd64) |
|
73 #pragma pack(4) |
|
74 #endif |
|
75 |
|
76 struct my_group_source_req { |
|
77 uint32_t gsr_interface; /* interface index */ |
|
78 struct sockaddr_storage gsr_group; /* group address */ |
|
79 struct sockaddr_storage gsr_source; /* source address */ |
|
80 }; |
|
81 |
|
82 #if defined(amd64) |
|
83 #pragma pack() |
|
84 #endif |
|
85 |
|
86 #endif /* __solaris__ */ |
|
87 |
|
88 |
43 #ifdef __linux__ |
89 #ifdef __linux__ |
44 #include <sys/utsname.h> |
90 |
45 |
91 #ifndef IP_BLOCK_SOURCE |
46 #define IPV6_MULTICAST_IF 17 |
92 |
47 #ifndef SO_BSDCOMPAT |
93 #define IP_BLOCK_SOURCE 38 |
48 #define SO_BSDCOMPAT 14 |
94 #define IP_UNBLOCK_SOURCE 37 |
49 #endif |
95 #define IP_ADD_SOURCE_MEMBERSHIP 39 |
50 #endif |
96 #define IP_DROP_SOURCE_MEMBERSHIP 40 |
|
97 |
|
98 #define MCAST_BLOCK_SOURCE 43 |
|
99 #define MCAST_UNBLOCK_SOURCE 44 |
|
100 #define MCAST_JOIN_SOURCE_GROUP 42 |
|
101 #define MCAST_LEAVE_SOURCE_GROUP 45 |
|
102 |
|
103 #endif /* IP_BLOCK_SOURCE */ |
|
104 |
|
105 struct my_ip_mreq_source { |
|
106 struct in_addr imr_multiaddr; |
|
107 struct in_addr imr_interface; |
|
108 struct in_addr imr_sourceaddr; |
|
109 }; |
|
110 |
|
111 struct my_group_source_req { |
|
112 uint32_t gsr_interface; /* interface index */ |
|
113 struct sockaddr_storage gsr_group; /* group address */ |
|
114 struct sockaddr_storage gsr_source; /* source address */ |
|
115 }; |
|
116 |
|
117 #endif /* __linux__ */ |
|
118 |
|
119 |
|
120 #define COPY_INET6_ADDRESS(env, source, target) \ |
|
121 (*env)->GetByteArrayRegion(env, source, 0, 16, target) |
|
122 |
|
123 /* |
|
124 * Copy IPv6 group, interface index, and IPv6 source address |
|
125 * into group_source_req structure. |
|
126 */ |
|
127 static void initGroupSourceReq(JNIEnv* env, jbyteArray group, jint index, |
|
128 jbyteArray source, struct my_group_source_req* req) |
|
129 { |
|
130 struct sockaddr_in6* sin6; |
|
131 |
|
132 req->gsr_interface = (uint32_t)index; |
|
133 |
|
134 sin6 = (struct sockaddr_in6*)&(req->gsr_group); |
|
135 sin6->sin6_family = AF_INET6; |
|
136 COPY_INET6_ADDRESS(env, group, (jbyte*)&(sin6->sin6_addr)); |
|
137 |
|
138 sin6 = (struct sockaddr_in6*)&(req->gsr_source); |
|
139 sin6->sin6_family = AF_INET6; |
|
140 COPY_INET6_ADDRESS(env, source, (jbyte*)&(sin6->sin6_addr)); |
|
141 } |
|
142 |
51 |
143 |
52 JNIEXPORT void JNICALL |
144 JNIEXPORT void JNICALL |
53 Java_sun_nio_ch_Net_initIDs(JNIEnv *env, jclass clazz) |
145 Java_sun_nio_ch_Net_initIDs(JNIEnv *env, jclass clazz) |
54 { |
146 { |
55 /* Here because Windows native code does need to init IDs */ |
147 /* Here because Windows native code does need to init IDs */ |
56 } |
148 } |
57 |
149 |
|
150 JNIEXPORT jboolean JNICALL |
|
151 Java_sun_nio_ch_Net_isIPv6Available0(JNIEnv* env, jclass cl) |
|
152 { |
|
153 return (ipv6_available()) ? JNI_TRUE : JNI_FALSE; |
|
154 } |
|
155 |
58 JNIEXPORT int JNICALL |
156 JNIEXPORT int JNICALL |
59 Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean stream, |
157 Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6, |
60 jboolean reuse) |
158 jboolean stream, jboolean reuse) |
61 { |
159 { |
62 int fd; |
160 int fd; |
63 |
161 int type = (stream ? SOCK_STREAM : SOCK_DGRAM); |
64 #ifdef AF_INET6 |
162 int domain = (ipv6_available() && preferIPv6) ? AF_INET6 : AF_INET; |
65 if (ipv6_available()) |
163 |
66 fd = socket(AF_INET6, (stream ? SOCK_STREAM : SOCK_DGRAM), 0); |
164 fd = socket(domain, type, 0); |
67 else |
|
68 #endif /* AF_INET6 */ |
|
69 fd = socket(AF_INET, (stream ? SOCK_STREAM : SOCK_DGRAM), 0); |
|
70 |
|
71 if (fd < 0) { |
165 if (fd < 0) { |
72 return handleSocketError(env, errno); |
166 return handleSocketError(env, errno); |
73 } |
167 } |
74 if (reuse) { |
168 if (reuse) { |
75 int arg = 1; |
169 int arg = 1; |
76 if (NET_SetSockOpt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, |
170 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, |
77 sizeof(arg)) < 0) { |
171 sizeof(arg)) < 0) { |
78 JNU_ThrowByNameWithLastError(env, |
172 JNU_ThrowByNameWithLastError(env, |
79 JNU_JAVANETPKG "SocketException", |
173 JNU_JAVANETPKG "SocketException", |
80 "sun.nio.ch.Net.setIntOption"); |
174 "sun.nio.ch.Net.setIntOption"); |
|
175 close(fd); |
|
176 return -1; |
81 } |
177 } |
82 } |
178 } |
|
179 #ifdef __linux__ |
|
180 /* By default, Linux uses the route default */ |
|
181 if (domain == AF_INET6 && type == SOCK_DGRAM) { |
|
182 int arg = 1; |
|
183 if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &arg, |
|
184 sizeof(arg)) < 0) { |
|
185 JNU_ThrowByNameWithLastError(env, |
|
186 JNU_JAVANETPKG "SocketException", |
|
187 "sun.nio.ch.Net.setIntOption"); |
|
188 close(fd); |
|
189 return -1; |
|
190 } |
|
191 } |
|
192 #endif |
83 return fd; |
193 return fd; |
84 } |
194 } |
85 |
195 |
86 JNIEXPORT void JNICALL |
196 JNIEXPORT void JNICALL |
87 Java_sun_nio_ch_Net_bind(JNIEnv *env, jclass clazz, /* ## Needs rest of PSI gunk */ |
197 Java_sun_nio_ch_Net_bind0(JNIEnv *env, jclass clazz, jboolean preferIPv6, |
88 jobject fdo, jobject ia, int port) |
198 jobject fdo, jobject iao, int port) |
89 { |
199 { |
90 SOCKADDR sa; |
200 SOCKADDR sa; |
91 int sa_len = SOCKADDR_LEN; |
201 int sa_len = SOCKADDR_LEN; |
92 int rv = 0; |
202 int rv = 0; |
93 |
203 |
94 if (NET_InetAddressToSockaddr(env, ia, port, (struct sockaddr *)&sa, &sa_len, JNI_TRUE) != 0) { |
204 if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, preferIPv6) != 0) { |
95 return; |
205 return; |
96 } |
206 } |
97 |
207 |
98 rv = NET_Bind(fdval(env, fdo), (struct sockaddr *)&sa, sa_len); |
208 rv = NET_Bind(fdval(env, fdo), (struct sockaddr *)&sa, sa_len); |
99 if (rv != 0) { |
209 if (rv != 0) { |
100 handleSocketError(env, errno); |
210 handleSocketError(env, errno); |
101 } |
211 } |
102 } |
212 } |
103 |
213 |
104 JNIEXPORT jint JNICALL |
214 JNIEXPORT void JNICALL |
105 Java_sun_nio_ch_Net_connect(JNIEnv *env, jclass clazz, |
215 Java_sun_nio_ch_Net_listen(JNIEnv *env, jclass cl, jobject fdo, jint backlog) |
106 jobject fdo, jobject iao, jint port, |
216 { |
107 jint trafficClass) |
217 if (listen(fdval(env, fdo), backlog) < 0) |
|
218 handleSocketError(env, errno); |
|
219 } |
|
220 |
|
221 JNIEXPORT jint JNICALL |
|
222 Java_sun_nio_ch_Net_connect0(JNIEnv *env, jclass clazz, jboolean preferIPv6, |
|
223 jobject fdo, jobject iao, jint port) |
108 { |
224 { |
109 SOCKADDR sa; |
225 SOCKADDR sa; |
110 int sa_len = SOCKADDR_LEN; |
226 int sa_len = SOCKADDR_LEN; |
111 int rv; |
227 int rv; |
112 |
228 |
113 if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *) &sa, &sa_len, JNI_TRUE) != 0) { |
229 if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *) &sa, |
|
230 &sa_len, preferIPv6) != 0) |
|
231 { |
114 return IOS_THROWN; |
232 return IOS_THROWN; |
115 } |
233 } |
116 |
|
117 #ifdef AF_INET6 |
|
118 #if 0 |
|
119 if (trafficClass != 0 && ipv6_available()) { /* ## FIX */ |
|
120 NET_SetTrafficClass((struct sockaddr *)&sa, trafficClass); |
|
121 } |
|
122 #endif |
|
123 #endif |
|
124 |
234 |
125 rv = connect(fdval(env, fdo), (struct sockaddr *)&sa, sa_len); |
235 rv = connect(fdval(env, fdo), (struct sockaddr *)&sa, sa_len); |
126 if (rv != 0) { |
236 if (rv != 0) { |
127 if (errno == EINPROGRESS) { |
237 if (errno == EINPROGRESS) { |
128 return IOS_UNAVAILABLE; |
238 return IOS_UNAVAILABLE; |
157 return NULL; |
267 return NULL; |
158 } |
268 } |
159 return NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port); |
269 return NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port); |
160 } |
270 } |
161 |
271 |
162 |
272 JNIEXPORT jint JNICALL |
163 #ifdef NEEDED |
273 Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, jobject fdo, |
164 |
274 jboolean mayNeedConversion, jint level, jint opt) |
165 /* ## This is gross. We should generate platform-specific constant |
275 { |
166 * ## definitions into a .java file and use those directly. |
|
167 */ |
|
168 |
|
169 static int |
|
170 mapOption(JNIEnv *env, int opt, int *klevel, int *kopt) |
|
171 { |
|
172 |
|
173 switch (opt) { |
|
174 |
|
175 case java_net_SocketOptions_IP_TOS: |
|
176 *klevel = IPPROTO_IP; |
|
177 *kopt = IP_TOS; |
|
178 break; |
|
179 |
|
180 case java_net_SocketOptions_SO_BROADCAST: |
|
181 case java_net_SocketOptions_SO_KEEPALIVE: |
|
182 case java_net_SocketOptions_SO_LINGER: |
|
183 case java_net_SocketOptions_SO_OOBINLINE: |
|
184 case java_net_SocketOptions_SO_RCVBUF: |
|
185 case java_net_SocketOptions_SO_REUSEADDR: |
|
186 case java_net_SocketOptions_SO_SNDBUF: |
|
187 *klevel = SOL_SOCKET; |
|
188 break; |
|
189 |
|
190 case java_net_SocketOptions_TCP_NODELAY: |
|
191 *klevel = IPPROTO_IP; |
|
192 *kopt = TCP_NODELAY; |
|
193 return 0; |
|
194 |
|
195 default: |
|
196 JNU_ThrowByName(env, "java/lang/IllegalArgumentException", NULL); |
|
197 return -1; |
|
198 } |
|
199 |
|
200 switch (opt) { |
|
201 |
|
202 case java_net_SocketOptions_SO_BROADCAST: *kopt = SO_BROADCAST; break; |
|
203 case java_net_SocketOptions_SO_KEEPALIVE: *kopt = SO_KEEPALIVE; break; |
|
204 case java_net_SocketOptions_SO_LINGER: *kopt = SO_LINGER; break; |
|
205 case java_net_SocketOptions_SO_OOBINLINE: *kopt = SO_OOBINLINE; break; |
|
206 case java_net_SocketOptions_SO_RCVBUF: *kopt = SO_RCVBUF; break; |
|
207 case java_net_SocketOptions_SO_REUSEADDR: *kopt = SO_REUSEADDR; break; |
|
208 case java_net_SocketOptions_SO_SNDBUF: *kopt = SO_SNDBUF; break; |
|
209 |
|
210 default: |
|
211 return -1; |
|
212 } |
|
213 |
|
214 return 0; |
|
215 } |
|
216 #endif |
|
217 |
|
218 |
|
219 JNIEXPORT jint JNICALL |
|
220 Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, |
|
221 jobject fdo, jint opt) |
|
222 { |
|
223 int klevel, kopt; |
|
224 int result; |
276 int result; |
225 struct linger linger; |
277 struct linger linger; |
|
278 u_char carg; |
226 void *arg; |
279 void *arg; |
227 int arglen; |
280 int arglen, n; |
228 |
281 |
229 if (NET_MapSocketOption(opt, &klevel, &kopt) < 0) { |
282 /* Option value is an int except for a few specific cases */ |
230 JNU_ThrowByNameWithLastError(env, |
283 |
231 JNU_JAVANETPKG "SocketException", |
284 arg = (void *)&result; |
232 "Unsupported socket option"); |
285 arglen = sizeof(result); |
233 return -1; |
286 |
234 } |
287 if (level == IPPROTO_IP && |
235 |
288 (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) { |
236 if (opt == java_net_SocketOptions_SO_LINGER) { |
289 arg = (void*)&carg; |
|
290 arglen = sizeof(carg); |
|
291 } |
|
292 |
|
293 if (level == SOL_SOCKET && opt == SO_LINGER) { |
237 arg = (void *)&linger; |
294 arg = (void *)&linger; |
238 arglen = sizeof(linger); |
295 arglen = sizeof(linger); |
|
296 } |
|
297 |
|
298 if (mayNeedConversion) { |
|
299 n = NET_GetSockOpt(fdval(env, fdo), level, opt, arg, &arglen); |
239 } else { |
300 } else { |
240 arg = (void *)&result; |
301 n = getsockopt(fdval(env, fdo), level, opt, arg, &arglen); |
241 arglen = sizeof(result); |
302 } |
242 } |
303 if (n < 0) { |
243 |
|
244 if (NET_GetSockOpt(fdval(env, fdo), klevel, kopt, arg, &arglen) < 0) { |
|
245 JNU_ThrowByNameWithLastError(env, |
304 JNU_ThrowByNameWithLastError(env, |
246 JNU_JAVANETPKG "SocketException", |
305 JNU_JAVANETPKG "SocketException", |
247 "sun.nio.ch.Net.getIntOption"); |
306 "sun.nio.ch.Net.getIntOption"); |
248 return -1; |
307 return -1; |
249 } |
308 } |
250 |
309 |
251 if (opt == java_net_SocketOptions_SO_LINGER) |
310 if (level == IPPROTO_IP && |
252 return linger.l_onoff ? linger.l_linger : -1; |
311 (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) |
253 else |
312 { |
254 return result; |
313 return (jint)carg; |
255 } |
314 } |
256 |
315 |
257 JNIEXPORT void JNICALL |
316 if (level == SOL_SOCKET && opt == SO_LINGER) |
258 Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, |
317 return linger.l_onoff ? (jint)linger.l_linger : (jint)-1; |
259 jobject fdo, jint opt, jint arg) |
318 |
260 { |
319 return (jint)result; |
261 int klevel, kopt; |
320 } |
|
321 |
|
322 JNIEXPORT void JNICALL |
|
323 Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, jobject fdo, |
|
324 jboolean mayNeedConversion, jint level, jint opt, jint arg) |
|
325 { |
262 int result; |
326 int result; |
263 struct linger linger; |
327 struct linger linger; |
|
328 u_char carg; |
264 void *parg; |
329 void *parg; |
265 int arglen; |
330 int arglen, n; |
266 |
331 |
267 if (NET_MapSocketOption(opt, &klevel, &kopt) < 0) { |
332 /* Option value is an int except for a few specific cases */ |
268 JNU_ThrowByNameWithLastError(env, |
333 |
269 JNU_JAVANETPKG "SocketException", |
334 parg = (void*)&arg; |
270 "Unsupported socket option"); |
335 arglen = sizeof(arg); |
271 return; |
336 |
272 } |
337 if (level == IPPROTO_IP && |
273 |
338 (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) { |
274 if (opt == java_net_SocketOptions_SO_LINGER) { |
339 parg = (void*)&carg; |
|
340 arglen = sizeof(carg); |
|
341 carg = (u_char)arg; |
|
342 } |
|
343 |
|
344 if (level == SOL_SOCKET && opt == SO_LINGER) { |
275 parg = (void *)&linger; |
345 parg = (void *)&linger; |
276 arglen = sizeof(linger); |
346 arglen = sizeof(linger); |
277 if (arg >= 0) { |
347 if (arg >= 0) { |
278 linger.l_onoff = 1; |
348 linger.l_onoff = 1; |
279 linger.l_linger = arg; |
349 linger.l_linger = arg; |
280 } else { |
350 } else { |
281 linger.l_onoff = 0; |
351 linger.l_onoff = 0; |
282 linger.l_linger = 0; |
352 linger.l_linger = 0; |
283 } |
353 } |
|
354 } |
|
355 |
|
356 if (mayNeedConversion) { |
|
357 n = NET_SetSockOpt(fdval(env, fdo), level, opt, parg, arglen); |
284 } else { |
358 } else { |
285 parg = (void *)&arg; |
359 n = setsockopt(fdval(env, fdo), level, opt, parg, arglen); |
286 arglen = sizeof(arg); |
360 } |
287 } |
361 if (n < 0) { |
288 |
|
289 if (NET_SetSockOpt(fdval(env, fdo), klevel, kopt, parg, arglen) < 0) { |
|
290 JNU_ThrowByNameWithLastError(env, |
362 JNU_ThrowByNameWithLastError(env, |
291 JNU_JAVANETPKG "SocketException", |
363 JNU_JAVANETPKG "SocketException", |
292 "sun.nio.ch.Net.setIntOption"); |
364 "sun.nio.ch.Net.setIntOption"); |
293 } |
365 } |
294 } |
366 } |
295 |
367 |
296 |
368 JNIEXPORT jint JNICALL |
|
369 Java_sun_nio_ch_Net_joinOrDrop4(JNIEnv *env, jobject this, jboolean join, jobject fdo, |
|
370 jint group, jint interf, jint source) |
|
371 { |
|
372 struct ip_mreq mreq; |
|
373 struct my_ip_mreq_source mreq_source; |
|
374 int opt, n, optlen; |
|
375 void* optval; |
|
376 |
|
377 if (source == 0) { |
|
378 mreq.imr_multiaddr.s_addr = htonl(group); |
|
379 mreq.imr_interface.s_addr = htonl(interf); |
|
380 opt = (join) ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP; |
|
381 optval = (void*)&mreq; |
|
382 optlen = sizeof(mreq); |
|
383 } else { |
|
384 mreq_source.imr_multiaddr.s_addr = htonl(group); |
|
385 mreq_source.imr_sourceaddr.s_addr = htonl(source); |
|
386 mreq_source.imr_interface.s_addr = htonl(interf); |
|
387 opt = (join) ? IP_ADD_SOURCE_MEMBERSHIP : IP_DROP_SOURCE_MEMBERSHIP; |
|
388 optval = (void*)&mreq_source; |
|
389 optlen = sizeof(mreq_source); |
|
390 } |
|
391 |
|
392 n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, optval, optlen); |
|
393 if (n < 0) { |
|
394 if (join && (errno == ENOPROTOOPT)) |
|
395 return IOS_UNAVAILABLE; |
|
396 handleSocketError(env, errno); |
|
397 } |
|
398 return 0; |
|
399 } |
|
400 |
|
401 JNIEXPORT jint JNICALL |
|
402 Java_sun_nio_ch_Net_blockOrUnblock4(JNIEnv *env, jobject this, jboolean block, jobject fdo, |
|
403 jint group, jint interf, jint source) |
|
404 { |
|
405 struct my_ip_mreq_source mreq_source; |
|
406 int n; |
|
407 int opt = (block) ? IP_BLOCK_SOURCE : IP_UNBLOCK_SOURCE; |
|
408 |
|
409 mreq_source.imr_multiaddr.s_addr = htonl(group); |
|
410 mreq_source.imr_sourceaddr.s_addr = htonl(source); |
|
411 mreq_source.imr_interface.s_addr = htonl(interf); |
|
412 |
|
413 n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, |
|
414 (void*)&mreq_source, sizeof(mreq_source)); |
|
415 if (n < 0) { |
|
416 if (block && (errno == ENOPROTOOPT)) |
|
417 return IOS_UNAVAILABLE; |
|
418 handleSocketError(env, errno); |
|
419 } |
|
420 return 0; |
|
421 } |
|
422 |
|
423 JNIEXPORT jint JNICALL |
|
424 Java_sun_nio_ch_Net_joinOrDrop6(JNIEnv *env, jobject this, jboolean join, jobject fdo, |
|
425 jbyteArray group, jint index, jbyteArray source) |
|
426 { |
|
427 struct ipv6_mreq mreq6; |
|
428 struct my_group_source_req req; |
|
429 int opt, n, optlen; |
|
430 void* optval; |
|
431 |
|
432 if (source == NULL) { |
|
433 COPY_INET6_ADDRESS(env, group, (jbyte*)&(mreq6.ipv6mr_multiaddr)); |
|
434 mreq6.ipv6mr_interface = (int)index; |
|
435 opt = (join) ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP; |
|
436 optval = (void*)&mreq6; |
|
437 optlen = sizeof(mreq6); |
|
438 } else { |
|
439 #ifdef __linux__ |
|
440 /* Include-mode filtering broken on Linux at least to 2.6.24 */ |
|
441 return IOS_UNAVAILABLE; |
|
442 #else |
|
443 initGroupSourceReq(env, group, index, source, &req); |
|
444 opt = (join) ? MCAST_JOIN_SOURCE_GROUP : MCAST_LEAVE_SOURCE_GROUP; |
|
445 optval = (void*)&req; |
|
446 optlen = sizeof(req); |
|
447 #endif |
|
448 } |
|
449 |
|
450 n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, optval, optlen); |
|
451 if (n < 0) { |
|
452 if (join && (errno == ENOPROTOOPT)) |
|
453 return IOS_UNAVAILABLE; |
|
454 handleSocketError(env, errno); |
|
455 } |
|
456 return 0; |
|
457 } |
|
458 |
|
459 JNIEXPORT jint JNICALL |
|
460 Java_sun_nio_ch_Net_blockOrUnblock6(JNIEnv *env, jobject this, jboolean block, jobject fdo, |
|
461 jbyteArray group, jint index, jbyteArray source) |
|
462 { |
|
463 struct my_group_source_req req; |
|
464 int n; |
|
465 int opt = (block) ? MCAST_BLOCK_SOURCE : MCAST_UNBLOCK_SOURCE; |
|
466 |
|
467 initGroupSourceReq(env, group, index, source, &req); |
|
468 |
|
469 n = setsockopt(fdval(env,fdo), IPPROTO_IPV6, opt, |
|
470 (void*)&req, sizeof(req)); |
|
471 if (n < 0) { |
|
472 if (block && (errno == ENOPROTOOPT)) |
|
473 return IOS_UNAVAILABLE; |
|
474 handleSocketError(env, errno); |
|
475 } |
|
476 return 0; |
|
477 } |
|
478 |
|
479 JNIEXPORT void JNICALL |
|
480 Java_sun_nio_ch_Net_setInterface4(JNIEnv* env, jobject this, jobject fdo, jint interf) |
|
481 { |
|
482 struct in_addr in; |
|
483 int arglen = sizeof(struct in_addr); |
|
484 int n; |
|
485 |
|
486 in.s_addr = htonl(interf); |
|
487 |
|
488 n = setsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, |
|
489 (void*)&(in.s_addr), arglen); |
|
490 if (n < 0) { |
|
491 handleSocketError(env, errno); |
|
492 } |
|
493 } |
|
494 |
|
495 JNIEXPORT jint JNICALL |
|
496 Java_sun_nio_ch_Net_getInterface4(JNIEnv* env, jobject this, jobject fdo) |
|
497 { |
|
498 struct in_addr in; |
|
499 int arglen = sizeof(struct in_addr); |
|
500 int n; |
|
501 |
|
502 n = getsockopt(fdval(env, fdo), IPPROTO_IP, IP_MULTICAST_IF, (void*)&in, &arglen); |
|
503 if (n < 0) { |
|
504 handleSocketError(env, errno); |
|
505 return -1; |
|
506 } |
|
507 return ntohl(in.s_addr); |
|
508 } |
|
509 |
|
510 JNIEXPORT void JNICALL |
|
511 Java_sun_nio_ch_Net_setInterface6(JNIEnv* env, jobject this, jobject fdo, jint index) |
|
512 { |
|
513 int value = (jint)index; |
|
514 int arglen = sizeof(value); |
|
515 int n; |
|
516 |
|
517 n = setsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, |
|
518 (void*)&(index), arglen); |
|
519 if (n < 0) { |
|
520 handleSocketError(env, errno); |
|
521 } |
|
522 } |
|
523 |
|
524 JNIEXPORT jint JNICALL |
|
525 Java_sun_nio_ch_Net_getInterface6(JNIEnv* env, jobject this, jobject fdo) |
|
526 { |
|
527 int index; |
|
528 int arglen = sizeof(index); |
|
529 int n; |
|
530 |
|
531 n = getsockopt(fdval(env, fdo), IPPROTO_IPV6, IPV6_MULTICAST_IF, (void*)&index, &arglen); |
|
532 if (n < 0) { |
|
533 handleSocketError(env, errno); |
|
534 return -1; |
|
535 } |
|
536 return (jint)index; |
|
537 } |
|
538 |
|
539 JNIEXPORT void JNICALL |
|
540 Java_sun_nio_ch_Net_shutdown(JNIEnv *env, jclass cl, jobject fdo, jint jhow) |
|
541 { |
|
542 int how = (jhow == sun_nio_ch_Net_SHUT_RD) ? SHUT_RD : |
|
543 (jhow == sun_nio_ch_Net_SHUT_WR) ? SHUT_WR : SHUT_RDWR; |
|
544 if (shutdown(fdval(env, fdo), how) < 0) |
|
545 handleSocketError(env, errno); |
|
546 } |
297 |
547 |
298 /* Declared in nio_util.h */ |
548 /* Declared in nio_util.h */ |
299 |
549 |
300 jint |
550 jint |
301 handleSocketError(JNIEnv *env, jint errorValue) |
551 handleSocketError(JNIEnv *env, jint errorValue) |