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