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