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