• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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