1 /*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "NetworkUtilities"
18
19 #include "NetworkUtilities.h"
20
21 #include <arpa/inet.h>
22 #include <fcntl.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/socket.h>
27 #include <sys/un.h>
28
29 #include <nativehelper/JNIHelp.h>
30 #include <nativehelper/ScopedLocalRef.h>
31
32 #include "JniConstants.h"
33
34 #include <log/log.h>
35
36
sockaddrToInetAddress(JNIEnv * env,const sockaddr_storage & ss,jint * port)37 jobject sockaddrToInetAddress(JNIEnv* env, const sockaddr_storage& ss, jint* port) {
38 // Convert IPv4-mapped IPv6 addresses to IPv4 addresses.
39 // The RI states "Java will never return an IPv4-mapped address".
40 const sockaddr_in6& sin6 = reinterpret_cast<const sockaddr_in6&>(ss);
41 if (ss.ss_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&sin6.sin6_addr)) {
42 // Copy the IPv6 address into the temporary sockaddr_storage.
43 sockaddr_storage tmp;
44 memset(&tmp, 0, sizeof(tmp));
45 memcpy(&tmp, &ss, sizeof(sockaddr_in6));
46 // Unmap it into an IPv4 address.
47 sockaddr_in& sin = reinterpret_cast<sockaddr_in&>(tmp);
48 sin.sin_family = AF_INET;
49 sin.sin_port = sin6.sin6_port;
50 memcpy(&sin.sin_addr.s_addr, &sin6.sin6_addr.s6_addr[12], 4);
51 // Do the regular conversion using the unmapped address.
52 return sockaddrToInetAddress(env, tmp, port);
53 }
54
55 const void* rawAddress;
56 size_t addressLength;
57 int sin_port = 0;
58 int scope_id = 0;
59 if (ss.ss_family == AF_INET) {
60 const sockaddr_in& sin = reinterpret_cast<const sockaddr_in&>(ss);
61 rawAddress = &sin.sin_addr.s_addr;
62 addressLength = 4;
63 sin_port = ntohs(sin.sin_port);
64 } else if (ss.ss_family == AF_INET6) {
65 const sockaddr_in6& sin6 = reinterpret_cast<const sockaddr_in6&>(ss);
66 rawAddress = &sin6.sin6_addr.s6_addr;
67 addressLength = 16;
68 sin_port = ntohs(sin6.sin6_port);
69 scope_id = sin6.sin6_scope_id;
70 } else {
71 // We can't throw SocketException. We aren't meant to see bad addresses, so seeing one
72 // really does imply an internal error.
73 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
74 "sockaddrToInetAddress unsupported ss_family: %i", ss.ss_family);
75 return NULL;
76 }
77 if (port != NULL) {
78 *port = sin_port;
79 }
80
81 ScopedLocalRef<jbyteArray> byteArray(env, env->NewByteArray(addressLength));
82 if (byteArray.get() == NULL) {
83 return NULL;
84 }
85 env->SetByteArrayRegion(byteArray.get(), 0, addressLength,
86 reinterpret_cast<const jbyte*>(rawAddress));
87
88 static jmethodID getByAddressMethod = env->GetStaticMethodID(JniConstants::GetInetAddressClass(env),
89 "getByAddress", "(Ljava/lang/String;[BI)Ljava/net/InetAddress;");
90 if (getByAddressMethod == NULL) {
91 return NULL;
92 }
93 return env->CallStaticObjectMethod(JniConstants::GetInetAddressClass(env), getByAddressMethod,
94 NULL, byteArray.get(), scope_id);
95 }
96
inetAddressToSockaddr(JNIEnv * env,jobject inetAddress,int port,sockaddr_storage & ss,socklen_t & sa_len,bool map)97 static bool inetAddressToSockaddr(JNIEnv* env, jobject inetAddress, int port, sockaddr_storage& ss, socklen_t& sa_len, bool map) {
98 memset(&ss, 0, sizeof(ss));
99 sa_len = 0;
100
101 if (inetAddress == NULL) {
102 jniThrowNullPointerException(env, NULL);
103 return false;
104 }
105
106 // Get holder.
107 static jfieldID holderFid = env->GetFieldID(JniConstants::GetInetAddressClass(env), "holder", "Ljava/net/InetAddress$InetAddressHolder;");
108 if (holderFid == NULL) {
109 return false;
110 }
111 ScopedLocalRef<jobject> holder(env, env->GetObjectField(inetAddress, holderFid));
112 // Get the address family.
113 static jfieldID familyFid = env->GetFieldID(JniConstants::GetInetAddressHolderClass(env), "family", "I");
114 if (familyFid == NULL) {
115 return false;
116 }
117 ss.ss_family = env->GetIntField(holder.get(), familyFid);
118 if (ss.ss_family == AF_UNSPEC) {
119 sa_len = sizeof(ss.ss_family);
120 return true; // Job done!
121 }
122
123 // Check this is an address family we support.
124 if (ss.ss_family != AF_INET && ss.ss_family != AF_INET6) {
125 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
126 "inetAddressToSockaddr bad family: %i", ss.ss_family);
127 return false;
128 }
129
130 // Get the byte array that stores the IP address bytes in the InetAddress.
131 static jmethodID bytesMid = env->GetMethodID(JniConstants::GetInetAddressClass(env), "getAddress", "()[B");
132 if (bytesMid == NULL) {
133 return false;
134 }
135 ScopedLocalRef<jbyteArray> addressBytes(env, reinterpret_cast<jbyteArray>(env->CallObjectMethod(inetAddress, bytesMid)));
136 if (env->ExceptionCheck()) {
137 return false;
138 }
139 if (addressBytes.get() == NULL) {
140 jniThrowNullPointerException(env, NULL);
141 return false;
142 }
143
144 // TODO: bionic's getnameinfo(3) seems to want its length parameter to be exactly
145 // sizeof(sockaddr_in) for an IPv4 address and sizeof (sockaddr_in6) for an
146 // IPv6 address. Fix getnameinfo so it accepts sizeof(sockaddr_storage), and
147 // then unconditionally set sa_len to sizeof(sockaddr_storage) instead of having
148 // to deal with this case by case.
149
150 // We use AF_INET6 sockets, so we want an IPv6 address (which may be a IPv4-mapped address).
151 sockaddr_in6& sin6 = reinterpret_cast<sockaddr_in6&>(ss);
152 sin6.sin6_port = htons(port);
153 if (ss.ss_family == AF_INET6) {
154 // IPv6 address. Copy the bytes...
155 jbyte* dst = reinterpret_cast<jbyte*>(&sin6.sin6_addr.s6_addr);
156 env->GetByteArrayRegion(addressBytes.get(), 0, 16, dst);
157 // ...and set the scope id...
158 static jfieldID holder6Fid = env->GetFieldID(JniConstants::GetInet6AddressClass(env),
159 "holder6",
160 "Ljava/net/Inet6Address$Inet6AddressHolder;");
161 if (holder6Fid == NULL) {
162 return false;
163 }
164 ScopedLocalRef<jobject> holder6(env, env->GetObjectField(inetAddress, holder6Fid));
165 static jfieldID scopeFid = env->GetFieldID(JniConstants::GetInet6AddressHolderClass(env),
166 "scope_id",
167 "I");
168 sin6.sin6_scope_id = env->GetIntField(holder6.get(), scopeFid);
169 sa_len = sizeof(sockaddr_in6);
170 return true;
171 }
172
173 // Deal with Inet4Address instances.
174 if (map) {
175 // We should represent this Inet4Address as an IPv4-mapped IPv6 sockaddr_in6.
176 // Change the family...
177 sin6.sin6_family = AF_INET6;
178 // Copy the bytes...
179 jbyte* dst = reinterpret_cast<jbyte*>(&sin6.sin6_addr.s6_addr[12]);
180 env->GetByteArrayRegion(addressBytes.get(), 0, 4, dst);
181 // INADDR_ANY and in6addr_any are both all-zeros...
182 if (!IN6_IS_ADDR_UNSPECIFIED(&sin6.sin6_addr)) {
183 // ...but all other IPv4-mapped addresses are ::ffff:a.b.c.d, so insert the ffff...
184 memset(&(sin6.sin6_addr.s6_addr[10]), 0xff, 2);
185 }
186 sa_len = sizeof(sockaddr_in6);
187 } else {
188 // We should represent this Inet4Address as an IPv4 sockaddr_in.
189 sockaddr_in& sin = reinterpret_cast<sockaddr_in&>(ss);
190 sin.sin_port = htons(port);
191 jbyte* dst = reinterpret_cast<jbyte*>(&sin.sin_addr.s_addr);
192 env->GetByteArrayRegion(addressBytes.get(), 0, 4, dst);
193 sa_len = sizeof(sockaddr_in);
194 }
195 return true;
196 }
197
inetAddressToSockaddrVerbatim(JNIEnv * env,jobject inetAddress,int port,sockaddr_storage & ss,socklen_t & sa_len)198 bool inetAddressToSockaddrVerbatim(JNIEnv* env, jobject inetAddress, int port, sockaddr_storage& ss, socklen_t& sa_len) {
199 return inetAddressToSockaddr(env, inetAddress, port, ss, sa_len, false);
200 }
201
inetAddressToSockaddr(JNIEnv * env,jobject inetAddress,int port,sockaddr_storage & ss,socklen_t & sa_len)202 bool inetAddressToSockaddr(JNIEnv* env, jobject inetAddress, int port, sockaddr_storage& ss, socklen_t& sa_len) {
203 return inetAddressToSockaddr(env, inetAddress, port, ss, sa_len, true);
204 }
205
206 /*
207 * Fill msg_contrl data from structCmsghdr[]
208 */
structCmsghdrArrayToMsgcontrol(JNIEnv * env,jobjectArray cmsgArray,struct msghdr & mhdr)209 bool structCmsghdrArrayToMsgcontrol(JNIEnv* env, jobjectArray cmsgArray, struct msghdr& mhdr) {
210 struct cmsghdr *cm = NULL;
211 int i = 0;
212 jclass structCmsghdrClass = JniConstants::GetStructCmsghdrClass(env);
213 static jfieldID cmsgDataFid = env->GetFieldID(structCmsghdrClass, "cmsg_data", "[B");
214 if (!cmsgDataFid) {
215 return false;
216 }
217 static jfieldID cmsgLevelFid = env->GetFieldID(structCmsghdrClass, "cmsg_level", "I");
218 if (!cmsgLevelFid) {
219 return false;
220 }
221 static jfieldID cmsgTypeFid = env->GetFieldID(structCmsghdrClass, "cmsg_type", "I");
222 if (!cmsgTypeFid) {
223 return false;
224 }
225
226 int cmsgArrayize = env->GetArrayLength(cmsgArray);
227 if (!cmsgArrayize) {
228 // Return true since msg_control is optional parameter.
229 return true;
230 }
231
232 for (int i = 0; i < cmsgArrayize; ++i) {
233 ScopedLocalRef<jobject> cmsg(env, env->GetObjectArrayElement(cmsgArray, i));
234 ScopedLocalRef<jbyteArray> cmsgData(env, reinterpret_cast<jbyteArray>(
235 env->GetObjectField(cmsg.get(), cmsgDataFid)));
236
237 mhdr.msg_controllen += CMSG_SPACE(env->GetArrayLength(cmsgData.get()));
238 }
239
240 mhdr.msg_control = (unsigned char*)malloc(mhdr.msg_controllen);
241 if (mhdr.msg_control == NULL) {
242 jniThrowException(env, "java/lang/OutOfMemoryError", "Out of memory");
243 return false;
244 }
245 memset(mhdr.msg_control, 0, mhdr.msg_controllen);
246
247 // Loop over each cmsghdr header and set data.
248 for (cm = CMSG_FIRSTHDR(&mhdr), i = 0; (cm != NULL); cm = CMSG_NXTHDR(&mhdr, cm), ++i)
249 {
250 size_t data_len = 0;
251 ScopedLocalRef<jobject> cmsg(env, env->GetObjectArrayElement(cmsgArray, i));
252 ScopedLocalRef<jbyteArray> cmsgData(env, reinterpret_cast<jbyteArray>(
253 env->GetObjectField(cmsg.get(), cmsgDataFid)));
254
255 cm->cmsg_level = env->GetIntField(cmsg.get(), cmsgLevelFid);
256 cm->cmsg_type = env->GetIntField(cmsg.get(), cmsgTypeFid);
257 data_len = env->GetArrayLength(cmsgData.get());
258 cm->cmsg_len = CMSG_LEN(data_len);
259 env->GetByteArrayRegion(cmsgData.get(), 0,
260 data_len, reinterpret_cast<jbyte*>CMSG_DATA(cm));
261 }
262 return true;
263 }
264
265 /*
266 * Fill structCmsghdr[] data per msgcontrol data, used when recvmsg
267 */
msgcontrolToStructCmsghdrArray(JNIEnv * env,jobject structMsghdr,struct msghdr & mhdr)268 bool msgcontrolToStructCmsghdrArray(JNIEnv* env, jobject structMsghdr, struct msghdr& mhdr) {
269 struct cmsghdr *cm = NULL;
270 int i = 0;
271
272 static jfieldID msgControlFid = env->GetFieldID(JniConstants::GetStructMsghdrClass(env),
273 "msg_control", "[Landroid/system/StructCmsghdr;");
274 if (!msgControlFid) {
275 return false;
276 }
277
278 static jmethodID cmsgInitMid = env->GetMethodID(JniConstants::GetStructCmsghdrClass(env),
279 "<init>", "(II[B)V");
280 if (!cmsgInitMid) {
281 return false;
282 }
283
284 int cmsghdrNumber = 0;
285 for (cm = CMSG_FIRSTHDR(&mhdr); (cm != NULL); cm = CMSG_NXTHDR(&mhdr, cm)) {
286 cmsghdrNumber++;
287 }
288 if (!cmsghdrNumber)
289 return true;
290
291 jobjectArray structCmsghdrArray = env->NewObjectArray(cmsghdrNumber,
292 JniConstants::GetStructCmsghdrClass(env), NULL);
293 if (!structCmsghdrArray) {
294 return false;
295 }
296
297 // Loop over each cmsghdr header and set data.
298 for (cm = CMSG_FIRSTHDR(&mhdr),i=0; (cm!=NULL); cm = CMSG_NXTHDR(&mhdr, cm),i++) {
299 // copy out cmsg_data
300 ScopedLocalRef<jbyteArray> msgData(env,
301 env->NewByteArray(cm->cmsg_len - sizeof(struct cmsghdr)));
302 env->SetByteArrayRegion(msgData.get(),
303 0,
304 env->GetArrayLength(msgData.get()),
305 reinterpret_cast<jbyte*>CMSG_DATA(cm));
306
307 ScopedLocalRef<jobject> objItem(env, env->NewObject(
308 JniConstants::GetStructCmsghdrClass(env),
309 cmsgInitMid, cm->cmsg_level, cm->cmsg_type, msgData.get()));
310
311 env->SetObjectArrayElement(structCmsghdrArray, i, objItem.get());
312 }
313
314 env->SetObjectField(structMsghdr, msgControlFid, structCmsghdrArray);
315
316 return true;
317 }
318
319 /*
320 * generate ScopedBytes object per ByteBuffer.isDirect
321 * if ByteBuffer.isDirect, generate ScopedBytes object by ByteBuffer itself;
322 * else, generate ScopedBytes object by ByteBuffer.array;
323 *
324 * Input: ByteBuffer object, isRW(R only or RW)
325 * Output: byte_len, length of the byte data per ByteBuffer.remaining;
326 * return value: pointer of new ScopedBytesRW or ScopedBytesRO
327 */
getScopedBytesFromByteBuffer(JNIEnv * env,jobject byteBuffer,int & byteLen,bool isRW)328 static void* getScopedBytesFromByteBuffer(JNIEnv* env,
329 jobject byteBuffer, int& byteLen, bool isRW) {
330
331 jclass byteBufferClass = JniConstants::GetByteBufferClass(env);
332 static jmethodID isDirectMid = env->GetMethodID(byteBufferClass, "isDirect", "()Z");
333 static jmethodID remainingMid = env->GetMethodID(byteBufferClass, "remaining", "()I");
334 static jmethodID arrayMid = env->GetMethodID(byteBufferClass, "array", "()[B");
335
336 if (!isDirectMid || !remainingMid || !arrayMid) {
337 return NULL;
338 }
339
340 byteLen = env->CallIntMethod(byteBuffer, remainingMid);
341 bool isDirect = env->CallBooleanMethod(byteBuffer, isDirectMid);
342 jobject objBuff;
343 if (isDirect == true) {
344 objBuff = env->NewLocalRef(byteBuffer); // Add LocalRef to align with CallObjectMethod
345 } else {
346 // return array
347 objBuff = env->CallObjectMethod(byteBuffer, arrayMid);
348 }
349
350 if (isRW) {
351 return (void*)(new ScopedBytesRW(env, objBuff));
352 } else {
353 return (void*)(new ScopedBytesRO(env, objBuff));
354 }
355
356 }
357
358 /*
359 * Convert ByteBuffer[] to mhdr.msg_iov/msg_iovlen
360 */
byteBufferArrayToIOV(JNIEnv * env,jobjectArray msgiovArray,struct msghdr & mhdr,ScopedByteBufferArray & scopeBufArray)361 bool byteBufferArrayToIOV(JNIEnv* env, jobjectArray msgiovArray, struct msghdr& mhdr,
362 ScopedByteBufferArray& scopeBufArray) {
363 int msgIovArraySize = env->GetArrayLength(msgiovArray);
364 if (!msgIovArraySize) {
365 /* would not happen since msg_iov is marked as NonNull */
366 mhdr.msg_iov = NULL;
367 mhdr.msg_iovlen = 0;
368 }
369
370 struct iovec* iovarr = (struct iovec*)malloc(sizeof(iovec)*msgIovArraySize);
371 if (!iovarr) {
372 jniThrowException(env, "java/lang/OutOfMemoryError", "Out of memory");
373 return false;
374 }
375
376 if (scopeBufArray.initArray(msgIovArraySize) == false) {
377 jniThrowException(env, "java/lang/OutOfMemoryError", "Out of memory");
378 return false;
379 }
380
381 // Set memory of each msg_iov item by the original bytes address.
382 for (int i=0; i<msgIovArraySize; i++)
383 {
384 jobject msgiovItem = env->GetObjectArrayElement(msgiovArray, i);
385 int byteLen = 0;
386 void* ptr = getScopedBytesFromByteBuffer(env, msgiovItem, byteLen, scopeBufArray.isRW());
387 if (!ptr) {
388 jniThrowException(env, "java/lang/OutOfMemoryError", "Out of memory");
389 return false;
390 }
391
392 scopeBufArray.setArrayItem(i, ptr);
393
394 if (scopeBufArray.isRW()) {
395 iovarr[i].iov_base = (unsigned char*)(((ScopedBytesRW*)ptr)->get());
396 }
397 else {
398 iovarr[i].iov_base = (unsigned char*)(((ScopedBytesRO*)ptr)->get());
399 }
400
401 iovarr[i].iov_len = byteLen;
402 }
403
404 mhdr.msg_iov = iovarr;
405 mhdr.msg_iovlen = msgIovArraySize;
406
407 return true;
408 }
409
410 /*
411 * Function: convertStructMsghdrAndmsghdr
412 * Description: convert between Java#StructMsghdr and C#msghdr for sendmsg/recvmsg
413 *
414 * Function Parameters:
415 * StructMsghdr, input, StructMsghdr
416 * for sendmsg,
417 * StructMsghdr.msg_name input(mandatory),
418 * StructMsghdr.msg_iov iput(mandatory)
419 * StructMsghdr.msg_control input(optional)
420 * StructMsghdr.msg_flags input(mandatory)
421 * for recvmsg,
422 * StructMsghdr.msg_name input/output(optional),
423 * StructMsghdr.msg_iov input/output(mandatory)
424 * StructMsghdr.msg_control input/output(optional)
425 * StructMsghdr.msg_flags input
426 * mhdr, input, struct msghdr
427 * scopeBufArray, output, store buffer array of ScopedBytesRW or ScopedBytesRO
428 * isFromStructCMsghdrTomsghdr, input, indicate StructMsghdr->msghdr or msghdr->StructMsghdr
429 *
430 * then in sendmsg scenario, call sequence will be:
431 * 1. convert(StructMsg->msghdr)
432 * 2. sendmsg
433 * in recvmsg scenario, call sequence will be:
434 * 1. convert(StructMsg->msghdr)
435 * 2. recvmsg
436 * 3. convert again(msghdr->StructMsg)
437 */
convertStructMsghdrAndmsghdr(JNIEnv * env,jobject structMsghdr,struct msghdr & mhdr,ScopedByteBufferArray & scopeBufArray,bool isFromStructCMsghdrTomsghdr)438 bool convertStructMsghdrAndmsghdr(JNIEnv* env, jobject structMsghdr, struct msghdr& mhdr,
439 ScopedByteBufferArray& scopeBufArray,
440 bool isFromStructCMsghdrTomsghdr) {
441 if (!structMsghdr) {
442 jniThrowNullPointerException(env, "missing structMsghdr");
443 return false;
444 }
445
446 jclass StructMsghdrClass = JniConstants::GetStructMsghdrClass(env);
447
448 // Get fieldID of each item in StructMsghdr.
449 static jfieldID msgIovFid = env->GetFieldID(StructMsghdrClass,
450 "msg_iov",
451 "[Ljava/nio/ByteBuffer;");
452 if (!msgIovFid) {
453 return false;
454 }
455 static jfieldID msgControlFid = env->GetFieldID(StructMsghdrClass,
456 "msg_control",
457 "[Landroid/system/StructCmsghdr;");
458 if (!msgControlFid) {
459 return false;
460 }
461 static jfieldID msgFlagsFid = env->GetFieldID(StructMsghdrClass,
462 "msg_flags",
463 "I");
464 if (!msgFlagsFid) {
465 return false;
466 }
467
468 if (isFromStructCMsghdrTomsghdr) {
469 // Pick StructMsghdr.msg_iov[].
470 jobjectArray msgIovArray = reinterpret_cast<jobjectArray>(
471 env->GetObjectField(structMsghdr, msgIovFid));
472 if (!msgIovArray) {
473 jniThrowNullPointerException(env, "null StructMsghdr.msg_iov");
474 return false;
475 }
476 // In case sendmsg, IOV buffer are RO to send data,
477 // in case recvmsg, IOV buffer are RW to store received data.
478 if (byteBufferArrayToIOV(env, msgIovArray, mhdr, scopeBufArray) == false) {
479 return false;
480 }
481
482 if (!scopeBufArray.isRW()) {
483 jobjectArray structCmsghdrObjArray = reinterpret_cast<jobjectArray>(
484 env->GetObjectField(structMsghdr, msgControlFid));
485 if (structCmsghdrObjArray != NULL) {
486 // convert StrucCmsg[] <-> msghdr.msgcontrl
487 if (structCmsghdrArrayToMsgcontrol(env, structCmsghdrObjArray, mhdr) == false) {
488 return false;
489 }
490 }
491 } else {
492 // hardcode 512 for recvmsg/msg_controllen, it should be enough for recvmsg
493 mhdr.msg_controllen = 512;
494 mhdr.msg_control = (unsigned char*)malloc(mhdr.msg_controllen);
495 }
496
497 mhdr.msg_flags = env->GetIntField(structMsghdr, msgFlagsFid);
498 } else {
499 // StructMsghdr.msg_iov[]/msg_control[] are output paramenter.
500 // StructMsghdr.msg_iov[] data are already updated by recvmsg syscall directly.
501 // StructMsghdr.msg_control[] are set below.
502 if (msgcontrolToStructCmsghdrArray(env, structMsghdr, mhdr) == false)
503 return false;
504 env->SetIntField(structMsghdr, msgFlagsFid, mhdr.msg_flags);
505 }
506
507 return true;
508
509 }
510
511 // Convert Java StructMsghdr to C msghdr.
msghdrJavaToC(JNIEnv * env,jobject structMsghdr,struct msghdr & mhdr,ScopedByteBufferArray & scopedBufArray)512 bool msghdrJavaToC(JNIEnv* env, jobject structMsghdr, struct msghdr& mhdr,
513 ScopedByteBufferArray& scopedBufArray) {
514 return convertStructMsghdrAndmsghdr(env, structMsghdr, mhdr,
515 scopedBufArray, true);
516 }
517
518 // Convert C msghdr to Java StructMsghdr.
msghdrCToJava(JNIEnv * env,jobject structMsghdr,struct msghdr & mhdr,ScopedByteBufferArray & scopedBufArray)519 bool msghdrCToJava(JNIEnv* env, jobject structMsghdr, struct msghdr& mhdr,
520 ScopedByteBufferArray& scopedBufArray) {
521 return convertStructMsghdrAndmsghdr(env, structMsghdr, mhdr,
522 scopedBufArray, false);
523 }
524
setBlocking(int fd,bool blocking)525 bool setBlocking(int fd, bool blocking) {
526 int flags = fcntl(fd, F_GETFL);
527 if (flags == -1) {
528 return false;
529 }
530
531 if (!blocking) {
532 flags |= O_NONBLOCK;
533 } else {
534 flags &= ~O_NONBLOCK;
535 }
536
537 int rc = fcntl(fd, F_SETFL, flags);
538 return (rc != -1);
539 }
540