1096N/A/*
2362N/A * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
1096N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1096N/A *
1096N/A * This code is free software; you can redistribute it and/or modify it
1096N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
1096N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
1096N/A *
1096N/A * This code is distributed in the hope that it will be useful, but WITHOUT
1096N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1096N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1096N/A * version 2 for more details (a copy is included in the LICENSE file that
1096N/A * accompanied this code).
1096N/A *
1096N/A * You should have received a copy of the GNU General Public License version
1096N/A * 2 along with this work; if not, write to the Free Software Foundation,
1096N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1096N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
1096N/A */
1096N/A
1096N/A#include <stdlib.h>
1096N/A#include <string.h>
1096N/A#include "Sctp.h"
1096N/A
1096N/A#include "jni.h"
1096N/A#include "nio_util.h"
1096N/A#include "nio.h"
1096N/A#include "net_util.h"
1096N/A#include "net_util_md.h"
1096N/A#include "sun_nio_ch_SctpNet.h"
1096N/A#include "sun_nio_ch_SctpChannelImpl.h"
1096N/A#include "sun_nio_ch_SctpAssocChange.h"
1096N/A#include "sun_nio_ch_SctpResultContainer.h"
1096N/A#include "sun_nio_ch_SctpPeerAddrChange.h"
1096N/A
1096N/A/* sizeof(union sctp_notification */
1096N/A#define NOTIFICATION_BUFFER_SIZE 280
1096N/A
1096N/A#define MESSAGE_IMPL_CLASS "sun/nio/ch/SctpMessageInfoImpl"
1096N/A#define RESULT_CONTAINER_CLASS "sun/nio/ch/SctpResultContainer"
1096N/A#define SEND_FAILED_CLASS "sun/nio/ch/SctpSendFailed"
1096N/A#define ASSOC_CHANGE_CLASS "sun/nio/ch/SctpAssocChange"
1096N/A#define PEER_CHANGE_CLASS "sun/nio/ch/SctpPeerAddrChange"
1096N/A#define SHUTDOWN_CLASS "sun/nio/ch/SctpShutdown"
1096N/A
1096N/Astruct controlData {
1096N/A int assocId;
1096N/A unsigned short streamNumber;
1096N/A jboolean unordered;
1096N/A unsigned int ppid;
1096N/A};
1096N/A
1096N/Astatic jclass smi_class; /* sun.nio.ch.SctpMessageInfoImpl */
1096N/Astatic jmethodID smi_ctrID; /* sun.nio.ch.SctpMessageInfoImpl.<init> */
1096N/Astatic jfieldID src_valueID; /* sun.nio.ch.SctpResultContainer.value */
1096N/Astatic jfieldID src_typeID; /* sun.nio.ch.SctpResultContainer.type */
1096N/Astatic jclass ssf_class; /* sun.nio.ch.SctpSendFailed */
1096N/Astatic jmethodID ssf_ctrID; /* sun.nio.ch.SctpSendFailed.<init> */
1096N/Astatic jclass sac_class; /* sun.nio.ch.SctpAssociationChanged */
1096N/Astatic jmethodID sac_ctrID; /* sun.nio.ch.SctpAssociationChanged.<init> */
1096N/Astatic jclass spc_class; /* sun.nio.ch.SctpPeerAddressChanged */
1096N/Astatic jmethodID spc_ctrID; /* sun.nio.ch.SctpPeerAddressChanged.<init> */
1096N/Astatic jclass ss_class; /* sun.nio.ch.SctpShutdown */
1096N/Astatic jmethodID ss_ctrID; /* sun.nio.ch.SctpShutdown.<init> */
1096N/A
1096N/A/* defined in SctpNet.c */
1096N/Ajobject SockAddrToInetSocketAddress(JNIEnv* env, struct sockaddr* addr);
1096N/A
1096N/A/* use SocketChannelImpl's checkConnect implementation */
1096N/Aextern jint Java_sun_nio_ch_SocketChannelImpl_checkConnect(JNIEnv* env,
1096N/A jobject this, jobject fdo, jboolean block, jboolean ready);
1096N/A
1096N/A/*
1096N/A * Class: sun_nio_ch_SctpChannelImpl
1096N/A * Method: initIDs
1096N/A * Signature: ()V
1096N/A */
1096N/AJNIEXPORT void JNICALL Java_sun_nio_ch_SctpChannelImpl_initIDs
1096N/A (JNIEnv *env, jclass klass) {
1096N/A jclass cls;
1096N/A
1096N/A /* SctpMessageInfoImpl */
1096N/A cls = (*env)->FindClass(env, MESSAGE_IMPL_CLASS);
1096N/A CHECK_NULL(cls);
1096N/A smi_class = (*env)->NewGlobalRef(env, cls);
1096N/A CHECK_NULL(smi_class);
1096N/A smi_ctrID = (*env)->GetMethodID(env, cls, "<init>",
1096N/A "(ILjava/net/SocketAddress;IIZZI)V");
1096N/A CHECK_NULL(smi_ctrID);
1096N/A
1096N/A /* SctpResultContainer */
1096N/A cls = (*env)->FindClass(env, RESULT_CONTAINER_CLASS);
1096N/A CHECK_NULL(cls);
1096N/A src_valueID = (*env)->GetFieldID(env, cls, "value", "Ljava/lang/Object;");
1096N/A CHECK_NULL(src_valueID);
1096N/A src_typeID = (*env)->GetFieldID(env, cls, "type", "I");
1096N/A CHECK_NULL(src_typeID);
1096N/A
1096N/A /* SctpSendFailed */
1096N/A cls = (*env)->FindClass(env, SEND_FAILED_CLASS);
1096N/A CHECK_NULL(cls);
1096N/A ssf_class = (*env)->NewGlobalRef(env, cls);
1096N/A CHECK_NULL(ssf_class);
1096N/A ssf_ctrID = (*env)->GetMethodID(env, cls, "<init>",
1096N/A "(ILjava/net/SocketAddress;Ljava/nio/ByteBuffer;II)V");
1096N/A CHECK_NULL(ssf_ctrID);
1096N/A
1096N/A /* SctpAssocChange */
1096N/A cls = (*env)->FindClass(env, ASSOC_CHANGE_CLASS);
1096N/A CHECK_NULL(cls);
1096N/A sac_class = (*env)->NewGlobalRef(env, cls);
1096N/A CHECK_NULL(sac_class);
1096N/A sac_ctrID = (*env)->GetMethodID(env, cls, "<init>", "(IIII)V");
1096N/A CHECK_NULL(sac_ctrID);
1096N/A
1096N/A /* SctpPeerAddrChange */
1096N/A cls = (*env)->FindClass(env, PEER_CHANGE_CLASS);
1096N/A CHECK_NULL(cls);
1096N/A spc_class = (*env)->NewGlobalRef(env, cls);
1096N/A CHECK_NULL(spc_class);
1096N/A spc_ctrID = (*env)->GetMethodID(env, cls, "<init>",
1096N/A "(ILjava/net/SocketAddress;I)V");
1096N/A CHECK_NULL(spc_ctrID);
1096N/A
1096N/A /* sun.nio.ch.SctpShutdown */
1096N/A cls = (*env)->FindClass(env, SHUTDOWN_CLASS);
1096N/A CHECK_NULL(cls);
1096N/A ss_class = (*env)->NewGlobalRef(env, cls);
1096N/A CHECK_NULL(ss_class);
1096N/A ss_ctrID = (*env)->GetMethodID(env, cls, "<init>", "(I)V");
1096N/A CHECK_NULL(ss_ctrID);
1096N/A}
1096N/A
1096N/Avoid getControlData
1096N/A (struct msghdr* msg, struct controlData* cdata) {
1096N/A struct cmsghdr* cmsg;
1096N/A
1096N/A for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) {
1096N/A if (cmsg->cmsg_level == IPPROTO_SCTP && cmsg->cmsg_type == SCTP_SNDRCV) {
1096N/A struct sctp_sndrcvinfo *sri;
1096N/A
1096N/A sri = (struct sctp_sndrcvinfo *) CMSG_DATA(cmsg);
1096N/A cdata->assocId = sri->sinfo_assoc_id;
1096N/A cdata->streamNumber = sri->sinfo_stream;
1096N/A cdata->unordered = (sri->sinfo_flags & SCTP_UNORDERED) ? JNI_TRUE :
1096N/A JNI_FALSE;
1096N/A cdata->ppid = ntohl(sri->sinfo_ppid);
1096N/A
1096N/A return;
1096N/A }
1096N/A }
1096N/A return;
1096N/A}
1096N/A
1096N/Avoid setControlData
1096N/A (struct msghdr* msg, struct controlData* cdata) {
1096N/A struct cmsghdr* cmsg;
1096N/A struct sctp_sndrcvinfo *sri;
1096N/A
1096N/A cmsg = CMSG_FIRSTHDR(msg);
1096N/A cmsg->cmsg_level = IPPROTO_SCTP;
1096N/A cmsg->cmsg_type = SCTP_SNDRCV;
1096N/A cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
1096N/A
1096N/A /* Initialize the payload */
1096N/A sri = (struct sctp_sndrcvinfo*) CMSG_DATA(cmsg);
1096N/A memset(sri, 0, sizeof (*sri));
1096N/A
1096N/A if (cdata->streamNumber > 0) {
1096N/A sri->sinfo_stream = cdata->streamNumber;
1096N/A }
1096N/A if (cdata->assocId > 0) {
1096N/A sri->sinfo_assoc_id = cdata->assocId;
1096N/A }
1096N/A if (cdata->unordered == JNI_TRUE) {
1096N/A sri->sinfo_flags = sri->sinfo_flags | SCTP_UNORDERED;
1096N/A }
1096N/A
1096N/A if (cdata->ppid > 0) {
1096N/A sri->sinfo_ppid = htonl(cdata->ppid);
1096N/A }
1096N/A
1096N/A /* Sum of the length of all control messages in the buffer. */
1096N/A msg->msg_controllen = cmsg->cmsg_len;
1096N/A}
1096N/A
1096N/A// TODO: test: can create send failed without any data? if so need to
1096N/A// update API so that buffer can be null if no data.
1096N/Avoid handleSendFailed
1096N/A (JNIEnv* env, int fd, jobject resultContainerObj, struct sctp_send_failed *ssf,
1096N/A int read, jboolean isEOR, struct sockaddr* sap) {
1096N/A jobject bufferObj = NULL, resultObj, isaObj;
1096N/A char *addressP;
1096N/A struct sctp_sndrcvinfo *sri;
1096N/A int remaining, dataLength;
1096N/A
1096N/A /* the actual undelivered message data is directly after the ssf */
1096N/A int dataOffset = sizeof(struct sctp_send_failed);
1096N/A
1096N/A sri = (struct sctp_sndrcvinfo*) &ssf->ssf_info;
1096N/A
1096N/A /* the number of bytes remaining to be read in the sctp_send_failed notif*/
1096N/A remaining = ssf->ssf_length - read;
1096N/A
1096N/A /* the size of the actual undelivered message */
1096N/A dataLength = ssf->ssf_length - dataOffset;
1096N/A
1096N/A /* retrieved address from sockaddr */
1096N/A isaObj = SockAddrToInetSocketAddress(env, sap);
1096N/A
1096N/A /* data retrieved from sff_data */
1096N/A if (dataLength > 0) {
1096N/A struct iovec iov[1];
1096N/A struct msghdr msg[1];
1096N/A int rv, alreadyRead;
1096N/A char *dataP = (char*) ssf;
1096N/A dataP += dataOffset;
1096N/A
1096N/A if ((addressP = malloc(dataLength)) == NULL) {
1096N/A JNU_ThrowOutOfMemoryError(env, "handleSendFailed");
1096N/A return;
1096N/A }
1096N/A
1096N/A memset(msg, 0, sizeof (*msg));
1096N/A msg->msg_iov = iov;
1096N/A msg->msg_iovlen = 1;
1096N/A
1096N/A bufferObj = (*env)->NewDirectByteBuffer(env, addressP, dataLength);
1096N/A CHECK_NULL(bufferObj);
1096N/A
1096N/A alreadyRead = read - dataOffset;
1096N/A if (alreadyRead > 0) {
1096N/A memcpy(addressP, /*ssf->ssf_data*/ dataP, alreadyRead);
1096N/A iov->iov_base = addressP + alreadyRead;
1096N/A iov->iov_len = dataLength - alreadyRead;
1096N/A } else {
1096N/A iov->iov_base = addressP;
1096N/A iov->iov_len = dataLength;
1096N/A }
1096N/A
1096N/A if (remaining > 0) {
1096N/A if ((rv = recvmsg(fd, msg, 0)) < 0) {
1096N/A handleSocketError(env, errno);
1096N/A return;
1096N/A }
1096N/A
1096N/A if (rv != (dataLength - alreadyRead) || !(msg->msg_flags & MSG_EOR)) {
1096N/A //TODO: assert false: "should not reach here";
1096N/A return;
1096N/A }
1096N/A // TODO: Set and document (in API) buffers position.
1096N/A }
1096N/A }
1096N/A
1096N/A /* create SctpSendFailed */
1096N/A resultObj = (*env)->NewObject(env, ssf_class, ssf_ctrID, ssf->ssf_assoc_id,
1326N/A isaObj, bufferObj, ssf->ssf_error, sri->sinfo_stream);
1096N/A CHECK_NULL(resultObj);
1096N/A (*env)->SetObjectField(env, resultContainerObj, src_valueID, resultObj);
1096N/A (*env)->SetIntField(env, resultContainerObj, src_typeID,
1096N/A sun_nio_ch_SctpResultContainer_SEND_FAILED);
1096N/A}
1096N/A
1096N/Avoid handleAssocChange
1096N/A (JNIEnv* env, jobject resultContainerObj, struct sctp_assoc_change *sac) {
1096N/A jobject resultObj;
1096N/A int state = 0;
1096N/A
1096N/A switch (sac->sac_state) {
1096N/A case SCTP_COMM_UP :
1096N/A state = sun_nio_ch_SctpAssocChange_SCTP_COMM_UP;
1096N/A break;
1096N/A case SCTP_COMM_LOST :
1096N/A state = sun_nio_ch_SctpAssocChange_SCTP_COMM_LOST;
1096N/A break;
1096N/A case SCTP_RESTART :
1096N/A state = sun_nio_ch_SctpAssocChange_SCTP_RESTART;
1096N/A break;
1096N/A case SCTP_SHUTDOWN_COMP :
1096N/A state = sun_nio_ch_SctpAssocChange_SCTP_SHUTDOWN;
1096N/A break;
1096N/A case SCTP_CANT_STR_ASSOC :
1096N/A state = sun_nio_ch_SctpAssocChange_SCTP_CANT_START;
1096N/A }
1096N/A
1096N/A /* create SctpAssociationChanged */
1096N/A resultObj = (*env)->NewObject(env, sac_class, sac_ctrID, sac->sac_assoc_id,
1096N/A state, sac->sac_outbound_streams, sac->sac_inbound_streams);
1096N/A CHECK_NULL(resultObj);
1096N/A (*env)->SetObjectField(env, resultContainerObj, src_valueID, resultObj);
1096N/A (*env)->SetIntField(env, resultContainerObj, src_typeID,
1096N/A sun_nio_ch_SctpResultContainer_ASSOCIATION_CHANGED);
1096N/A}
1096N/A
1096N/Avoid handleShutdown
1096N/A (JNIEnv* env, jobject resultContainerObj, struct sctp_shutdown_event* sse) {
1096N/A /* create SctpShutdown */
1096N/A jobject resultObj = (*env)->NewObject(env, ss_class, ss_ctrID, sse->sse_assoc_id);
1096N/A CHECK_NULL(resultObj);
1096N/A (*env)->SetObjectField(env, resultContainerObj, src_valueID, resultObj);
1096N/A (*env)->SetIntField(env, resultContainerObj, src_typeID,
1096N/A sun_nio_ch_SctpResultContainer_SHUTDOWN);
1096N/A}
1096N/A
1096N/Avoid handlePeerAddrChange
1096N/A (JNIEnv* env, jobject resultContainerObj, struct sctp_paddr_change* spc) {
1096N/A int event = 0;
1096N/A jobject addressObj, resultObj;
1096N/A unsigned int state = spc->spc_state;
1096N/A
1096N/A switch (state) {
1096N/A case SCTP_ADDR_AVAILABLE :
1096N/A event = sun_nio_ch_SctpPeerAddrChange_SCTP_ADDR_AVAILABLE;
1096N/A break;
1096N/A case SCTP_ADDR_UNREACHABLE :
1096N/A event = sun_nio_ch_SctpPeerAddrChange_SCTP_ADDR_UNREACHABLE;
1096N/A break;
1096N/A case SCTP_ADDR_REMOVED :
1096N/A event = sun_nio_ch_SctpPeerAddrChange_SCTP_ADDR_REMOVED;
1096N/A break;
1096N/A case SCTP_ADDR_ADDED :
1096N/A event = sun_nio_ch_SctpPeerAddrChange_SCTP_ADDR_ADDED;
1096N/A break;
1096N/A case SCTP_ADDR_MADE_PRIM :
1096N/A event = sun_nio_ch_SctpPeerAddrChange_SCTP_ADDR_MADE_PRIM;
4632N/A#ifndef __solaris__ /* Solaris currently doesn't support SCTP_ADDR_CONFIRMED */
1096N/A break;
1096N/A case SCTP_ADDR_CONFIRMED :
1096N/A event = sun_nio_ch_SctpPeerAddrChange_SCTP_ADDR_CONFIRMED;
4632N/A#endif /* __solaris__ */
1096N/A }
1096N/A
1096N/A addressObj = SockAddrToInetSocketAddress(env, (struct sockaddr*)&spc->spc_aaddr);
1096N/A
1096N/A /* create SctpPeerAddressChanged */
1096N/A resultObj = (*env)->NewObject(env, spc_class, spc_ctrID, spc->spc_assoc_id,
1096N/A addressObj, event);
1096N/A CHECK_NULL(resultObj);
1096N/A (*env)->SetObjectField(env, resultContainerObj, src_valueID, resultObj);
1096N/A (*env)->SetIntField(env, resultContainerObj, src_typeID,
1096N/A sun_nio_ch_SctpResultContainer_PEER_ADDRESS_CHANGED);
1096N/A}
1096N/A
1096N/Avoid handleUninteresting
1096N/A (union sctp_notification *snp) {
1096N/A //fprintf(stdout,"\nNative: handleUninterestingNotification: Receive notification type [%u]", snp->sn_header.sn_type);
1096N/A}
1096N/A
1096N/A/**
1096N/A * Handle notifications from the SCTP stack.
1096N/A * Returns JNI_TRUE if the notification is one that is of interest to the
1096N/A * Java API, otherwise JNI_FALSE.
1096N/A */
1096N/Ajboolean handleNotification
1096N/A (JNIEnv* env, int fd, jobject resultContainerObj, union sctp_notification* snp,
1096N/A int read, jboolean isEOR, struct sockaddr* sap) {
1096N/A switch (snp->sn_header.sn_type) {
1096N/A case SCTP_SEND_FAILED:
1096N/A handleSendFailed(env, fd, resultContainerObj, &snp->sn_send_failed,
1096N/A read, isEOR, sap);
1096N/A return JNI_TRUE;
1096N/A case SCTP_ASSOC_CHANGE:
1096N/A handleAssocChange(env, resultContainerObj, &snp->sn_assoc_change);
1096N/A return JNI_TRUE;
1096N/A case SCTP_SHUTDOWN_EVENT:
1096N/A handleShutdown(env, resultContainerObj, &snp->sn_shutdown_event);
1096N/A return JNI_TRUE;
1096N/A case SCTP_PEER_ADDR_CHANGE:
1096N/A handlePeerAddrChange(env, resultContainerObj, &snp->sn_paddr_change);
1096N/A return JNI_TRUE;
1096N/A default :
1096N/A /* the Java API is not interested in this event, maybe we are? */
1096N/A handleUninteresting(snp);
1096N/A }
1096N/A return JNI_FALSE;
1096N/A}
1096N/A
1096N/Avoid handleMessage
1096N/A (JNIEnv* env, jobject resultContainerObj, struct msghdr* msg,int read,
1096N/A jboolean isEOR, struct sockaddr* sap) {
1096N/A jobject isa, resultObj;
1096N/A struct controlData cdata[1];
1096N/A
1096N/A if (read == 0) {
1096N/A /* we reached EOF */
1096N/A read = -1;
1096N/A }
1096N/A
1096N/A isa = SockAddrToInetSocketAddress(env, sap);
1096N/A getControlData(msg, cdata);
1096N/A
1096N/A /* create SctpMessageInfoImpl */
1096N/A resultObj = (*env)->NewObject(env, smi_class, smi_ctrID, cdata->assocId,
1096N/A isa, read, cdata->streamNumber,
1096N/A isEOR ? JNI_TRUE : JNI_FALSE,
1096N/A cdata->unordered, cdata->ppid);
1096N/A CHECK_NULL(resultObj);
1096N/A (*env)->SetObjectField(env, resultContainerObj, src_valueID, resultObj);
1096N/A (*env)->SetIntField(env, resultContainerObj, src_typeID,
1096N/A sun_nio_ch_SctpResultContainer_MESSAGE);
1096N/A}
1096N/A
1096N/A/*
1096N/A * Class: sun_nio_ch_SctpChannelImpl
1096N/A * Method: receive0
1427N/A * Signature: (ILsun/nio/ch/SctpResultContainer;JIZ)I
1096N/A */
1096N/AJNIEXPORT jint JNICALL Java_sun_nio_ch_SctpChannelImpl_receive0
1096N/A (JNIEnv *env, jclass klass, jint fd, jobject resultContainerObj,
1427N/A jlong address, jint length, jboolean peek) {
1096N/A SOCKADDR sa;
1096N/A int sa_len = sizeof(sa);
1096N/A ssize_t rv = 0;
1096N/A jlong *addr = jlong_to_ptr(address);
1096N/A struct iovec iov[1];
1096N/A struct msghdr msg[1];
1096N/A char cbuf[CMSG_SPACE(sizeof (struct sctp_sndrcvinfo))];
1427N/A int flags = peek == JNI_TRUE ? MSG_PEEK : 0;
1096N/A
1096N/A /* Set up the msghdr structure for receiving */
1096N/A memset(msg, 0, sizeof (*msg));
1096N/A msg->msg_name = &sa;
1096N/A msg->msg_namelen = sa_len;
1096N/A iov->iov_base = addr;
1096N/A iov->iov_len = length;
1096N/A msg->msg_iov = iov;
1096N/A msg->msg_iovlen = 1;
1096N/A msg->msg_control = cbuf;
1096N/A msg->msg_controllen = sizeof(cbuf);
1096N/A msg->msg_flags = 0;
1096N/A
1096N/A do {
1427N/A if ((rv = recvmsg(fd, msg, flags)) < 0) {
1096N/A if (errno == EWOULDBLOCK) {
1096N/A return IOS_UNAVAILABLE;
1096N/A } else if (errno == EINTR) {
1096N/A return IOS_INTERRUPTED;
1096N/A
1096N/A#ifdef __linux__
1096N/A } else if (errno == ENOTCONN) {
1096N/A /* ENOTCONN when EOF reached */
1096N/A rv = 0;
1096N/A /* there will be no control data */
1096N/A msg->msg_controllen = 0;
1096N/A#endif /* __linux__ */
1096N/A
1096N/A } else {
1096N/A handleSocketError(env, errno);
1096N/A return 0;
1096N/A }
1096N/A }
1096N/A
1096N/A if (msg->msg_flags & MSG_NOTIFICATION) {
1096N/A char *bufp = (char*)addr;
1096N/A union sctp_notification *snp;
1096N/A
1096N/A if (!(msg->msg_flags & MSG_EOR) && length < NOTIFICATION_BUFFER_SIZE) {
1096N/A char buf[NOTIFICATION_BUFFER_SIZE];
1096N/A int rvSAVE = rv;
1096N/A memcpy(buf, addr, rv);
1096N/A iov->iov_base = buf + rv;
1096N/A iov->iov_len = NOTIFICATION_BUFFER_SIZE - rv;
1427N/A if ((rv = recvmsg(fd, msg, flags)) < 0) {
1096N/A handleSocketError(env, errno);
1096N/A return 0;
1096N/A }
1096N/A bufp = buf;
1096N/A rv += rvSAVE;
1096N/A }
1096N/A snp = (union sctp_notification *) bufp;
1096N/A if (handleNotification(env, fd, resultContainerObj, snp, rv,
1096N/A (msg->msg_flags & MSG_EOR),
1096N/A (struct sockaddr*)&sa ) == JNI_TRUE) {
1096N/A /* We have received a notification that is of interest to
1096N/A to the Java API. The appropriate notification will be
1096N/A set in the result container. */
1096N/A return 0;
1096N/A }
1096N/A
1096N/A // set iov back to addr, and reset msg_controllen
1096N/A iov->iov_base = addr;
1096N/A iov->iov_len = length;
1096N/A msg->msg_control = cbuf;
1096N/A msg->msg_controllen = sizeof(cbuf);
1096N/A }
1096N/A } while (msg->msg_flags & MSG_NOTIFICATION);
1096N/A
1096N/A handleMessage(env, resultContainerObj, msg, rv,
1096N/A (msg->msg_flags & MSG_EOR), (struct sockaddr*)&sa);
1096N/A return rv;
1096N/A}
1096N/A
1096N/A/*
1096N/A * Class: sun_nio_ch_SctpChannelImpl
1096N/A * Method: send0
5697N/A * Signature: (IJILjava/net/InetAddress;IIIZI)I
1096N/A */
1096N/AJNIEXPORT jint JNICALL Java_sun_nio_ch_SctpChannelImpl_send0
1096N/A (JNIEnv *env, jclass klass, jint fd, jlong address, jint length,
5697N/A jobject targetAddress, jint targetPort, jint assocId, jint streamNumber,
5697N/A jboolean unordered, jint ppid) {
1096N/A SOCKADDR sa;
1096N/A int sa_len = sizeof(sa);
1096N/A ssize_t rv = 0;
1096N/A jlong *addr = jlong_to_ptr(address);
1096N/A struct iovec iov[1];
1096N/A struct msghdr msg[1];
1096N/A int cbuf_size = CMSG_SPACE(sizeof (struct sctp_sndrcvinfo));
1096N/A char cbuf[CMSG_SPACE(sizeof (struct sctp_sndrcvinfo))];
1096N/A struct controlData cdata[1];
1096N/A
1096N/A /* SctpChannel:
5697N/A * targetAddress may contain the preferred address or NULL to use primary,
1096N/A * assocId will always be -1
1096N/A * SctpMultiChannell:
5697N/A * Setup new association, targetAddress will contain address, assocId = -1
5697N/A * Association already existing, assocId != -1, targetAddress = preferred addr
1096N/A */
5697N/A if (targetAddress != NULL /*&& assocId <= 0*/) {
1096N/A if (NET_InetAddressToSockaddr(env, targetAddress, targetPort,
1096N/A (struct sockaddr *)&sa,
1096N/A &sa_len, JNI_TRUE) != 0) {
1096N/A return IOS_THROWN;
1096N/A }
1096N/A } else {
1096N/A memset(&sa, '\x0', sa_len);
1096N/A sa_len = 0;
1096N/A }
1096N/A
1096N/A /* Set up the msghdr structure for sending */
1096N/A memset(msg, 0, sizeof (*msg));
1096N/A memset(cbuf, 0, cbuf_size);
1096N/A msg->msg_name = &sa;
1096N/A msg->msg_namelen = sa_len;
1096N/A iov->iov_base = addr;
1096N/A iov->iov_len = length;
1096N/A msg->msg_iov = iov;
1096N/A msg->msg_iovlen = 1;
1096N/A msg->msg_control = cbuf;
1096N/A msg->msg_controllen = cbuf_size;
1096N/A msg->msg_flags = 0;
1096N/A
1096N/A cdata->streamNumber = streamNumber;
1096N/A cdata->assocId = assocId;
1096N/A cdata->unordered = unordered;
1096N/A cdata->ppid = ppid;
1096N/A setControlData(msg, cdata);
1096N/A
1096N/A if ((rv = sendmsg(fd, msg, 0)) < 0) {
1096N/A if (errno == EWOULDBLOCK) {
1096N/A return IOS_UNAVAILABLE;
1096N/A } else if (errno == EINTR) {
1096N/A return IOS_INTERRUPTED;
1096N/A } else if (errno == EPIPE) {
1096N/A JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
1096N/A "Socket is shutdown for writing");
1096N/A } else {
1096N/A handleSocketError(env, errno);
1096N/A return 0;
1096N/A }
1096N/A }
1096N/A
1096N/A return rv;
1096N/A}
1096N/A
1096N/A/*
1096N/A * Class: sun_nio_ch_SctpChannelImpl
1096N/A * Method: checkConnect
1096N/A * Signature: (Ljava/io/FileDescriptor;ZZ)I
1096N/A */
1096N/AJNIEXPORT jint JNICALL Java_sun_nio_ch_SctpChannelImpl_checkConnect
1096N/A (JNIEnv* env, jobject this, jobject fdo, jboolean block, jboolean ready) {
1096N/A return Java_sun_nio_ch_SocketChannelImpl_checkConnect(env, this,
1096N/A fdo, block, ready);
1096N/A}
1096N/A