| File: | jdk/src/jdk.sctp/unix/native/libsctp/SctpChannelImpl.c |
| Warning: | line 407, column 17 4th function call argument is an uninitialized value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* | |||
| 2 | * Copyright (c) 2009, 2021, 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" "sun/nio/ch/sctp/MessageInfoImpl" | |||
| 44 | #define RESULT_CONTAINER_CLASS"sun/nio/ch/sctp/ResultContainer" "sun/nio/ch/sctp/ResultContainer" | |||
| 45 | #define SEND_FAILED_CLASS"sun/nio/ch/sctp/SendFailed" "sun/nio/ch/sctp/SendFailed" | |||
| 46 | #define ASSOC_CHANGE_CLASS"sun/nio/ch/sctp/AssociationChange" "sun/nio/ch/sctp/AssociationChange" | |||
| 47 | #define PEER_CHANGE_CLASS"sun/nio/ch/sctp/PeerAddrChange" "sun/nio/ch/sctp/PeerAddrChange" | |||
| 48 | #define SHUTDOWN_CLASS"sun/nio/ch/sctp/Shutdown" "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 | /* | |||
| 76 | * Class: sun_nio_ch_sctp_SctpChannelImpl | |||
| 77 | * Method: initIDs | |||
| 78 | * Signature: ()V | |||
| 79 | */ | |||
| 80 | JNIEXPORT__attribute__((visibility("default"))) 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"sun/nio/ch/sctp/MessageInfoImpl"); | |||
| 86 | CHECK_NULL(cls)do { if ((cls) == ((void*)0)) { return; } } while (0); | |||
| 87 | smi_class = (*env)->NewGlobalRef(env, cls); | |||
| 88 | CHECK_NULL(smi_class)do { if ((smi_class) == ((void*)0)) { return; } } while (0); | |||
| 89 | smi_ctrID = (*env)->GetMethodID(env, cls, "<init>", | |||
| 90 | "(ILjava/net/SocketAddress;IIZZI)V"); | |||
| 91 | CHECK_NULL(smi_ctrID)do { if ((smi_ctrID) == ((void*)0)) { return; } } while (0); | |||
| 92 | ||||
| 93 | /* ResultContainer */ | |||
| 94 | cls = (*env)->FindClass(env, RESULT_CONTAINER_CLASS"sun/nio/ch/sctp/ResultContainer"); | |||
| 95 | CHECK_NULL(cls)do { if ((cls) == ((void*)0)) { return; } } while (0); | |||
| 96 | src_valueID = (*env)->GetFieldID(env, cls, "value", "Ljava/lang/Object;"); | |||
| 97 | CHECK_NULL(src_valueID)do { if ((src_valueID) == ((void*)0)) { return; } } while (0); | |||
| 98 | src_typeID = (*env)->GetFieldID(env, cls, "type", "I"); | |||
| 99 | CHECK_NULL(src_typeID)do { if ((src_typeID) == ((void*)0)) { return; } } while (0); | |||
| 100 | ||||
| 101 | /* SendFailed */ | |||
| 102 | cls = (*env)->FindClass(env, SEND_FAILED_CLASS"sun/nio/ch/sctp/SendFailed"); | |||
| 103 | CHECK_NULL(cls)do { if ((cls) == ((void*)0)) { return; } } while (0); | |||
| 104 | ssf_class = (*env)->NewGlobalRef(env, cls); | |||
| 105 | CHECK_NULL(ssf_class)do { if ((ssf_class) == ((void*)0)) { return; } } while (0); | |||
| 106 | ssf_ctrID = (*env)->GetMethodID(env, cls, "<init>", | |||
| 107 | "(ILjava/net/SocketAddress;Ljava/nio/ByteBuffer;II)V"); | |||
| 108 | CHECK_NULL(ssf_ctrID)do { if ((ssf_ctrID) == ((void*)0)) { return; } } while (0); | |||
| 109 | ||||
| 110 | /* AssociationChange */ | |||
| 111 | cls = (*env)->FindClass(env, ASSOC_CHANGE_CLASS"sun/nio/ch/sctp/AssociationChange"); | |||
| 112 | CHECK_NULL(cls)do { if ((cls) == ((void*)0)) { return; } } while (0); | |||
| 113 | sac_class = (*env)->NewGlobalRef(env, cls); | |||
| 114 | CHECK_NULL(sac_class)do { if ((sac_class) == ((void*)0)) { return; } } while (0); | |||
| 115 | sac_ctrID = (*env)->GetMethodID(env, cls, "<init>", "(IIII)V"); | |||
| 116 | CHECK_NULL(sac_ctrID)do { if ((sac_ctrID) == ((void*)0)) { return; } } while (0); | |||
| 117 | ||||
| 118 | /* PeerAddrChange */ | |||
| 119 | cls = (*env)->FindClass(env, PEER_CHANGE_CLASS"sun/nio/ch/sctp/PeerAddrChange"); | |||
| 120 | CHECK_NULL(cls)do { if ((cls) == ((void*)0)) { return; } } while (0); | |||
| 121 | spc_class = (*env)->NewGlobalRef(env, cls); | |||
| 122 | CHECK_NULL(spc_class)do { if ((spc_class) == ((void*)0)) { return; } } while (0); | |||
| 123 | spc_ctrID = (*env)->GetMethodID(env, cls, "<init>", | |||
| 124 | "(ILjava/net/SocketAddress;I)V"); | |||
| 125 | CHECK_NULL(spc_ctrID)do { if ((spc_ctrID) == ((void*)0)) { return; } } while (0); | |||
| 126 | ||||
| 127 | /* Shutdown */ | |||
| 128 | cls = (*env)->FindClass(env, SHUTDOWN_CLASS"sun/nio/ch/sctp/Shutdown"); | |||
| 129 | CHECK_NULL(cls)do { if ((cls) == ((void*)0)) { return; } } while (0); | |||
| 130 | ss_class = (*env)->NewGlobalRef(env, cls); | |||
| 131 | CHECK_NULL(ss_class)do { if ((ss_class) == ((void*)0)) { return; } } while (0); | |||
| 132 | ss_ctrID = (*env)->GetMethodID(env, cls, "<init>", "(I)V"); | |||
| 133 | CHECK_NULL(ss_ctrID)do { if ((ss_ctrID) == ((void*)0)) { return; } } while (0); | |||
| 134 | } | |||
| 135 | ||||
| 136 | void getControlData | |||
| 137 | (struct msghdr* msg, struct controlData* cdata) { | |||
| 138 | struct cmsghdr* cmsg; | |||
| 139 | ||||
| 140 | for (cmsg = CMSG_FIRSTHDR(msg)((size_t) (msg)->msg_controllen >= sizeof (struct cmsghdr ) ? (struct cmsghdr *) (msg)->msg_control : (struct cmsghdr *) 0); cmsg != NULL((void*)0); cmsg = CMSG_NXTHDR(msg, cmsg)__cmsg_nxthdr (msg, cmsg)) { | |||
| 141 | if (cmsg->cmsg_level == IPPROTO_SCTPIPPROTO_SCTP && cmsg->cmsg_type == SCTP_SNDRCVSCTP_SNDRCV) { | |||
| 142 | struct sctp_sndrcvinfo *sri; | |||
| 143 | ||||
| 144 | sri = (struct sctp_sndrcvinfo *) CMSG_DATA(cmsg)((cmsg)->__cmsg_data); | |||
| 145 | cdata->assocId = sri->sinfo_assoc_id; | |||
| 146 | cdata->streamNumber = sri->sinfo_stream; | |||
| 147 | cdata->unordered = (sri->sinfo_flags & SCTP_UNORDERED) ? JNI_TRUE1 : | |||
| 148 | JNI_FALSE0; | |||
| 149 | cdata->ppid = ntohl(sri->sinfo_ppid)(__extension__ ({ unsigned int __v, __x = (sri->sinfo_ppid ); if (__builtin_constant_p (__x)) __v = ((((__x) & 0xff000000 ) >> 24) | (((__x) & 0x00ff0000) >> 8) | (((__x ) & 0x0000ff00) << 8) | (((__x) & 0x000000ff) << 24)); else __asm__ ("bswap %0" : "=r" (__v) : "0" (__x)); __v ; })); | |||
| 150 | ||||
| 151 | return; | |||
| 152 | } | |||
| 153 | } | |||
| 154 | return; | |||
| 155 | } | |||
| 156 | ||||
| 157 | void setControlData | |||
| 158 | (struct msghdr* msg, struct controlData* cdata) { | |||
| 159 | struct cmsghdr* cmsg; | |||
| 160 | struct sctp_sndrcvinfo *sri; | |||
| 161 | ||||
| 162 | cmsg = CMSG_FIRSTHDR(msg)((size_t) (msg)->msg_controllen >= sizeof (struct cmsghdr ) ? (struct cmsghdr *) (msg)->msg_control : (struct cmsghdr *) 0); | |||
| 163 | cmsg->cmsg_level = IPPROTO_SCTPIPPROTO_SCTP; | |||
| 164 | cmsg->cmsg_type = SCTP_SNDRCVSCTP_SNDRCV; | |||
| 165 | cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo))((((sizeof (struct cmsghdr)) + sizeof (size_t) - 1) & (size_t ) ~(sizeof (size_t) - 1)) + (sizeof(struct sctp_sndrcvinfo))); | |||
| 166 | ||||
| 167 | /* Initialize the payload */ | |||
| 168 | sri = (struct sctp_sndrcvinfo*) CMSG_DATA(cmsg)((cmsg)->__cmsg_data); | |||
| 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_TRUE1) { | |||
| 178 | sri->sinfo_flags = sri->sinfo_flags | SCTP_UNORDERED; | |||
| 179 | } | |||
| 180 | ||||
| 181 | if (cdata->ppid > 0) { | |||
| 182 | sri->sinfo_ppid = htonl(cdata->ppid)(__extension__ ({ unsigned int __v, __x = (cdata->ppid); if (__builtin_constant_p (__x)) __v = ((((__x) & 0xff000000 ) >> 24) | (((__x) & 0x00ff0000) >> 8) | (((__x ) & 0x0000ff00) << 8) | (((__x) & 0x000000ff) << 24)); else __asm__ ("bswap %0" : "=r" (__v) : "0" (__x)); __v ; })); | |||
| 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. | |||
| 191 | void 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((void*)0), 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)do { if ((isaObj) == ((void*)0)) { return; } } while (0); | |||
| 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((void*)0)) { | |||
| 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 | if (bufferObj == NULL((void*)0)) { | |||
| 233 | free(addressP); | |||
| 234 | return; | |||
| 235 | } | |||
| 236 | ||||
| 237 | alreadyRead = read - dataOffset; | |||
| 238 | if (alreadyRead > 0) { | |||
| 239 | memcpy(addressP, /*ssf->ssf_data*/ dataP, alreadyRead); | |||
| 240 | iov->iov_base = addressP + alreadyRead; | |||
| 241 | iov->iov_len = dataLength - alreadyRead; | |||
| 242 | } else { | |||
| 243 | iov->iov_base = addressP; | |||
| 244 | iov->iov_len = dataLength; | |||
| 245 | } | |||
| 246 | ||||
| 247 | if (remaining > 0) { | |||
| 248 | if ((rv = recvmsg(fd, msg, 0)) < 0) { | |||
| 249 | free(addressP); | |||
| 250 | handleSocketError(env, errno(*__errno_location ())); | |||
| 251 | return; | |||
| 252 | } | |||
| 253 | ||||
| 254 | if (rv != (dataLength - alreadyRead) || !(msg->msg_flags & MSG_EORMSG_EOR)) { | |||
| 255 | //TODO: assert false: "should not reach here"; | |||
| 256 | free(addressP); | |||
| 257 | return; | |||
| 258 | } | |||
| 259 | // TODO: Set and document (in API) buffers position. | |||
| 260 | } | |||
| 261 | } | |||
| 262 | ||||
| 263 | /* create SendFailed */ | |||
| 264 | resultObj = (*env)->NewObject(env, ssf_class, ssf_ctrID, ssf->ssf_assoc_id, | |||
| 265 | isaObj, bufferObj, ssf->ssf_error, sri->sinfo_stream); | |||
| 266 | if (resultObj == NULL((void*)0)) { | |||
| 267 | if (bufferObj != NULL((void*)0)) free(addressP); | |||
| 268 | return; | |||
| 269 | } | |||
| 270 | (*env)->SetObjectField(env, resultContainerObj, src_valueID, resultObj); | |||
| 271 | (*env)->SetIntField(env, resultContainerObj, src_typeID, | |||
| 272 | sun_nio_ch_sctp_ResultContainer_SEND_FAILED2L); | |||
| 273 | } | |||
| 274 | ||||
| 275 | void handleAssocChange | |||
| 276 | (JNIEnv* env, jobject resultContainerObj, struct sctp_assoc_change *sac) { | |||
| 277 | jobject resultObj; | |||
| 278 | int state = 0; | |||
| 279 | ||||
| 280 | switch (sac->sac_state) { | |||
| 281 | case SCTP_COMM_UP : | |||
| 282 | state = sun_nio_ch_sctp_AssociationChange_SCTP_COMM_UP1L; | |||
| 283 | break; | |||
| 284 | case SCTP_COMM_LOST : | |||
| 285 | state = sun_nio_ch_sctp_AssociationChange_SCTP_COMM_LOST2L; | |||
| 286 | break; | |||
| 287 | case SCTP_RESTART : | |||
| 288 | state = sun_nio_ch_sctp_AssociationChange_SCTP_RESTART3L; | |||
| 289 | break; | |||
| 290 | case SCTP_SHUTDOWN_COMP : | |||
| 291 | state = sun_nio_ch_sctp_AssociationChange_SCTP_SHUTDOWN4L; | |||
| 292 | break; | |||
| 293 | case SCTP_CANT_STR_ASSOC : | |||
| 294 | state = sun_nio_ch_sctp_AssociationChange_SCTP_CANT_START5L; | |||
| 295 | } | |||
| 296 | ||||
| 297 | /* create AssociationChange */ | |||
| 298 | resultObj = (*env)->NewObject(env, sac_class, sac_ctrID, sac->sac_assoc_id, | |||
| 299 | state, sac->sac_outbound_streams, sac->sac_inbound_streams); | |||
| 300 | CHECK_NULL(resultObj)do { if ((resultObj) == ((void*)0)) { return; } } while (0); | |||
| 301 | (*env)->SetObjectField(env, resultContainerObj, src_valueID, resultObj); | |||
| 302 | (*env)->SetIntField(env, resultContainerObj, src_typeID, | |||
| 303 | sun_nio_ch_sctp_ResultContainer_ASSOCIATION_CHANGED3L); | |||
| 304 | } | |||
| 305 | ||||
| 306 | void handleShutdown | |||
| 307 | (JNIEnv* env, jobject resultContainerObj, struct sctp_shutdown_event* sse) { | |||
| 308 | /* create Shutdown */ | |||
| 309 | jobject resultObj = (*env)->NewObject(env, ss_class, ss_ctrID, sse->sse_assoc_id); | |||
| 310 | CHECK_NULL(resultObj)do { if ((resultObj) == ((void*)0)) { return; } } while (0); | |||
| 311 | (*env)->SetObjectField(env, resultContainerObj, src_valueID, resultObj); | |||
| 312 | (*env)->SetIntField(env, resultContainerObj, src_typeID, | |||
| 313 | sun_nio_ch_sctp_ResultContainer_SHUTDOWN5L); | |||
| 314 | } | |||
| 315 | ||||
| 316 | void handlePeerAddrChange | |||
| 317 | (JNIEnv* env, jobject resultContainerObj, struct sctp_paddr_change* spc) { | |||
| 318 | int event = 0; | |||
| 319 | jobject addressObj, resultObj; | |||
| 320 | unsigned int state = spc->spc_state; | |||
| 321 | ||||
| 322 | switch (state) { | |||
| 323 | case SCTP_ADDR_AVAILABLE : | |||
| 324 | event = sun_nio_ch_sctp_PeerAddrChange_SCTP_ADDR_AVAILABLE1L; | |||
| 325 | break; | |||
| 326 | case SCTP_ADDR_UNREACHABLE : | |||
| 327 | event = sun_nio_ch_sctp_PeerAddrChange_SCTP_ADDR_UNREACHABLE2L; | |||
| 328 | break; | |||
| 329 | case SCTP_ADDR_REMOVED : | |||
| 330 | event = sun_nio_ch_sctp_PeerAddrChange_SCTP_ADDR_REMOVED3L; | |||
| 331 | break; | |||
| 332 | case SCTP_ADDR_ADDED : | |||
| 333 | event = sun_nio_ch_sctp_PeerAddrChange_SCTP_ADDR_ADDED4L; | |||
| 334 | break; | |||
| 335 | case SCTP_ADDR_MADE_PRIM : | |||
| 336 | event = sun_nio_ch_sctp_PeerAddrChange_SCTP_ADDR_MADE_PRIM5L; | |||
| 337 | break; | |||
| 338 | #ifdef __linux__1 | |||
| 339 | case SCTP_ADDR_CONFIRMED : | |||
| 340 | event = sun_nio_ch_sctp_PeerAddrChange_SCTP_ADDR_CONFIRMED6L; | |||
| 341 | break; | |||
| 342 | #endif /* __linux__ */ | |||
| 343 | } | |||
| 344 | ||||
| 345 | addressObj = SockAddrToInetSocketAddress(env, (struct sockaddr*)&spc->spc_aaddr); | |||
| 346 | CHECK_NULL(addressObj)do { if ((addressObj) == ((void*)0)) { return; } } while (0); | |||
| 347 | ||||
| 348 | /* create PeerAddressChanged */ | |||
| 349 | resultObj = (*env)->NewObject(env, spc_class, spc_ctrID, spc->spc_assoc_id, | |||
| 350 | addressObj, event); | |||
| 351 | CHECK_NULL(resultObj)do { if ((resultObj) == ((void*)0)) { return; } } while (0); | |||
| 352 | (*env)->SetObjectField(env, resultContainerObj, src_valueID, resultObj); | |||
| 353 | (*env)->SetIntField(env, resultContainerObj, src_typeID, | |||
| 354 | sun_nio_ch_sctp_ResultContainer_PEER_ADDRESS_CHANGED4L); | |||
| 355 | } | |||
| 356 | ||||
| 357 | void handleUninteresting | |||
| 358 | (union sctp_notification *snp) { | |||
| 359 | //fprintf(stdout,"\nNative: handleUninterestingNotification: Receive notification type [%u]", snp->sn_header.sn_type); | |||
| 360 | } | |||
| 361 | ||||
| 362 | /** | |||
| 363 | * Handle notifications from the SCTP stack. | |||
| 364 | * Returns JNI_TRUE if the notification is one that is of interest to the | |||
| 365 | * Java API, otherwise JNI_FALSE. | |||
| 366 | */ | |||
| 367 | jboolean handleNotification | |||
| 368 | (JNIEnv* env, int fd, jobject resultContainerObj, union sctp_notification* snp, | |||
| 369 | int read, jboolean isEOR, struct sockaddr* sap) { | |||
| 370 | switch (snp->sn_header.sn_type) { | |||
| 371 | case SCTP_SEND_FAILED: | |||
| 372 | handleSendFailed(env, fd, resultContainerObj, &snp->sn_send_failed, | |||
| 373 | read, isEOR, sap); | |||
| 374 | return JNI_TRUE1; | |||
| 375 | case SCTP_ASSOC_CHANGE: | |||
| 376 | handleAssocChange(env, resultContainerObj, &snp->sn_assoc_change); | |||
| 377 | return JNI_TRUE1; | |||
| 378 | case SCTP_SHUTDOWN_EVENT: | |||
| 379 | handleShutdown(env, resultContainerObj, &snp->sn_shutdown_event); | |||
| 380 | return JNI_TRUE1; | |||
| 381 | case SCTP_PEER_ADDR_CHANGE: | |||
| 382 | handlePeerAddrChange(env, resultContainerObj, &snp->sn_paddr_change); | |||
| 383 | return JNI_TRUE1; | |||
| 384 | default : | |||
| 385 | /* the Java API is not interested in this event, maybe we are? */ | |||
| 386 | handleUninteresting(snp); | |||
| 387 | } | |||
| 388 | return JNI_FALSE0; | |||
| 389 | } | |||
| 390 | ||||
| 391 | void handleMessage | |||
| 392 | (JNIEnv* env, jobject resultContainerObj, struct msghdr* msg,int read, | |||
| 393 | jboolean isEOR, struct sockaddr* sap) { | |||
| 394 | jobject isa, resultObj; | |||
| 395 | struct controlData cdata[1]; | |||
| 396 | ||||
| 397 | if (read == 0) { | |||
| 398 | /* we reached EOF */ | |||
| 399 | read = -1; | |||
| 400 | } | |||
| 401 | ||||
| 402 | isa = SockAddrToInetSocketAddress(env, sap); | |||
| 403 | CHECK_NULL(isa)do { if ((isa) == ((void*)0)) { return; } } while (0); | |||
| 404 | getControlData(msg, cdata); | |||
| 405 | ||||
| 406 | /* create MessageInfoImpl */ | |||
| 407 | resultObj = (*env)->NewObject(env, smi_class, smi_ctrID, cdata->assocId, | |||
| ||||
| 408 | isa, read, cdata->streamNumber, | |||
| 409 | isEOR ? JNI_TRUE1 : JNI_FALSE0, | |||
| 410 | cdata->unordered, cdata->ppid); | |||
| 411 | CHECK_NULL(resultObj)do { if ((resultObj) == ((void*)0)) { return; } } while (0); | |||
| 412 | (*env)->SetObjectField(env, resultContainerObj, src_valueID, resultObj); | |||
| 413 | (*env)->SetIntField(env, resultContainerObj, src_typeID, | |||
| 414 | sun_nio_ch_sctp_ResultContainer_MESSAGE1L); | |||
| 415 | } | |||
| 416 | ||||
| 417 | /* | |||
| 418 | * Class: sun_nio_ch_sctp_SctpChannelImpl | |||
| 419 | * Method: receive0 | |||
| 420 | * Signature: (ILsun/nio/ch/sctp/ResultContainer;JIZ)I | |||
| 421 | */ | |||
| 422 | JNIEXPORT__attribute__((visibility("default"))) jint JNICALL Java_sun_nio_ch_sctp_SctpChannelImpl_receive0 | |||
| 423 | (JNIEnv *env, jclass klass, jint fd, jobject resultContainerObj, | |||
| 424 | jlong address, jint length, jboolean peek) { | |||
| 425 | SOCKETADDRESS sa; | |||
| 426 | ssize_t rv = 0; | |||
| 427 | jlong *addr = jlong_to_ptr(address)((void*)(address)); | |||
| 428 | struct iovec iov[1]; | |||
| 429 | struct msghdr msg[1]; | |||
| 430 | char cbuf[CMSG_SPACE(sizeof (struct sctp_sndrcvinfo))((((sizeof (struct sctp_sndrcvinfo)) + sizeof (size_t) - 1) & (size_t) ~(sizeof (size_t) - 1)) + (((sizeof (struct cmsghdr )) + sizeof (size_t) - 1) & (size_t) ~(sizeof (size_t) - 1 )))]; | |||
| 431 | int flags = peek == JNI_TRUE1 ? MSG_PEEKMSG_PEEK : 0; | |||
| ||||
| 432 | ||||
| 433 | /* Set up the msghdr structure for receiving */ | |||
| 434 | memset(msg, 0, sizeof (*msg)); | |||
| 435 | msg->msg_name = &sa; | |||
| 436 | msg->msg_namelen = sizeof(sa); | |||
| 437 | iov->iov_base = addr; | |||
| 438 | iov->iov_len = length; | |||
| 439 | msg->msg_iov = iov; | |||
| 440 | msg->msg_iovlen = 1; | |||
| 441 | msg->msg_control = cbuf; | |||
| 442 | msg->msg_controllen = sizeof(cbuf); | |||
| 443 | msg->msg_flags = 0; | |||
| 444 | ||||
| 445 | do { | |||
| 446 | if ((rv = recvmsg(fd, msg, flags)) < 0) { | |||
| 447 | if (errno(*__errno_location ()) == EAGAIN11 || errno(*__errno_location ()) == EWOULDBLOCK11) { | |||
| 448 | return IOS_UNAVAILABLE(-2L); | |||
| 449 | } else if (errno(*__errno_location ()) == EINTR4) { | |||
| 450 | return IOS_INTERRUPTED(-3L); | |||
| 451 | ||||
| 452 | #ifdef __linux__1 | |||
| 453 | } else if (errno(*__errno_location ()) == ENOTCONN107) { | |||
| 454 | /* ENOTCONN when EOF reached */ | |||
| 455 | rv = 0; | |||
| 456 | /* there will be no control data */ | |||
| 457 | msg->msg_controllen = 0; | |||
| 458 | #endif /* __linux__ */ | |||
| 459 | ||||
| 460 | } else { | |||
| 461 | handleSocketError(env, errno(*__errno_location ())); | |||
| 462 | return 0; | |||
| 463 | } | |||
| 464 | } | |||
| 465 | ||||
| 466 | if (msg->msg_flags & MSG_NOTIFICATIONMSG_NOTIFICATION) { | |||
| 467 | char *bufp = (char*)addr; | |||
| 468 | union sctp_notification *snp; | |||
| 469 | jboolean allocated = JNI_FALSE0; | |||
| 470 | ||||
| 471 | if (!(msg->msg_flags & MSG_EORMSG_EOR) && length < SCTP_NOTIFICATION_SIZE) { | |||
| 472 | char* newBuf; | |||
| 473 | int rvSAVE = rv; | |||
| 474 | ||||
| 475 | if ((newBuf = malloc(SCTP_NOTIFICATION_SIZE)) == NULL((void*)0)) { | |||
| 476 | JNU_ThrowOutOfMemoryError(env, "Out of native heap space."); | |||
| 477 | return -1; | |||
| 478 | } | |||
| 479 | allocated = JNI_TRUE1; | |||
| 480 | ||||
| 481 | memcpy(newBuf, addr, rv); | |||
| 482 | iov->iov_base = newBuf + rv; | |||
| 483 | iov->iov_len = SCTP_NOTIFICATION_SIZE - rv; | |||
| 484 | if ((rv = recvmsg(fd, msg, flags)) < 0) { | |||
| 485 | handleSocketError(env, errno(*__errno_location ())); | |||
| 486 | free(newBuf); | |||
| 487 | return 0; | |||
| 488 | } | |||
| 489 | bufp = newBuf; | |||
| 490 | rv += rvSAVE; | |||
| 491 | } | |||
| 492 | snp = (union sctp_notification *) bufp; | |||
| 493 | if (handleNotification(env, fd, resultContainerObj, snp, rv, | |||
| 494 | (msg->msg_flags & MSG_EORMSG_EOR), | |||
| 495 | &sa.sa) == JNI_TRUE1) { | |||
| 496 | /* We have received a notification that is of interest | |||
| 497 | to the Java API. The appropriate notification will be | |||
| 498 | set in the result container. */ | |||
| 499 | if (allocated == JNI_TRUE1) { | |||
| 500 | free(bufp); | |||
| 501 | } | |||
| 502 | return 0; | |||
| 503 | } | |||
| 504 | ||||
| 505 | if (allocated == JNI_TRUE1) { | |||
| 506 | free(bufp); | |||
| 507 | } | |||
| 508 | ||||
| 509 | // set iov back to addr, and reset msg_controllen | |||
| 510 | iov->iov_base = addr; | |||
| 511 | iov->iov_len = length; | |||
| 512 | msg->msg_control = cbuf; | |||
| 513 | msg->msg_controllen = sizeof(cbuf); | |||
| 514 | } | |||
| 515 | } while (msg->msg_flags & MSG_NOTIFICATIONMSG_NOTIFICATION); | |||
| 516 | ||||
| 517 | handleMessage(env, resultContainerObj, msg, rv, | |||
| 518 | (msg->msg_flags & MSG_EORMSG_EOR), &sa.sa); | |||
| 519 | return rv; | |||
| 520 | } | |||
| 521 | ||||
| 522 | /* | |||
| 523 | * Class: sun_nio_ch_sctp_SctpChannelImpl | |||
| 524 | * Method: send0 | |||
| 525 | * Signature: (IJILjava/net/InetAddress;IIIZI)I | |||
| 526 | */ | |||
| 527 | JNIEXPORT__attribute__((visibility("default"))) jint JNICALL Java_sun_nio_ch_sctp_SctpChannelImpl_send0 | |||
| 528 | (JNIEnv *env, jclass klass, jint fd, jlong address, jint length, | |||
| 529 | jobject targetAddress, jint targetPort, jint assocId, jint streamNumber, | |||
| 530 | jboolean unordered, jint ppid) { | |||
| 531 | SOCKETADDRESS sa; | |||
| 532 | int sa_len = 0; | |||
| 533 | ssize_t rv = 0; | |||
| 534 | jlong *addr = jlong_to_ptr(address)((void*)(address)); | |||
| 535 | struct iovec iov[1]; | |||
| 536 | struct msghdr msg[1]; | |||
| 537 | int cbuf_size = CMSG_SPACE(sizeof (struct sctp_sndrcvinfo))((((sizeof (struct sctp_sndrcvinfo)) + sizeof (size_t) - 1) & (size_t) ~(sizeof (size_t) - 1)) + (((sizeof (struct cmsghdr )) + sizeof (size_t) - 1) & (size_t) ~(sizeof (size_t) - 1 ))); | |||
| 538 | char cbuf[CMSG_SPACE(sizeof (struct sctp_sndrcvinfo))((((sizeof (struct sctp_sndrcvinfo)) + sizeof (size_t) - 1) & (size_t) ~(sizeof (size_t) - 1)) + (((sizeof (struct cmsghdr )) + sizeof (size_t) - 1) & (size_t) ~(sizeof (size_t) - 1 )))]; | |||
| 539 | struct controlData cdata[1]; | |||
| 540 | ||||
| 541 | /* SctpChannel: | |||
| 542 | * targetAddress may contain the preferred address or NULL to use primary, | |||
| 543 | * assocId will always be -1 | |||
| 544 | * SctpMultiChannell: | |||
| 545 | * Setup new association, targetAddress will contain address, assocId = -1 | |||
| 546 | * Association already existing, assocId != -1, targetAddress = preferred addr | |||
| 547 | */ | |||
| 548 | if (targetAddress != NULL((void*)0) /*&& assocId <= 0*/) { | |||
| 549 | if (NET_InetAddressToSockaddr(env, targetAddress, targetPort, &sa, | |||
| 550 | &sa_len, JNI_TRUE1) != 0) { | |||
| 551 | return IOS_THROWN(-5L); | |||
| 552 | } | |||
| 553 | } else { | |||
| 554 | memset(&sa, '\x0', sizeof(sa)); | |||
| 555 | } | |||
| 556 | ||||
| 557 | /* Set up the msghdr structure for sending */ | |||
| 558 | memset(msg, 0, sizeof (*msg)); | |||
| 559 | memset(cbuf, 0, cbuf_size); | |||
| 560 | msg->msg_name = &sa; | |||
| 561 | msg->msg_namelen = sa_len; | |||
| 562 | iov->iov_base = addr; | |||
| 563 | iov->iov_len = length; | |||
| 564 | msg->msg_iov = iov; | |||
| 565 | msg->msg_iovlen = 1; | |||
| 566 | msg->msg_control = cbuf; | |||
| 567 | msg->msg_controllen = cbuf_size; | |||
| 568 | msg->msg_flags = 0; | |||
| 569 | ||||
| 570 | cdata->streamNumber = streamNumber; | |||
| 571 | cdata->assocId = assocId; | |||
| 572 | cdata->unordered = unordered; | |||
| 573 | cdata->ppid = ppid; | |||
| 574 | setControlData(msg, cdata); | |||
| 575 | ||||
| 576 | if ((rv = sendmsg(fd, msg, 0)) < 0) { | |||
| 577 | if (errno(*__errno_location ()) == EAGAIN11 || errno(*__errno_location ()) == EWOULDBLOCK11) { | |||
| 578 | return IOS_UNAVAILABLE(-2L); | |||
| 579 | } else if (errno(*__errno_location ()) == EINTR4) { | |||
| 580 | return IOS_INTERRUPTED(-3L); | |||
| 581 | } else if (errno(*__errno_location ()) == EPIPE32) { | |||
| 582 | JNU_ThrowByName(env, JNU_JAVANETPKG"java/net/" "SocketException", | |||
| 583 | "Socket is shutdown for writing"); | |||
| 584 | } else { | |||
| 585 | handleSocketError(env, errno(*__errno_location ())); | |||
| 586 | return 0; | |||
| 587 | } | |||
| 588 | } | |||
| 589 | ||||
| 590 | return rv; | |||
| 591 | } | |||
| 592 |