1 /* 2 * Copyright (c) 2009, 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 <stdlib.h> 27 #include <string.h> 28 #include "Sctp.h" 29 30 #include "jni.h" 31 #include "nio_util.h" 32 #include "nio.h" 33 #include "net_util.h" 34 #include "net_util_md.h" 35 #include "sun_nio_ch_SctpNet.h" 36 #include "sun_nio_ch_SctpChannelImpl.h" 37 #include "sun_nio_ch_SctpAssocChange.h" 38 #include "sun_nio_ch_SctpResultContainer.h" 39 #include "sun_nio_ch_SctpPeerAddrChange.h" 40 41 /* sizeof(union sctp_notification */ 42 #define NOTIFICATION_BUFFER_SIZE 280 43 44 #define MESSAGE_IMPL_CLASS "sun/nio/ch/SctpMessageInfoImpl" 45 #define RESULT_CONTAINER_CLASS "sun/nio/ch/SctpResultContainer" 46 #define SEND_FAILED_CLASS "sun/nio/ch/SctpSendFailed" 47 #define ASSOC_CHANGE_CLASS "sun/nio/ch/SctpAssocChange" 48 #define PEER_CHANGE_CLASS "sun/nio/ch/SctpPeerAddrChange" 49 #define SHUTDOWN_CLASS "sun/nio/ch/SctpShutdown" 50 51 struct controlData { 52 int assocId; 53 unsigned short streamNumber; 54 jboolean unordered; 55 unsigned int ppid; 56 }; 57 58 static jclass smi_class; /* sun.nio.ch.SctpMessageInfoImpl */ 59 static jmethodID smi_ctrID; /* sun.nio.ch.SctpMessageInfoImpl.<init> */ 60 static jfieldID src_valueID; /* sun.nio.ch.SctpResultContainer.value */ 61 static jfieldID src_typeID; /* sun.nio.ch.SctpResultContainer.type */ 62 static jclass ssf_class; /* sun.nio.ch.SctpSendFailed */ 63 static jmethodID ssf_ctrID; /* sun.nio.ch.SctpSendFailed.<init> */ 64 static jclass sac_class; /* sun.nio.ch.SctpAssociationChanged */ 65 static jmethodID sac_ctrID; /* sun.nio.ch.SctpAssociationChanged.<init> */ 66 static jclass spc_class; /* sun.nio.ch.SctpPeerAddressChanged */ 67 static jmethodID spc_ctrID; /* sun.nio.ch.SctpPeerAddressChanged.<init> */ 68 static jclass ss_class; /* sun.nio.ch.SctpShutdown */ 69 static jmethodID ss_ctrID; /* sun.nio.ch.SctpShutdown.<init> */ 70 static jfieldID isa_addrID; /* java.net.InetSocketAddress.addr */ 71 static jfieldID isa_portID; /* java.net.InetSocketAddress.port */ 72 73 /* defined in SctpNet.c */ 74 jobject SockAddrToInetSocketAddress(JNIEnv* env, struct sockaddr* addr); 75 76 /* use SocketChannelImpl's checkConnect implementation */ 77 extern jint Java_sun_nio_ch_SocketChannelImpl_checkConnect(JNIEnv* env, 78 jobject this, jobject fdo, jboolean block, jboolean ready); 79 80 /* 81 * Class: sun_nio_ch_SctpChannelImpl 82 * Method: initIDs 83 * Signature: ()V 84 */ 85 JNIEXPORT void JNICALL Java_sun_nio_ch_SctpChannelImpl_initIDs 86 (JNIEnv *env, jclass klass) { 87 jclass cls; 88 89 /* SctpMessageInfoImpl */ 90 cls = (*env)->FindClass(env, MESSAGE_IMPL_CLASS); 91 CHECK_NULL(cls); 92 smi_class = (*env)->NewGlobalRef(env, cls); 93 CHECK_NULL(smi_class); 94 smi_ctrID = (*env)->GetMethodID(env, cls, "<init>", 95 "(ILjava/net/SocketAddress;IIZZI)V"); 96 CHECK_NULL(smi_ctrID); 97 98 /* SctpResultContainer */ 99 cls = (*env)->FindClass(env, RESULT_CONTAINER_CLASS); 100 CHECK_NULL(cls); 101 src_valueID = (*env)->GetFieldID(env, cls, "value", "Ljava/lang/Object;"); 102 CHECK_NULL(src_valueID); 103 src_typeID = (*env)->GetFieldID(env, cls, "type", "I"); 104 CHECK_NULL(src_typeID); 105 106 /* SctpSendFailed */ 107 cls = (*env)->FindClass(env, SEND_FAILED_CLASS); 108 CHECK_NULL(cls); 109 ssf_class = (*env)->NewGlobalRef(env, cls); 110 CHECK_NULL(ssf_class); 111 ssf_ctrID = (*env)->GetMethodID(env, cls, "<init>", 112 "(ILjava/net/SocketAddress;Ljava/nio/ByteBuffer;II)V"); 113 CHECK_NULL(ssf_ctrID); 114 115 /* SctpAssocChange */ 116 cls = (*env)->FindClass(env, ASSOC_CHANGE_CLASS); 117 CHECK_NULL(cls); 118 sac_class = (*env)->NewGlobalRef(env, cls); 119 CHECK_NULL(sac_class); 120 sac_ctrID = (*env)->GetMethodID(env, cls, "<init>", "(IIII)V"); 121 CHECK_NULL(sac_ctrID); 122 123 /* SctpPeerAddrChange */ 124 cls = (*env)->FindClass(env, PEER_CHANGE_CLASS); 125 CHECK_NULL(cls); 126 spc_class = (*env)->NewGlobalRef(env, cls); 127 CHECK_NULL(spc_class); 128 spc_ctrID = (*env)->GetMethodID(env, cls, "<init>", 129 "(ILjava/net/SocketAddress;I)V"); 130 CHECK_NULL(spc_ctrID); 131 132 /* sun.nio.ch.SctpShutdown */ 133 cls = (*env)->FindClass(env, SHUTDOWN_CLASS); 134 CHECK_NULL(cls); 135 ss_class = (*env)->NewGlobalRef(env, cls); 136 CHECK_NULL(ss_class); 137 ss_ctrID = (*env)->GetMethodID(env, cls, "<init>", "(I)V"); 138 CHECK_NULL(ss_ctrID); 139 140 /* InetSocketAddress */ 141 cls = (*env)->FindClass(env, "java/net/InetSocketAddress"); 142 CHECK_NULL(cls); 143 isa_addrID = (*env)->GetFieldID(env, cls, "addr", "Ljava/net/InetAddress;"); 144 CHECK_NULL(isa_addrID); 145 isa_portID = (*env)->GetFieldID(env, cls, "port", "I"); 146 } 147 148 void getControlData 149 (struct msghdr* msg, struct controlData* cdata) { 150 struct cmsghdr* cmsg; 151 152 for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) { 153 if (cmsg->cmsg_level == IPPROTO_SCTP && cmsg->cmsg_type == SCTP_SNDRCV) { 154 struct sctp_sndrcvinfo *sri; 155 156 sri = (struct sctp_sndrcvinfo *) CMSG_DATA(cmsg); 157 cdata->assocId = sri->sinfo_assoc_id; 158 cdata->streamNumber = sri->sinfo_stream; 159 cdata->unordered = (sri->sinfo_flags & SCTP_UNORDERED) ? JNI_TRUE : 160 JNI_FALSE; 161 cdata->ppid = ntohl(sri->sinfo_ppid); 162 163 return; 164 } 165 } 166 return; 167 } 168 169 void setControlData 170 (struct msghdr* msg, struct controlData* cdata) { 171 struct cmsghdr* cmsg; 172 struct sctp_sndrcvinfo *sri; 173 174 cmsg = CMSG_FIRSTHDR(msg); 175 cmsg->cmsg_level = IPPROTO_SCTP; 176 cmsg->cmsg_type = SCTP_SNDRCV; 177 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); 178 179 /* Initialize the payload */ 180 sri = (struct sctp_sndrcvinfo*) CMSG_DATA(cmsg); 181 memset(sri, 0, sizeof (*sri)); 182 183 if (cdata->streamNumber > 0) { 184 sri->sinfo_stream = cdata->streamNumber; 185 } 186 if (cdata->assocId > 0) { 187 sri->sinfo_assoc_id = cdata->assocId; 188 } 189 if (cdata->unordered == JNI_TRUE) { 190 sri->sinfo_flags = sri->sinfo_flags | SCTP_UNORDERED; 191 } 192 193 if (cdata->ppid > 0) { 194 sri->sinfo_ppid = htonl(cdata->ppid); 195 } 196 197 /* Sum of the length of all control messages in the buffer. */ 198 msg->msg_controllen = cmsg->cmsg_len; 199 } 200 201 // TODO: test: can create send failed without any data? if so need to 202 // update API so that buffer can be null if no data. 203 void handleSendFailed 204 (JNIEnv* env, int fd, jobject resultContainerObj, struct sctp_send_failed *ssf, 205 int read, jboolean isEOR, struct sockaddr* sap) { 206 jobject bufferObj = NULL, resultObj, isaObj; 207 char *addressP; 208 struct sctp_sndrcvinfo *sri; 209 int remaining, dataLength; 210 211 /* the actual undelivered message data is directly after the ssf */ 212 int dataOffset = sizeof(struct sctp_send_failed); 213 214 sri = (struct sctp_sndrcvinfo*) &ssf->ssf_info; 215 216 /* the number of bytes remaining to be read in the sctp_send_failed notif*/ 217 remaining = ssf->ssf_length - read; 218 219 /* the size of the actual undelivered message */ 220 dataLength = ssf->ssf_length - dataOffset; 221 222 /* retrieved address from sockaddr */ 223 isaObj = SockAddrToInetSocketAddress(env, sap); 224 225 /* data retrieved from sff_data */ 226 if (dataLength > 0) { 227 struct iovec iov[1]; 228 struct msghdr msg[1]; 229 int rv, alreadyRead; 230 char *dataP = (char*) ssf; 231 dataP += dataOffset; 232 233 if ((addressP = malloc(dataLength)) == NULL) { 234 JNU_ThrowOutOfMemoryError(env, "handleSendFailed"); 235 return; 236 } 237 238 memset(msg, 0, sizeof (*msg)); 239 msg->msg_iov = iov; 240 msg->msg_iovlen = 1; 241 242 bufferObj = (*env)->NewDirectByteBuffer(env, addressP, dataLength); 243 CHECK_NULL(bufferObj); 244 245 alreadyRead = read - dataOffset; 246 if (alreadyRead > 0) { 247 memcpy(addressP, /*ssf->ssf_data*/ dataP, alreadyRead); 248 iov->iov_base = addressP + alreadyRead; 249 iov->iov_len = dataLength - alreadyRead; 250 } else { 251 iov->iov_base = addressP; 252 iov->iov_len = dataLength; 253 } 254 255 if (remaining > 0) { 256 if ((rv = recvmsg(fd, msg, 0)) < 0) { 257 handleSocketError(env, errno); 258 return; 259 } 260 261 if (rv != (dataLength - alreadyRead) || !(msg->msg_flags & MSG_EOR)) { 262 //TODO: assert false: "should not reach here"; 263 return; 264 } 265 // TODO: Set and document (in API) buffers position. 266 } 267 } 268 269 /* create SctpSendFailed */ 270 resultObj = (*env)->NewObject(env, ssf_class, ssf_ctrID, ssf->ssf_assoc_id, 271 isaObj, bufferObj, ssf->ssf_error, sri->sinfo_stream); 272 CHECK_NULL(resultObj); 273 (*env)->SetObjectField(env, resultContainerObj, src_valueID, resultObj); 274 (*env)->SetIntField(env, resultContainerObj, src_typeID, 275 sun_nio_ch_SctpResultContainer_SEND_FAILED); 276 } 277 278 void handleAssocChange 279 (JNIEnv* env, jobject resultContainerObj, struct sctp_assoc_change *sac) { 280 jobject resultObj; 281 int state = 0; 282 283 switch (sac->sac_state) { 284 case SCTP_COMM_UP : 285 state = sun_nio_ch_SctpAssocChange_SCTP_COMM_UP; 286 break; 287 case SCTP_COMM_LOST : 288 state = sun_nio_ch_SctpAssocChange_SCTP_COMM_LOST; 289 break; 290 case SCTP_RESTART : 291 state = sun_nio_ch_SctpAssocChange_SCTP_RESTART; 292 break; 293 case SCTP_SHUTDOWN_COMP : 294 state = sun_nio_ch_SctpAssocChange_SCTP_SHUTDOWN; 295 break; 296 case SCTP_CANT_STR_ASSOC : 297 state = sun_nio_ch_SctpAssocChange_SCTP_CANT_START; 298 } 299 300 /* create SctpAssociationChanged */ 301 resultObj = (*env)->NewObject(env, sac_class, sac_ctrID, sac->sac_assoc_id, 302 state, sac->sac_outbound_streams, sac->sac_inbound_streams); 303 CHECK_NULL(resultObj); 304 (*env)->SetObjectField(env, resultContainerObj, src_valueID, resultObj); 305 (*env)->SetIntField(env, resultContainerObj, src_typeID, 306 sun_nio_ch_SctpResultContainer_ASSOCIATION_CHANGED); 307 } 308 309 void handleShutdown 310 (JNIEnv* env, jobject resultContainerObj, struct sctp_shutdown_event* sse) { 311 /* create SctpShutdown */ 312 jobject resultObj = (*env)->NewObject(env, ss_class, ss_ctrID, sse->sse_assoc_id); 313 CHECK_NULL(resultObj); 314 (*env)->SetObjectField(env, resultContainerObj, src_valueID, resultObj); 315 (*env)->SetIntField(env, resultContainerObj, src_typeID, 316 sun_nio_ch_SctpResultContainer_SHUTDOWN); 317 } 318 319 void handlePeerAddrChange 320 (JNIEnv* env, jobject resultContainerObj, struct sctp_paddr_change* spc) { 321 int event = 0; 322 jobject addressObj, resultObj; 323 unsigned int state = spc->spc_state; 324 325 switch (state) { 326 case SCTP_ADDR_AVAILABLE : 327 event = sun_nio_ch_SctpPeerAddrChange_SCTP_ADDR_AVAILABLE; 328 break; 329 case SCTP_ADDR_UNREACHABLE : 330 event = sun_nio_ch_SctpPeerAddrChange_SCTP_ADDR_UNREACHABLE; 331 break; 332 case SCTP_ADDR_REMOVED : 333 event = sun_nio_ch_SctpPeerAddrChange_SCTP_ADDR_REMOVED; 334 break; 335 case SCTP_ADDR_ADDED : 336 event = sun_nio_ch_SctpPeerAddrChange_SCTP_ADDR_ADDED; 337 break; 338 case SCTP_ADDR_MADE_PRIM : 339 event = sun_nio_ch_SctpPeerAddrChange_SCTP_ADDR_MADE_PRIM; 340 #ifndef __solaris__ /* Solaris currently doesn't support SCTP_ADDR_CONFIRMED */ 341 break; 342 case SCTP_ADDR_CONFIRMED : 343 event = sun_nio_ch_SctpPeerAddrChange_SCTP_ADDR_CONFIRMED; 344 #endif /* __solaris__ */ 345 } 346 347 addressObj = SockAddrToInetSocketAddress(env, (struct sockaddr*)&spc->spc_aaddr); 348 349 /* create SctpPeerAddressChanged */ 350 resultObj = (*env)->NewObject(env, spc_class, spc_ctrID, spc->spc_assoc_id, 351 addressObj, event); 352 CHECK_NULL(resultObj); 353 (*env)->SetObjectField(env, resultContainerObj, src_valueID, resultObj); 354 (*env)->SetIntField(env, resultContainerObj, src_typeID, 355 sun_nio_ch_SctpResultContainer_PEER_ADDRESS_CHANGED); 356 } 357 358 void handleUninteresting 359 (union sctp_notification *snp) { 360 //fprintf(stdout,"\nNative: handleUninterestingNotification: Receive notification type [%u]", snp->sn_header.sn_type); 361 } 362 363 /** 364 * Handle notifications from the SCTP stack. 365 * Returns JNI_TRUE if the notification is one that is of interest to the 366 * Java API, otherwise JNI_FALSE. 367 */ 368 jboolean handleNotification 369 (JNIEnv* env, int fd, jobject resultContainerObj, union sctp_notification* snp, 370 int read, jboolean isEOR, struct sockaddr* sap) { 371 switch (snp->sn_header.sn_type) { 372 case SCTP_SEND_FAILED: 373 handleSendFailed(env, fd, resultContainerObj, &snp->sn_send_failed, 374 read, isEOR, sap); 375 return JNI_TRUE; 376 case SCTP_ASSOC_CHANGE: 377 handleAssocChange(env, resultContainerObj, &snp->sn_assoc_change); 378 return JNI_TRUE; 379 case SCTP_SHUTDOWN_EVENT: 380 handleShutdown(env, resultContainerObj, &snp->sn_shutdown_event); 381 return JNI_TRUE; 382 case SCTP_PEER_ADDR_CHANGE: 383 handlePeerAddrChange(env, resultContainerObj, &snp->sn_paddr_change); 384 return JNI_TRUE; 385 default : 386 /* the Java API is not interested in this event, maybe we are? */ 387 handleUninteresting(snp); 388 } 389 return JNI_FALSE; 390 } 391 392 void handleMessage 393 (JNIEnv* env, jobject resultContainerObj, struct msghdr* msg,int read, 394 jboolean isEOR, struct sockaddr* sap) { 395 jobject isa, resultObj; 396 struct controlData cdata[1]; 397 398 if (read == 0) { 399 /* we reached EOF */ 400 read = -1; 401 } 402 403 isa = SockAddrToInetSocketAddress(env, sap); 404 getControlData(msg, cdata); 405 406 /* create SctpMessageInfoImpl */ 407 resultObj = (*env)->NewObject(env, smi_class, smi_ctrID, cdata->assocId, 408 isa, read, cdata->streamNumber, 409 isEOR ? JNI_TRUE : JNI_FALSE, 410 cdata->unordered, cdata->ppid); 411 CHECK_NULL(resultObj); 412 (*env)->SetObjectField(env, resultContainerObj, src_valueID, resultObj); 413 (*env)->SetIntField(env, resultContainerObj, src_typeID, 414 sun_nio_ch_SctpResultContainer_MESSAGE); 415 } 416 417 /* 418 * Class: sun_nio_ch_SctpChannelImpl 419 * Method: receive0 420 * Signature: (ILsun/nio/ch/SctpResultContainer;JIZ)I 421 */ 422 JNIEXPORT jint JNICALL Java_sun_nio_ch_SctpChannelImpl_receive0 423 (JNIEnv *env, jclass klass, jint fd, jobject resultContainerObj, 424 jlong address, jint length, jboolean peek) { 425 SOCKADDR sa; 426 int sa_len = sizeof(sa); 427 ssize_t rv = 0; 428 jlong *addr = jlong_to_ptr(address); 429 struct iovec iov[1]; 430 struct msghdr msg[1]; 431 char cbuf[CMSG_SPACE(sizeof (struct sctp_sndrcvinfo))]; 432 int flags = peek == JNI_TRUE ? MSG_PEEK : 0; 433 434 /* Set up the msghdr structure for receiving */ 435 memset(msg, 0, sizeof (*msg)); 436 msg->msg_name = &sa; 437 msg->msg_namelen = sa_len; 438 iov->iov_base = addr; 439 iov->iov_len = length; 440 msg->msg_iov = iov; 441 msg->msg_iovlen = 1; 442 msg->msg_control = cbuf; 443 msg->msg_controllen = sizeof(cbuf); 444 msg->msg_flags = 0; 445 446 do { 447 if ((rv = recvmsg(fd, msg, flags)) < 0) { 448 if (errno == EWOULDBLOCK) { 449 return IOS_UNAVAILABLE; 450 } else if (errno == EINTR) { 451 return IOS_INTERRUPTED; 452 453 #ifdef __linux__ 454 } else if (errno == ENOTCONN) { 455 /* ENOTCONN when EOF reached */ 456 rv = 0; 457 /* there will be no control data */ 458 msg->msg_controllen = 0; 459 #endif /* __linux__ */ 460 461 } else { 462 handleSocketError(env, errno); 463 return 0; 464 } 465 } 466 467 if (msg->msg_flags & MSG_NOTIFICATION) { 468 char *bufp = (char*)addr; 469 union sctp_notification *snp; 470 471 if (!(msg->msg_flags & MSG_EOR) && length < NOTIFICATION_BUFFER_SIZE) { 472 char buf[NOTIFICATION_BUFFER_SIZE]; 473 int rvSAVE = rv; 474 memcpy(buf, addr, rv); 475 iov->iov_base = buf + rv; 476 iov->iov_len = NOTIFICATION_BUFFER_SIZE - rv; 477 if ((rv = recvmsg(fd, msg, flags)) < 0) { 478 handleSocketError(env, errno); 479 return 0; 480 } 481 bufp = buf; 482 rv += rvSAVE; 483 } 484 snp = (union sctp_notification *) bufp; 485 if (handleNotification(env, fd, resultContainerObj, snp, rv, 486 (msg->msg_flags & MSG_EOR), 487 (struct sockaddr*)&sa ) == JNI_TRUE) { 488 /* We have received a notification that is of interest to 489 to the Java API. The appropriate notification will be 490 set in the result container. */ 491 return 0; 492 } 493 494 // set iov back to addr, and reset msg_controllen 495 iov->iov_base = addr; 496 iov->iov_len = length; 497 msg->msg_control = cbuf; 498 msg->msg_controllen = sizeof(cbuf); 499 } 500 } while (msg->msg_flags & MSG_NOTIFICATION); 501 502 handleMessage(env, resultContainerObj, msg, rv, 503 (msg->msg_flags & MSG_EOR), (struct sockaddr*)&sa); 504 return rv; 505 } 506 507 /* 508 * Class: sun_nio_ch_SctpChannelImpl 509 * Method: send0 510 * Signature: (IJILjava/net/SocketAddress;IIZI)I 511 */ 512 JNIEXPORT jint JNICALL Java_sun_nio_ch_SctpChannelImpl_send0 513 (JNIEnv *env, jclass klass, jint fd, jlong address, jint length, 514 jobject saTarget, jint assocId, jint streamNumber, jboolean unordered, 515 jint ppid) { 516 SOCKADDR sa; 517 int sa_len = sizeof(sa); 518 ssize_t rv = 0; 519 jlong *addr = jlong_to_ptr(address); 520 struct iovec iov[1]; 521 struct msghdr msg[1]; 522 int cbuf_size = CMSG_SPACE(sizeof (struct sctp_sndrcvinfo)); 523 char cbuf[CMSG_SPACE(sizeof (struct sctp_sndrcvinfo))]; 524 struct controlData cdata[1]; 525 526 /* SctpChannel: 527 * saTarget may contain the preferred address or NULL to use primary, 528 * assocId will always be -1 529 * SctpMultiChannell: 530 * Setup new association, saTarget will contain address, assocId = -1 531 * Association already existing, assocId != -1, saTarget = preferred addr 532 */ 533 if (saTarget != NULL /*&& assocId <= 0*/) { 534 535 jobject targetAddress = (*env)->GetObjectField(env, saTarget, isa_addrID); 536 jint targetPort = (*env)->GetIntField(env, saTarget, isa_portID); 537 538 if (NET_InetAddressToSockaddr(env, targetAddress, targetPort, 539 (struct sockaddr *)&sa, 540 &sa_len, JNI_TRUE) != 0) { 541 return IOS_THROWN; 542 } 543 } else { 544 memset(&sa, '\x0', sa_len); 545 sa_len = 0; 546 } 547 548 /* Set up the msghdr structure for sending */ 549 memset(msg, 0, sizeof (*msg)); 550 memset(cbuf, 0, cbuf_size); 551 msg->msg_name = &sa; 552 msg->msg_namelen = sa_len; 553 iov->iov_base = addr; 554 iov->iov_len = length; 555 msg->msg_iov = iov; 556 msg->msg_iovlen = 1; 557 msg->msg_control = cbuf; 558 msg->msg_controllen = cbuf_size; 559 msg->msg_flags = 0; 560 561 cdata->streamNumber = streamNumber; 562 cdata->assocId = assocId; 563 cdata->unordered = unordered; 564 cdata->ppid = ppid; 565 setControlData(msg, cdata); 566 567 if ((rv = sendmsg(fd, msg, 0)) < 0) { 568 if (errno == EWOULDBLOCK) { 569 return IOS_UNAVAILABLE; 570 } else if (errno == EINTR) { 571 return IOS_INTERRUPTED; 572 } else if (errno == EPIPE) { 573 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", 574 "Socket is shutdown for writing"); 575 } else { 576 handleSocketError(env, errno); 577 return 0; 578 } 579 } 580 581 return rv; 582 } 583 584 /* 585 * Class: sun_nio_ch_SctpChannelImpl 586 * Method: checkConnect 587 * Signature: (Ljava/io/FileDescriptor;ZZ)I 588 */ 589 JNIEXPORT jint JNICALL Java_sun_nio_ch_SctpChannelImpl_checkConnect 590 (JNIEnv* env, jobject this, jobject fdo, jboolean block, jboolean ready) { 591 return Java_sun_nio_ch_SocketChannelImpl_checkConnect(env, this, 592 fdo, block, ready); 593 } 594