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