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