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