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 |