|
1 /* |
|
2 * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
|
22 * CA 95054 USA or visit www.sun.com if you need additional information or |
|
23 * have any questions. |
|
24 */ |
|
25 |
|
26 #include <stdlib.h> |
|
27 #include <string.h> |
|
28 #include <dlfcn.h> |
|
29 |
|
30 #include "Sctp.h" |
|
31 #include "jni.h" |
|
32 #include "jni_util.h" |
|
33 #include "nio_util.h" |
|
34 #include "nio.h" |
|
35 #include "net_util.h" |
|
36 #include "net_util_md.h" |
|
37 #include "sun_nio_ch_SctpNet.h" |
|
38 #include "sun_nio_ch_SctpStdSocketOption.h" |
|
39 |
|
40 static jclass isaCls = 0; |
|
41 static jmethodID isaCtrID = 0; |
|
42 |
|
43 static const char* nativeSctpLib = "libsctp.so.1"; |
|
44 static jboolean funcsLoaded = JNI_FALSE; |
|
45 |
|
46 JNIEXPORT jint JNICALL JNI_OnLoad |
|
47 (JavaVM *vm, void *reserved) { |
|
48 return JNI_VERSION_1_2; |
|
49 } |
|
50 |
|
51 /** |
|
52 * Loads the native sctp library that contains the socket extension |
|
53 * functions, as well as locating the individual functions. |
|
54 * There will be a pending exception if this method returns false. |
|
55 */ |
|
56 jboolean loadSocketExtensionFuncs |
|
57 (JNIEnv* env) { |
|
58 if (dlopen(nativeSctpLib, RTLD_GLOBAL | RTLD_LAZY) == NULL) { |
|
59 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", |
|
60 dlerror()); |
|
61 return JNI_FALSE; |
|
62 } |
|
63 |
|
64 if ((nio_sctp_getladdrs = (sctp_getladdrs_func*) |
|
65 dlsym(RTLD_DEFAULT, "sctp_getladdrs")) == NULL) { |
|
66 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", |
|
67 dlerror()); |
|
68 return JNI_FALSE; |
|
69 } |
|
70 |
|
71 if ((nio_sctp_freeladdrs = (sctp_freeladdrs_func*) |
|
72 dlsym(RTLD_DEFAULT, "sctp_freeladdrs")) == NULL) { |
|
73 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", |
|
74 dlerror()); |
|
75 return JNI_FALSE; |
|
76 } |
|
77 |
|
78 if ((nio_sctp_getpaddrs = (sctp_getpaddrs_func*) |
|
79 dlsym(RTLD_DEFAULT, "sctp_getpaddrs")) == NULL) { |
|
80 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", |
|
81 dlerror()); |
|
82 return JNI_FALSE; |
|
83 } |
|
84 |
|
85 if ((nio_sctp_freepaddrs = (sctp_freepaddrs_func*) |
|
86 dlsym(RTLD_DEFAULT, "sctp_freepaddrs")) == NULL) { |
|
87 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", |
|
88 dlerror()); |
|
89 return JNI_FALSE; |
|
90 } |
|
91 |
|
92 if ((nio_sctp_bindx = (sctp_bindx_func*) |
|
93 dlsym(RTLD_DEFAULT, "sctp_bindx")) == NULL) { |
|
94 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", |
|
95 dlerror()); |
|
96 return JNI_FALSE; |
|
97 } |
|
98 |
|
99 funcsLoaded = JNI_TRUE; |
|
100 return JNI_TRUE; |
|
101 } |
|
102 |
|
103 /* |
|
104 * Class: sun_nio_ch_SctpNet |
|
105 * Method: socket0 |
|
106 * Signature: (Z)I |
|
107 */ |
|
108 JNIEXPORT jint JNICALL Java_sun_nio_ch_SctpNet_socket0 |
|
109 (JNIEnv *env, jclass klass, jboolean oneToOne) { |
|
110 int fd; |
|
111 struct sctp_event_subscribe event; |
|
112 |
|
113 /* Try to load the socket API extension functions */ |
|
114 if (!funcsLoaded && !loadSocketExtensionFuncs(env)) { |
|
115 return 0; |
|
116 } |
|
117 |
|
118 fd = socket(ipv6_available() ? AF_INET6 : AF_INET, |
|
119 (oneToOne ? SOCK_STREAM : SOCK_SEQPACKET), IPPROTO_SCTP); |
|
120 |
|
121 if (fd < 0) { |
|
122 return handleSocketError(env, errno); |
|
123 } |
|
124 |
|
125 /* Enable events */ |
|
126 memset(&event, 0, sizeof(event)); |
|
127 event.sctp_data_io_event = 1; |
|
128 event.sctp_association_event = 1; |
|
129 event.sctp_address_event = 1; |
|
130 event.sctp_send_failure_event = 1; |
|
131 //event.sctp_peer_error_event = 1; |
|
132 event.sctp_shutdown_event = 1; |
|
133 //event.sctp_partial_delivery_event = 1; |
|
134 //event.sctp_adaptation_layer_event = 1; |
|
135 if (setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(event)) != 0) { |
|
136 handleSocketError(env, errno); |
|
137 } |
|
138 return fd; |
|
139 } |
|
140 |
|
141 /* |
|
142 * Class: sun_nio_ch_SctpNet |
|
143 * Method: bindx |
|
144 * Signature: (I[Ljava/net/InetAddress;IIZ)V |
|
145 */ |
|
146 JNIEXPORT void JNICALL Java_sun_nio_ch_SctpNet_bindx |
|
147 (JNIEnv *env, jclass klass, jint fd, jobjectArray addrs, jint port, |
|
148 jint addrsLength, jboolean add, jboolean preferIPv6) { |
|
149 SOCKADDR *sap, *tmpSap; |
|
150 int i, sa_len = sizeof(SOCKADDR); |
|
151 jobject ia; |
|
152 |
|
153 if (addrsLength < 1) |
|
154 return; |
|
155 |
|
156 if ((sap = calloc(addrsLength, sa_len)) == NULL) { |
|
157 JNU_ThrowOutOfMemoryError(env, "heap allocation failure"); |
|
158 return; |
|
159 } |
|
160 |
|
161 tmpSap = sap; |
|
162 for (i=0; i<addrsLength; i++) { |
|
163 ia = (*env)->GetObjectArrayElement(env, addrs, i); |
|
164 if (NET_InetAddressToSockaddr(env, ia, port, (struct sockaddr*)tmpSap, |
|
165 &sa_len, preferIPv6) != 0) { |
|
166 free(sap); |
|
167 return; |
|
168 } |
|
169 tmpSap++; |
|
170 } |
|
171 |
|
172 if (nio_sctp_bindx(fd, (void*)sap, addrsLength, add ? SCTP_BINDX_ADD_ADDR : |
|
173 SCTP_BINDX_REM_ADDR) != 0) { |
|
174 handleSocketError(env, errno); |
|
175 } |
|
176 |
|
177 free(sap); |
|
178 } |
|
179 |
|
180 void initializeISA |
|
181 (JNIEnv* env) { |
|
182 if (isaCls == 0) { |
|
183 jclass c = (*env)->FindClass(env, "java/net/InetSocketAddress"); |
|
184 CHECK_NULL(c); |
|
185 isaCls = (*env)->NewGlobalRef(env, c); |
|
186 CHECK_NULL(isaCls); |
|
187 (*env)->DeleteLocalRef(env, c); |
|
188 isaCtrID = (*env)->GetMethodID(env, isaCls, "<init>", |
|
189 "(Ljava/net/InetAddress;I)V"); |
|
190 } |
|
191 } |
|
192 |
|
193 jobject SockAddrToInetSocketAddress |
|
194 (JNIEnv *env, struct sockaddr* sap) { |
|
195 int port = 0; |
|
196 |
|
197 jobject ia = NET_SockaddrToInetAddress(env, sap, &port); |
|
198 if (ia == NULL) |
|
199 return NULL; |
|
200 |
|
201 if (isaCls == 0) { |
|
202 initializeISA(env); |
|
203 CHECK_NULL_RETURN(isaCls, NULL); |
|
204 } |
|
205 |
|
206 return (*env)->NewObject(env, isaCls, isaCtrID, ia, port); |
|
207 } |
|
208 |
|
209 /* |
|
210 * Class: sun_nio_ch_SctpNet |
|
211 * Method: getLocalAddresses0 |
|
212 * Signature: (I)[Ljava/net/SocketAddress; |
|
213 */ |
|
214 JNIEXPORT jobjectArray JNICALL Java_sun_nio_ch_SctpNet_getLocalAddresses0 |
|
215 (JNIEnv *env, jclass klass, jint fd) { |
|
216 void *addr_buf, *laddr; |
|
217 struct sockaddr* sap; |
|
218 int i, addrCount; |
|
219 jobjectArray isaa; |
|
220 |
|
221 #ifdef __solaris__ |
|
222 if ((addrCount = nio_sctp_getladdrs(fd, 0, (void **)&addr_buf)) == -1) { |
|
223 #else /* __linux__ */ |
|
224 if ((addrCount = nio_sctp_getladdrs(fd, 0, (struct sockaddr **)&addr_buf)) == -1) { |
|
225 #endif |
|
226 handleSocketError(env, errno); |
|
227 return NULL; |
|
228 } |
|
229 |
|
230 if (addrCount < 1) |
|
231 return NULL; |
|
232 |
|
233 if (isaCls == 0) { |
|
234 initializeISA(env); |
|
235 CHECK_NULL_RETURN(isaCls, NULL); |
|
236 } |
|
237 |
|
238 isaa = (*env)->NewObjectArray(env, addrCount, isaCls, NULL); |
|
239 if (isaa == NULL) { |
|
240 nio_sctp_freeladdrs(addr_buf); |
|
241 return NULL; |
|
242 } |
|
243 |
|
244 laddr = addr_buf; |
|
245 for (i=0; i<addrCount; i++) { |
|
246 int port = 0; |
|
247 jobject isa = NULL, ia; |
|
248 sap = (struct sockaddr*)addr_buf; |
|
249 ia = NET_SockaddrToInetAddress(env, sap, &port); |
|
250 if (ia != NULL) |
|
251 isa = (*env)->NewObject(env, isaCls, isaCtrID, ia, port); |
|
252 if (isa != NULL) |
|
253 (*env)->SetObjectArrayElement(env, isaa, i, isa); |
|
254 |
|
255 if (sap->sa_family == AF_INET) |
|
256 addr_buf = ((struct sockaddr_in*)addr_buf) + 1; |
|
257 else |
|
258 addr_buf = ((struct sockaddr_in6*)addr_buf) + 1; |
|
259 } |
|
260 |
|
261 nio_sctp_freeladdrs(laddr); |
|
262 return isaa; |
|
263 } |
|
264 |
|
265 jobjectArray getRemoteAddresses |
|
266 (JNIEnv *env, jint fd, sctp_assoc_t id) { |
|
267 void *addr_buf, *paddr; |
|
268 struct sockaddr* sap; |
|
269 int i, addrCount; |
|
270 jobjectArray isaa; |
|
271 |
|
272 #if __solaris__ |
|
273 if ((addrCount = nio_sctp_getpaddrs(fd, id, (void **)&addr_buf)) == -1) { |
|
274 #else /* __linux__ */ |
|
275 if ((addrCount = nio_sctp_getpaddrs(fd, id, (struct sockaddr**)&addr_buf)) == -1) { |
|
276 #endif |
|
277 handleSocketError(env, errno); |
|
278 return NULL; |
|
279 } |
|
280 |
|
281 if (addrCount < 1) |
|
282 return NULL; |
|
283 |
|
284 if (isaCls == 0) { |
|
285 initializeISA(env); |
|
286 CHECK_NULL_RETURN(isaCls, NULL); |
|
287 } |
|
288 |
|
289 isaa = (*env)->NewObjectArray(env, addrCount, isaCls, NULL); |
|
290 if (isaa == NULL) { |
|
291 nio_sctp_freepaddrs(addr_buf); |
|
292 return NULL; |
|
293 } |
|
294 |
|
295 paddr = addr_buf; |
|
296 for (i=0; i<addrCount; i++) { |
|
297 jobject ia, isa = NULL; |
|
298 int port; |
|
299 sap = (struct sockaddr*)addr_buf; |
|
300 ia = NET_SockaddrToInetAddress(env, sap, &port); |
|
301 if (ia != NULL) |
|
302 isa = (*env)->NewObject(env, isaCls, isaCtrID, ia, port); |
|
303 if (isa != NULL) |
|
304 (*env)->SetObjectArrayElement(env, isaa, i, isa); |
|
305 |
|
306 if (sap->sa_family == AF_INET) |
|
307 addr_buf = ((struct sockaddr_in*)addr_buf) + 1; |
|
308 else |
|
309 addr_buf = ((struct sockaddr_in6*)addr_buf) + 1; |
|
310 } |
|
311 |
|
312 nio_sctp_freepaddrs(paddr); |
|
313 |
|
314 return isaa; |
|
315 } |
|
316 |
|
317 /* |
|
318 * Class: sun_nio_ch_SctpNet |
|
319 * Method: getRemoteAddresses0 |
|
320 * Signature: (II)[Ljava/net/SocketAddress; |
|
321 */ |
|
322 JNIEXPORT jobjectArray JNICALL Java_sun_nio_ch_SctpNet_getRemoteAddresses0 |
|
323 (JNIEnv *env, jclass klass, jint fd, jint assocId) { |
|
324 return getRemoteAddresses(env, fd, assocId); |
|
325 } |
|
326 |
|
327 /* Map the Java level option to the native level */ |
|
328 int mapSocketOption |
|
329 (jint cmd, int *level, int *optname) { |
|
330 static struct { |
|
331 jint cmd; |
|
332 int level; |
|
333 int optname; |
|
334 } const opts[] = { |
|
335 { sun_nio_ch_SctpStdSocketOption_SCTP_DISABLE_FRAGMENTS, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS }, |
|
336 { sun_nio_ch_SctpStdSocketOption_SCTP_EXPLICIT_COMPLETE, IPPROTO_SCTP, SCTP_EXPLICIT_EOR }, |
|
337 { sun_nio_ch_SctpStdSocketOption_SCTP_FRAGMENT_INTERLEAVE, IPPROTO_SCTP, SCTP_FRAGMENT_INTERLEAVE }, |
|
338 { sun_nio_ch_SctpStdSocketOption_SCTP_NODELAY, IPPROTO_SCTP, SCTP_NODELAY }, |
|
339 { sun_nio_ch_SctpStdSocketOption_SO_SNDBUF, SOL_SOCKET, SO_SNDBUF }, |
|
340 { sun_nio_ch_SctpStdSocketOption_SO_RCVBUF, SOL_SOCKET, SO_RCVBUF }, |
|
341 { sun_nio_ch_SctpStdSocketOption_SO_LINGER, SOL_SOCKET, SO_LINGER } }; |
|
342 |
|
343 int i; |
|
344 for (i=0; i<(int)(sizeof(opts) / sizeof(opts[0])); i++) { |
|
345 if (cmd == opts[i].cmd) { |
|
346 *level = opts[i].level; |
|
347 *optname = opts[i].optname; |
|
348 return 0; |
|
349 } |
|
350 } |
|
351 |
|
352 /* not found */ |
|
353 return -1; |
|
354 } |
|
355 |
|
356 /* |
|
357 * Class: sun_nio_ch_SctpNet |
|
358 * Method: setIntOption0 |
|
359 * Signature: (III)V |
|
360 */ |
|
361 JNIEXPORT void JNICALL Java_sun_nio_ch_SctpNet_setIntOption0 |
|
362 (JNIEnv *env, jclass klass, jint fd, jint opt, int arg) { |
|
363 int klevel, kopt; |
|
364 int result; |
|
365 struct linger linger; |
|
366 void *parg; |
|
367 int arglen; |
|
368 |
|
369 if (mapSocketOption(opt, &klevel, &kopt) < 0) { |
|
370 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", |
|
371 "Unsupported socket option"); |
|
372 return; |
|
373 } |
|
374 |
|
375 if (opt == sun_nio_ch_SctpStdSocketOption_SO_LINGER) { |
|
376 parg = (void *)&linger; |
|
377 arglen = sizeof(linger); |
|
378 if (arg >= 0) { |
|
379 linger.l_onoff = 1; |
|
380 linger.l_linger = arg; |
|
381 } else { |
|
382 linger.l_onoff = 0; |
|
383 linger.l_linger = 0; |
|
384 } |
|
385 } else { |
|
386 parg = (void *)&arg; |
|
387 arglen = sizeof(arg); |
|
388 } |
|
389 |
|
390 if (setsockopt(fd, klevel, kopt, parg, arglen) < 0) { |
|
391 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", |
|
392 "sun_nio_ch_SctpNet.setIntOption0"); |
|
393 } |
|
394 } |
|
395 |
|
396 /* |
|
397 * Class: sun_nio_ch_SctpNet |
|
398 * Method: getIntOption0 |
|
399 * Signature: (II)I |
|
400 */ |
|
401 JNIEXPORT int JNICALL Java_sun_nio_ch_SctpNet_getIntOption0 |
|
402 (JNIEnv *env, jclass klass, jint fd, jint opt) { |
|
403 int klevel, kopt; |
|
404 int result; |
|
405 struct linger linger; |
|
406 void *arg; |
|
407 unsigned int arglen; |
|
408 |
|
409 if (mapSocketOption(opt, &klevel, &kopt) < 0) { |
|
410 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", |
|
411 "Unsupported socket option"); |
|
412 return -1; |
|
413 } |
|
414 |
|
415 if (opt == sun_nio_ch_SctpStdSocketOption_SO_LINGER) { |
|
416 arg = (void *)&linger; |
|
417 arglen = sizeof(linger); |
|
418 } else { |
|
419 arg = (void *)&result; |
|
420 arglen = sizeof(result); |
|
421 } |
|
422 |
|
423 if (getsockopt(fd, klevel, kopt, arg, &arglen) < 0) { |
|
424 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", |
|
425 "sun.nio.ch.Net.getIntOption"); |
|
426 return -1; |
|
427 } |
|
428 |
|
429 if (opt == sun_nio_ch_SctpStdSocketOption_SO_LINGER) |
|
430 return linger.l_onoff ? linger.l_linger : -1; |
|
431 else |
|
432 return result; |
|
433 } |
|
434 |
|
435 /* |
|
436 * Class: sun_nio_ch_SctpNet |
|
437 * Method: getPrimAddrOption0 |
|
438 * Signature: (II)Ljava/net/SocketAddress; |
|
439 */ |
|
440 JNIEXPORT jobject JNICALL Java_sun_nio_ch_SctpNet_getPrimAddrOption0 |
|
441 (JNIEnv *env, jclass klass, jint fd, jint assocId) { |
|
442 struct sctp_setprim prim; |
|
443 struct sockaddr_storage ss; |
|
444 int ss_len = sizeof(ss); |
|
445 unsigned int prim_len = sizeof(prim); |
|
446 |
|
447 prim.ssp_assoc_id = assocId; |
|
448 prim.ssp_addr = ss; |
|
449 |
|
450 if (getsockopt(fd, IPPROTO_SCTP, SCTP_PRIMARY_ADDR, &prim, &prim_len) < 0) { |
|
451 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", |
|
452 "sun.nio.ch.SctpNet.getPrimAddrOption0"); |
|
453 return NULL; |
|
454 } |
|
455 |
|
456 return SockAddrToInetSocketAddress(env, (struct sockaddr*)&ss); |
|
457 } |
|
458 |
|
459 /* |
|
460 * Class: sun_nio_ch_SctpNet |
|
461 * Method: setPrimAddrOption0 |
|
462 * Signature: (IILjava/net/InetAddress;I)V |
|
463 */ |
|
464 JNIEXPORT void JNICALL Java_sun_nio_ch_SctpNet_setPrimAddrOption0 |
|
465 (JNIEnv *env, jclass klass, jint fd, jint assocId, jobject iaObj, jint port) { |
|
466 struct sctp_setprim prim; |
|
467 struct sockaddr_storage ss; |
|
468 int ss_len = sizeof(ss); |
|
469 |
|
470 if (NET_InetAddressToSockaddr(env, iaObj, port, (struct sockaddr *)&ss, |
|
471 &ss_len, JNI_TRUE) != 0) { |
|
472 return; |
|
473 } |
|
474 |
|
475 prim.ssp_assoc_id = assocId; |
|
476 prim.ssp_addr = ss; |
|
477 |
|
478 if (setsockopt(fd, IPPROTO_SCTP, SCTP_PRIMARY_ADDR, &prim, sizeof(prim)) < 0) { |
|
479 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", |
|
480 "sun.nio.ch.SctpNet.setPrimAddrOption0"); |
|
481 } |
|
482 } |
|
483 |
|
484 /* |
|
485 * Class: sun_nio_ch_SctpNet |
|
486 * Method: setPeerPrimAddrOption0 |
|
487 * Signature: (IILjava/net/InetAddress;I)V |
|
488 */ |
|
489 JNIEXPORT void JNICALL Java_sun_nio_ch_SctpNet_setPeerPrimAddrOption0 |
|
490 (JNIEnv *env, jclass klass, jint fd, jint assocId, jobject iaObj, jint port) { |
|
491 struct sctp_setpeerprim prim; |
|
492 struct sockaddr_storage ss; |
|
493 int ss_len = sizeof(ss); |
|
494 |
|
495 if (NET_InetAddressToSockaddr(env, iaObj, port, (struct sockaddr *)&ss, |
|
496 &ss_len, JNI_TRUE) != 0) { |
|
497 return; |
|
498 } |
|
499 |
|
500 prim.sspp_assoc_id = assocId; |
|
501 prim.sspp_addr = ss; |
|
502 |
|
503 if (setsockopt(fd, IPPROTO_SCTP, SCTP_SET_PEER_PRIMARY_ADDR, &prim, |
|
504 sizeof(prim)) < 0) { |
|
505 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", |
|
506 "sun.nio.ch.SctpNet.setPeerPrimAddrOption0"); |
|
507 } |
|
508 } |
|
509 |
|
510 /* |
|
511 * Class: sun_nio_ch_SctpNet |
|
512 * Method: getInitMsgOption0 |
|
513 * Signature: (I[I)V |
|
514 */ |
|
515 JNIEXPORT void JNICALL Java_sun_nio_ch_SctpNet_getInitMsgOption0 |
|
516 (JNIEnv *env, jclass klass, jint fd, jintArray retVal) { |
|
517 struct sctp_initmsg sctp_initmsg; |
|
518 unsigned int sim_len = sizeof(sctp_initmsg); |
|
519 int vals[2]; |
|
520 |
|
521 if (getsockopt(fd, IPPROTO_SCTP, SCTP_INITMSG, &sctp_initmsg, |
|
522 &sim_len) < 0) { |
|
523 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", |
|
524 "sun.nio.ch.SctpNet.getInitMsgOption0"); |
|
525 return; |
|
526 } |
|
527 |
|
528 vals[0] = sctp_initmsg.sinit_max_instreams; |
|
529 vals[1] = sctp_initmsg.sinit_num_ostreams; |
|
530 (*env)->SetIntArrayRegion(env, retVal, 0, 2, vals); |
|
531 } |
|
532 |
|
533 /* |
|
534 * Class: sun_nio_ch_SctpNet |
|
535 * Method: setInitMsgOption0 |
|
536 * Signature: (III)V |
|
537 */ |
|
538 JNIEXPORT void JNICALL Java_sun_nio_ch_SctpNet_setInitMsgOption0 |
|
539 (JNIEnv *env, jclass klass, jint fd, jint inArg, jint outArg) { |
|
540 struct sctp_initmsg sctp_initmsg; |
|
541 |
|
542 sctp_initmsg.sinit_max_instreams = (unsigned int)inArg; |
|
543 sctp_initmsg.sinit_num_ostreams = (unsigned int)outArg; |
|
544 sctp_initmsg.sinit_max_attempts = 0; // default |
|
545 sctp_initmsg.sinit_max_init_timeo = 0; // default |
|
546 |
|
547 if (setsockopt(fd, IPPROTO_SCTP, SCTP_INITMSG, &sctp_initmsg, |
|
548 sizeof(sctp_initmsg)) < 0) { |
|
549 JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", |
|
550 "sun.nio.ch.SctpNet.setInitMsgOption0"); |
|
551 } |
|
552 } |
|
553 |
|
554 /* |
|
555 * Class: sun_nio_ch_SctpNet |
|
556 * Method: shutdown0 |
|
557 * Signature: (II)V |
|
558 */ |
|
559 JNIEXPORT void JNICALL Java_sun_nio_ch_SctpNet_shutdown0 |
|
560 (JNIEnv *env, jclass klass, jint fd, jint assocId) { |
|
561 int rv; |
|
562 struct msghdr msg[1]; |
|
563 struct iovec iov[1]; |
|
564 int cbuf_size = CMSG_SPACE(sizeof (struct sctp_sndrcvinfo)); |
|
565 char cbuf[CMSG_SPACE(sizeof (struct sctp_sndrcvinfo))]; |
|
566 struct cmsghdr* cmsg; |
|
567 struct sctp_sndrcvinfo *sri; |
|
568 |
|
569 /* SctpSocketChannel */ |
|
570 if (assocId < 0) { |
|
571 shutdown(fd, SHUT_WR); |
|
572 return; |
|
573 } |
|
574 |
|
575 memset(msg, 0, sizeof (*msg)); |
|
576 memset(cbuf, 0, cbuf_size); |
|
577 msg->msg_name = NULL; |
|
578 msg->msg_namelen = 0; |
|
579 iov->iov_base = NULL; |
|
580 iov->iov_len = 0; |
|
581 msg->msg_iov = iov; |
|
582 msg->msg_iovlen = 1; |
|
583 msg->msg_control = cbuf; |
|
584 msg->msg_controllen = cbuf_size; |
|
585 msg->msg_flags = 0; |
|
586 |
|
587 cmsg = CMSG_FIRSTHDR(msg); |
|
588 cmsg->cmsg_level = IPPROTO_SCTP; |
|
589 cmsg->cmsg_type = SCTP_SNDRCV; |
|
590 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); |
|
591 |
|
592 /* Initialize the payload: */ |
|
593 sri = (struct sctp_sndrcvinfo*) CMSG_DATA(cmsg); |
|
594 memset(sri, 0, sizeof (*sri)); |
|
595 |
|
596 if (assocId > 0) { |
|
597 sri->sinfo_assoc_id = assocId; |
|
598 } |
|
599 |
|
600 sri->sinfo_flags = sri->sinfo_flags | SCTP_EOF; |
|
601 |
|
602 /* Sum of the length of all control messages in the buffer. */ |
|
603 msg->msg_controllen = cmsg->cmsg_len; |
|
604 |
|
605 if ((rv = sendmsg(fd, msg, 0)) < 0) { |
|
606 handleSocketError(env, errno); |
|
607 } |
|
608 } |
|
609 |