1 /* 2 * Copyright (C) 2006 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 "LocalSocketImpl" 18 19 #include "JNIHelp.h" 20 #include "jni.h" 21 #include "utils/Log.h" 22 #include "utils/misc.h" 23 24 #include <stdio.h> 25 #include <string.h> 26 #include <sys/types.h> 27 #include <sys/socket.h> 28 #include <sys/un.h> 29 #include <arpa/inet.h> 30 #include <netinet/in.h> 31 #include <stdlib.h> 32 #include <errno.h> 33 #include <unistd.h> 34 #include <sys/ioctl.h> 35 36 #include <cutils/sockets.h> 37 #include <netinet/tcp.h> 38 #include <ScopedUtfChars.h> 39 40 namespace android { 41 42 template <typename T> 43 void UNUSED(T t) {} 44 45 static jfieldID field_inboundFileDescriptors; 46 static jfieldID field_outboundFileDescriptors; 47 static jclass class_Credentials; 48 static jclass class_FileDescriptor; 49 static jmethodID method_CredentialsInit; 50 51 /* private native void connectLocal(FileDescriptor fd, 52 * String name, int namespace) throws IOException 53 */ 54 static void 55 socket_connect_local(JNIEnv *env, jobject object, 56 jobject fileDescriptor, jstring name, jint namespaceId) 57 { 58 int ret; 59 int fd; 60 61 fd = jniGetFDFromFileDescriptor(env, fileDescriptor); 62 63 if (env->ExceptionCheck()) { 64 return; 65 } 66 67 ScopedUtfChars nameUtf8(env, name); 68 69 ret = socket_local_client_connect( 70 fd, 71 nameUtf8.c_str(), 72 namespaceId, 73 SOCK_STREAM); 74 75 if (ret < 0) { 76 jniThrowIOException(env, errno); 77 return; 78 } 79 } 80 81 #define DEFAULT_BACKLOG 4 82 83 /* private native void bindLocal(FileDescriptor fd, String name, namespace) 84 * throws IOException; 85 */ 86 87 static void 88 socket_bind_local (JNIEnv *env, jobject object, jobject fileDescriptor, 89 jstring name, jint namespaceId) 90 { 91 int ret; 92 int fd; 93 94 if (name == NULL) { 95 jniThrowNullPointerException(env, NULL); 96 return; 97 } 98 99 fd = jniGetFDFromFileDescriptor(env, fileDescriptor); 100 101 if (env->ExceptionCheck()) { 102 return; 103 } 104 105 ScopedUtfChars nameUtf8(env, name); 106 107 ret = socket_local_server_bind(fd, nameUtf8.c_str(), namespaceId); 108 109 if (ret < 0) { 110 jniThrowIOException(env, errno); 111 return; 112 } 113 } 114 115 /* private native void listen_native(int fd, int backlog) throws IOException; */ 116 static void 117 socket_listen (JNIEnv *env, jobject object, jobject fileDescriptor, jint backlog) 118 { 119 int ret; 120 int fd; 121 122 fd = jniGetFDFromFileDescriptor(env, fileDescriptor); 123 124 if (env->ExceptionCheck()) { 125 return; 126 } 127 128 ret = listen(fd, backlog); 129 130 if (ret < 0) { 131 jniThrowIOException(env, errno); 132 return; 133 } 134 } 135 136 /* private native FileDescriptor 137 ** accept (FileDescriptor fd, LocalSocketImpl s) 138 ** throws IOException; 139 */ 140 static jobject 141 socket_accept (JNIEnv *env, jobject object, jobject fileDescriptor, jobject s) 142 { 143 union { 144 struct sockaddr address; 145 struct sockaddr_un un_address; 146 } sa; 147 148 int ret; 149 int retFD; 150 int fd; 151 socklen_t addrlen; 152 153 if (s == NULL) { 154 jniThrowNullPointerException(env, NULL); 155 return NULL; 156 } 157 158 fd = jniGetFDFromFileDescriptor(env, fileDescriptor); 159 160 if (env->ExceptionCheck()) { 161 return NULL; 162 } 163 164 do { 165 addrlen = sizeof(sa); 166 ret = accept(fd, &(sa.address), &addrlen); 167 } while (ret < 0 && errno == EINTR); 168 169 if (ret < 0) { 170 jniThrowIOException(env, errno); 171 return NULL; 172 } 173 174 retFD = ret; 175 176 return jniCreateFileDescriptor(env, retFD); 177 } 178 179 /* private native void shutdown(FileDescriptor fd, boolean shutdownInput) */ 180 181 static void 182 socket_shutdown (JNIEnv *env, jobject object, jobject fileDescriptor, 183 jboolean shutdownInput) 184 { 185 int ret; 186 int fd; 187 188 fd = jniGetFDFromFileDescriptor(env, fileDescriptor); 189 190 if (env->ExceptionCheck()) { 191 return; 192 } 193 194 ret = shutdown(fd, shutdownInput ? SHUT_RD : SHUT_WR); 195 196 if (ret < 0) { 197 jniThrowIOException(env, errno); 198 return; 199 } 200 } 201 202 static bool 203 java_opt_to_real(int optID, int* opt, int* level) 204 { 205 switch (optID) 206 { 207 case 4098: 208 *opt = SO_RCVBUF; 209 *level = SOL_SOCKET; 210 return true; 211 case 4097: 212 *opt = SO_SNDBUF; 213 *level = SOL_SOCKET; 214 return true; 215 case 4102: 216 *opt = SO_SNDTIMEO; 217 *level = SOL_SOCKET; 218 return true; 219 case 128: 220 *opt = SO_LINGER; 221 *level = SOL_SOCKET; 222 return true; 223 case 1: 224 *opt = TCP_NODELAY; 225 *level = IPPROTO_TCP; 226 return true; 227 case 4: 228 *opt = SO_REUSEADDR; 229 *level = SOL_SOCKET; 230 return true; 231 232 } 233 return false; 234 } 235 236 static jint 237 socket_getOption(JNIEnv *env, jobject object, jobject fileDescriptor, jint optID) 238 { 239 int ret, value; 240 int opt, level; 241 int fd; 242 243 socklen_t size = sizeof(int); 244 245 if (!java_opt_to_real(optID, &opt, &level)) { 246 jniThrowIOException(env, -1); 247 return 0; 248 } 249 250 fd = jniGetFDFromFileDescriptor(env, fileDescriptor); 251 252 if (env->ExceptionCheck()) { 253 return 0; 254 } 255 256 switch (opt) 257 { 258 case SO_LINGER: 259 { 260 struct linger lingr; 261 size = sizeof(lingr); 262 ret = getsockopt(fd, level, opt, &lingr, &size); 263 if (!lingr.l_onoff) { 264 value = -1; 265 } else { 266 value = lingr.l_linger; 267 } 268 break; 269 } 270 default: 271 ret = getsockopt(fd, level, opt, &value, &size); 272 break; 273 } 274 275 276 if (ret != 0) { 277 jniThrowIOException(env, errno); 278 return 0; 279 } 280 281 return value; 282 } 283 284 static void socket_setOption( 285 JNIEnv *env, jobject object, jobject fileDescriptor, jint optID, 286 jint boolValue, jint intValue) { 287 int ret; 288 int optname; 289 int level; 290 int fd; 291 292 if (!java_opt_to_real(optID, &optname, &level)) { 293 jniThrowIOException(env, -1); 294 return; 295 } 296 297 fd = jniGetFDFromFileDescriptor(env, fileDescriptor); 298 299 if (env->ExceptionCheck()) { 300 return; 301 } 302 303 switch (optname) { 304 case SO_LINGER: { 305 /* 306 * SO_LINGER is special because it needs to use a special 307 * "linger" struct as well as use the incoming boolean 308 * argument specially. 309 */ 310 struct linger lingr; 311 lingr.l_onoff = boolValue ? 1 : 0; // Force it to be 0 or 1. 312 lingr.l_linger = intValue; 313 ret = setsockopt(fd, level, optname, &lingr, sizeof(lingr)); 314 break; 315 } 316 case SO_SNDTIMEO: { 317 /* 318 * SO_TIMEOUT from the core library gets converted to 319 * SO_SNDTIMEO, but the option is supposed to set both 320 * send and receive timeouts. Note: The incoming timeout 321 * value is in milliseconds. 322 */ 323 struct timeval timeout; 324 timeout.tv_sec = intValue / 1000; 325 timeout.tv_usec = (intValue % 1000) * 1000; 326 327 ret = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, 328 (void *)&timeout, sizeof(timeout)); 329 330 if (ret == 0) { 331 ret = setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, 332 (void *)&timeout, sizeof(timeout)); 333 } 334 335 break; 336 } 337 default: { 338 /* 339 * In all other cases, the translated option level and 340 * optname may be used directly for a call to setsockopt(). 341 */ 342 ret = setsockopt(fd, level, optname, &intValue, sizeof(intValue)); 343 break; 344 } 345 } 346 347 if (ret != 0) { 348 jniThrowIOException(env, errno); 349 return; 350 } 351 } 352 static jint socket_pending (JNIEnv *env, jobject object, 353 jobject fileDescriptor) 354 { 355 int fd; 356 357 fd = jniGetFDFromFileDescriptor(env, fileDescriptor); 358 359 if (env->ExceptionCheck()) { 360 return (jint)-1; 361 } 362 363 int pending; 364 int ret = ioctl(fd, TIOCOUTQ, &pending); 365 366 // If this were a non-socket fd, there would be other cases to worry 367 // about... 368 369 //ALOGD("socket_pending, ioctl ret:%d, pending:%d", ret, pending); 370 if (ret < 0) { 371 jniThrowIOException(env, errno); 372 return (jint) 0; 373 } 374 375 return (jint)pending; 376 } 377 static jint socket_available (JNIEnv *env, jobject object, 378 jobject fileDescriptor) 379 { 380 int fd; 381 382 fd = jniGetFDFromFileDescriptor(env, fileDescriptor); 383 384 if (env->ExceptionCheck()) { 385 return (jint)-1; 386 } 387 388 #if 1 389 int avail; 390 int ret = ioctl(fd, FIONREAD, &avail); 391 392 // If this were a non-socket fd, there would be other cases to worry 393 // about... 394 395 if (ret < 0) { 396 jniThrowIOException(env, errno); 397 return (jint) 0; 398 } 399 400 return (jint)avail; 401 #else 402 // there appears to be a bionic bug that prevents this version from working. 403 404 ssize_t ret; 405 struct msghdr msg; 406 407 memset(&msg, 0, sizeof(msg)); 408 409 do { 410 ret = recvmsg(fd, &msg, MSG_PEEK | MSG_DONTWAIT | MSG_NOSIGNAL); 411 } while (ret < 0 && errno == EINTR); 412 413 414 // MSG_PEEK returns 0 on EOF and EWOULDBLOCK on none available 415 if (ret < 0 && errno == EWOULDBLOCK) { 416 return 0; 417 } if (ret < 0) { 418 jniThrowIOException(env, errno); 419 return -1; 420 } 421 422 return (jint)ret; 423 #endif 424 } 425 426 /** 427 * Processes ancillary data, handling only 428 * SCM_RIGHTS. Creates appropriate objects and sets appropriate 429 * fields in the LocalSocketImpl object. Returns 0 on success 430 * or -1 if an exception was thrown. 431 */ 432 static int socket_process_cmsg(JNIEnv *env, jobject thisJ, struct msghdr * pMsg) 433 { 434 struct cmsghdr *cmsgptr; 435 436 for (cmsgptr = CMSG_FIRSTHDR(pMsg); 437 cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(pMsg, cmsgptr)) { 438 439 if (cmsgptr->cmsg_level != SOL_SOCKET) { 440 continue; 441 } 442 443 if (cmsgptr->cmsg_type == SCM_RIGHTS) { 444 int *pDescriptors = (int *)CMSG_DATA(cmsgptr); 445 jobjectArray fdArray; 446 int count 447 = ((cmsgptr->cmsg_len - CMSG_LEN(0)) / sizeof(int)); 448 449 if (count < 0) { 450 jniThrowException(env, "java/io/IOException", 451 "invalid cmsg length"); 452 return -1; 453 } 454 455 fdArray = env->NewObjectArray(count, class_FileDescriptor, NULL); 456 457 if (fdArray == NULL) { 458 return -1; 459 } 460 461 for (int i = 0; i < count; i++) { 462 jobject fdObject 463 = jniCreateFileDescriptor(env, pDescriptors[i]); 464 465 if (env->ExceptionCheck()) { 466 return -1; 467 } 468 469 env->SetObjectArrayElement(fdArray, i, fdObject); 470 471 if (env->ExceptionCheck()) { 472 return -1; 473 } 474 } 475 476 env->SetObjectField(thisJ, field_inboundFileDescriptors, fdArray); 477 478 if (env->ExceptionCheck()) { 479 return -1; 480 } 481 } 482 } 483 484 return 0; 485 } 486 487 /** 488 * Reads data from a socket into buf, processing any ancillary data 489 * and adding it to thisJ. 490 * 491 * Returns the length of normal data read, or -1 if an exception has 492 * been thrown in this function. 493 */ 494 static ssize_t socket_read_all(JNIEnv *env, jobject thisJ, int fd, 495 void *buffer, size_t len) 496 { 497 ssize_t ret; 498 struct msghdr msg; 499 struct iovec iv; 500 unsigned char *buf = (unsigned char *)buffer; 501 // Enough buffer for a pile of fd's. We throw an exception if 502 // this buffer is too small. 503 struct cmsghdr cmsgbuf[2*sizeof(cmsghdr) + 0x100]; 504 505 memset(&msg, 0, sizeof(msg)); 506 memset(&iv, 0, sizeof(iv)); 507 508 iv.iov_base = buf; 509 iv.iov_len = len; 510 511 msg.msg_iov = &iv; 512 msg.msg_iovlen = 1; 513 msg.msg_control = cmsgbuf; 514 msg.msg_controllen = sizeof(cmsgbuf); 515 516 do { 517 ret = recvmsg(fd, &msg, MSG_NOSIGNAL); 518 } while (ret < 0 && errno == EINTR); 519 520 if (ret < 0 && errno == EPIPE) { 521 // Treat this as an end of stream 522 return 0; 523 } 524 525 if (ret < 0) { 526 jniThrowIOException(env, errno); 527 return -1; 528 } 529 530 if ((msg.msg_flags & (MSG_CTRUNC | MSG_OOB | MSG_ERRQUEUE)) != 0) { 531 // To us, any of the above flags are a fatal error 532 533 jniThrowException(env, "java/io/IOException", 534 "Unexpected error or truncation during recvmsg()"); 535 536 return -1; 537 } 538 539 if (ret >= 0) { 540 socket_process_cmsg(env, thisJ, &msg); 541 } 542 543 return ret; 544 } 545 546 /** 547 * Writes all the data in the specified buffer to the specified socket. 548 * 549 * Returns 0 on success or -1 if an exception was thrown. 550 */ 551 static int socket_write_all(JNIEnv *env, jobject object, int fd, 552 void *buf, size_t len) 553 { 554 ssize_t ret; 555 struct msghdr msg; 556 unsigned char *buffer = (unsigned char *)buf; 557 memset(&msg, 0, sizeof(msg)); 558 559 jobjectArray outboundFds 560 = (jobjectArray)env->GetObjectField( 561 object, field_outboundFileDescriptors); 562 563 if (env->ExceptionCheck()) { 564 return -1; 565 } 566 567 struct cmsghdr *cmsg; 568 int countFds = outboundFds == NULL ? 0 : env->GetArrayLength(outboundFds); 569 int fds[countFds]; 570 char msgbuf[CMSG_SPACE(countFds)]; 571 572 // Add any pending outbound file descriptors to the message 573 if (outboundFds != NULL) { 574 575 if (env->ExceptionCheck()) { 576 return -1; 577 } 578 579 for (int i = 0; i < countFds; i++) { 580 jobject fdObject = env->GetObjectArrayElement(outboundFds, i); 581 if (env->ExceptionCheck()) { 582 return -1; 583 } 584 585 fds[i] = jniGetFDFromFileDescriptor(env, fdObject); 586 if (env->ExceptionCheck()) { 587 return -1; 588 } 589 } 590 591 // See "man cmsg" really 592 msg.msg_control = msgbuf; 593 msg.msg_controllen = sizeof msgbuf; 594 cmsg = CMSG_FIRSTHDR(&msg); 595 cmsg->cmsg_level = SOL_SOCKET; 596 cmsg->cmsg_type = SCM_RIGHTS; 597 cmsg->cmsg_len = CMSG_LEN(sizeof fds); 598 memcpy(CMSG_DATA(cmsg), fds, sizeof fds); 599 } 600 601 // We only write our msg_control during the first write 602 while (len > 0) { 603 struct iovec iv; 604 memset(&iv, 0, sizeof(iv)); 605 606 iv.iov_base = buffer; 607 iv.iov_len = len; 608 609 msg.msg_iov = &iv; 610 msg.msg_iovlen = 1; 611 612 do { 613 ret = sendmsg(fd, &msg, MSG_NOSIGNAL); 614 } while (ret < 0 && errno == EINTR); 615 616 if (ret < 0) { 617 jniThrowIOException(env, errno); 618 return -1; 619 } 620 621 buffer += ret; 622 len -= ret; 623 624 // Wipes out any msg_control too 625 memset(&msg, 0, sizeof(msg)); 626 } 627 628 return 0; 629 } 630 631 static jint socket_read (JNIEnv *env, jobject object, jobject fileDescriptor) 632 { 633 int fd; 634 int err; 635 636 if (fileDescriptor == NULL) { 637 jniThrowNullPointerException(env, NULL); 638 return (jint)-1; 639 } 640 641 fd = jniGetFDFromFileDescriptor(env, fileDescriptor); 642 643 if (env->ExceptionCheck()) { 644 return (jint)0; 645 } 646 647 unsigned char buf; 648 649 err = socket_read_all(env, object, fd, &buf, 1); 650 651 if (err < 0) { 652 jniThrowIOException(env, errno); 653 return (jint)0; 654 } 655 656 if (err == 0) { 657 // end of file 658 return (jint)-1; 659 } 660 661 return (jint)buf; 662 } 663 664 static jint socket_readba (JNIEnv *env, jobject object, 665 jbyteArray buffer, jint off, jint len, jobject fileDescriptor) 666 { 667 int fd; 668 jbyte* byteBuffer; 669 int ret; 670 671 if (fileDescriptor == NULL || buffer == NULL) { 672 jniThrowNullPointerException(env, NULL); 673 return (jint)-1; 674 } 675 676 if (off < 0 || len < 0 || (off + len) > env->GetArrayLength(buffer)) { 677 jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL); 678 return (jint)-1; 679 } 680 681 if (len == 0) { 682 // because socket_read_all returns 0 on EOF 683 return 0; 684 } 685 686 fd = jniGetFDFromFileDescriptor(env, fileDescriptor); 687 688 if (env->ExceptionCheck()) { 689 return (jint)-1; 690 } 691 692 byteBuffer = env->GetByteArrayElements(buffer, NULL); 693 694 if (NULL == byteBuffer) { 695 // an exception will have been thrown 696 return (jint)-1; 697 } 698 699 ret = socket_read_all(env, object, 700 fd, byteBuffer + off, len); 701 702 // A return of -1 above means an exception is pending 703 704 env->ReleaseByteArrayElements(buffer, byteBuffer, 0); 705 706 return (jint) ((ret == 0) ? -1 : ret); 707 } 708 709 static void socket_write (JNIEnv *env, jobject object, 710 jint b, jobject fileDescriptor) 711 { 712 int fd; 713 int err; 714 715 if (fileDescriptor == NULL) { 716 jniThrowNullPointerException(env, NULL); 717 return; 718 } 719 720 fd = jniGetFDFromFileDescriptor(env, fileDescriptor); 721 722 if (env->ExceptionCheck()) { 723 return; 724 } 725 726 err = socket_write_all(env, object, fd, &b, 1); 727 UNUSED(err); 728 // A return of -1 above means an exception is pending 729 } 730 731 static void socket_writeba (JNIEnv *env, jobject object, 732 jbyteArray buffer, jint off, jint len, jobject fileDescriptor) 733 { 734 int fd; 735 int err; 736 jbyte* byteBuffer; 737 738 if (fileDescriptor == NULL || buffer == NULL) { 739 jniThrowNullPointerException(env, NULL); 740 return; 741 } 742 743 if (off < 0 || len < 0 || (off + len) > env->GetArrayLength(buffer)) { 744 jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL); 745 return; 746 } 747 748 fd = jniGetFDFromFileDescriptor(env, fileDescriptor); 749 750 if (env->ExceptionCheck()) { 751 return; 752 } 753 754 byteBuffer = env->GetByteArrayElements(buffer,NULL); 755 756 if (NULL == byteBuffer) { 757 // an exception will have been thrown 758 return; 759 } 760 761 err = socket_write_all(env, object, fd, 762 byteBuffer + off, len); 763 UNUSED(err); 764 // A return of -1 above means an exception is pending 765 766 env->ReleaseByteArrayElements(buffer, byteBuffer, JNI_ABORT); 767 } 768 769 static jobject socket_get_peer_credentials(JNIEnv *env, 770 jobject object, jobject fileDescriptor) 771 { 772 int err; 773 int fd; 774 775 if (fileDescriptor == NULL) { 776 jniThrowNullPointerException(env, NULL); 777 return NULL; 778 } 779 780 fd = jniGetFDFromFileDescriptor(env, fileDescriptor); 781 782 if (env->ExceptionCheck()) { 783 return NULL; 784 } 785 786 struct ucred creds; 787 788 memset(&creds, 0, sizeof(creds)); 789 socklen_t szCreds = sizeof(creds); 790 791 err = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &creds, &szCreds); 792 793 if (err < 0) { 794 jniThrowIOException(env, errno); 795 return NULL; 796 } 797 798 if (szCreds == 0) { 799 return NULL; 800 } 801 802 return env->NewObject(class_Credentials, method_CredentialsInit, 803 creds.pid, creds.uid, creds.gid); 804 } 805 806 #if 0 807 //TODO change this to return an instance of LocalSocketAddress 808 static jobject socket_getSockName(JNIEnv *env, 809 jobject object, jobject fileDescriptor) 810 { 811 int err; 812 int fd; 813 814 if (fileDescriptor == NULL) { 815 jniThrowNullPointerException(env, NULL); 816 return NULL; 817 } 818 819 fd = jniGetFDFromFileDescriptor(env, fileDescriptor); 820 821 if (env->ExceptionCheck()) { 822 return NULL; 823 } 824 825 union { 826 struct sockaddr address; 827 struct sockaddr_un un_address; 828 } sa; 829 830 memset(&sa, 0, sizeof(sa)); 831 832 socklen_t namelen = sizeof(sa); 833 err = getsockname(fd, &(sa.address), &namelen); 834 835 if (err < 0) { 836 jniThrowIOException(env, errno); 837 return NULL; 838 } 839 840 if (sa.address.sa_family != AF_UNIX) { 841 // We think we're an impl only for AF_UNIX, so this should never happen. 842 843 jniThrowIOException(env, EINVAL); 844 return NULL; 845 } 846 847 if (sa.un_address.sun_path[0] == '\0') { 848 } else { 849 } 850 851 852 853 854 } 855 #endif 856 857 /* 858 * JNI registration. 859 */ 860 static JNINativeMethod gMethods[] = { 861 /* name, signature, funcPtr */ 862 {"getOption_native", "(Ljava/io/FileDescriptor;I)I", (void*)socket_getOption}, 863 {"setOption_native", "(Ljava/io/FileDescriptor;III)V", (void*)socket_setOption}, 864 {"connectLocal", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V", 865 (void*)socket_connect_local}, 866 {"bindLocal", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V", (void*)socket_bind_local}, 867 {"listen_native", "(Ljava/io/FileDescriptor;I)V", (void*)socket_listen}, 868 {"accept", "(Ljava/io/FileDescriptor;Landroid/net/LocalSocketImpl;)Ljava/io/FileDescriptor;", (void*)socket_accept}, 869 {"shutdown", "(Ljava/io/FileDescriptor;Z)V", (void*)socket_shutdown}, 870 {"available_native", "(Ljava/io/FileDescriptor;)I", (void*) socket_available}, 871 {"pending_native", "(Ljava/io/FileDescriptor;)I", (void*) socket_pending}, 872 {"read_native", "(Ljava/io/FileDescriptor;)I", (void*) socket_read}, 873 {"readba_native", "([BIILjava/io/FileDescriptor;)I", (void*) socket_readba}, 874 {"writeba_native", "([BIILjava/io/FileDescriptor;)V", (void*) socket_writeba}, 875 {"write_native", "(ILjava/io/FileDescriptor;)V", (void*) socket_write}, 876 {"getPeerCredentials_native", 877 "(Ljava/io/FileDescriptor;)Landroid/net/Credentials;", 878 (void*) socket_get_peer_credentials} 879 //,{"getSockName_native", "(Ljava/io/FileDescriptor;)Ljava/lang/String;", 880 // (void *) socket_getSockName} 881 882 }; 883 884 int register_android_net_LocalSocketImpl(JNIEnv *env) 885 { 886 jclass clazz; 887 888 clazz = env->FindClass("android/net/LocalSocketImpl"); 889 890 if (clazz == NULL) { 891 goto error; 892 } 893 894 field_inboundFileDescriptors = env->GetFieldID(clazz, 895 "inboundFileDescriptors", "[Ljava/io/FileDescriptor;"); 896 897 if (field_inboundFileDescriptors == NULL) { 898 goto error; 899 } 900 901 field_outboundFileDescriptors = env->GetFieldID(clazz, 902 "outboundFileDescriptors", "[Ljava/io/FileDescriptor;"); 903 904 if (field_outboundFileDescriptors == NULL) { 905 goto error; 906 } 907 908 class_Credentials = env->FindClass("android/net/Credentials"); 909 910 if (class_Credentials == NULL) { 911 goto error; 912 } 913 914 class_Credentials = (jclass)env->NewGlobalRef(class_Credentials); 915 916 class_FileDescriptor = env->FindClass("java/io/FileDescriptor"); 917 918 if (class_FileDescriptor == NULL) { 919 goto error; 920 } 921 922 class_FileDescriptor = (jclass)env->NewGlobalRef(class_FileDescriptor); 923 924 method_CredentialsInit 925 = env->GetMethodID(class_Credentials, "<init>", "(III)V"); 926 927 if (method_CredentialsInit == NULL) { 928 goto error; 929 } 930 931 return jniRegisterNativeMethods(env, 932 "android/net/LocalSocketImpl", gMethods, NELEM(gMethods)); 933 934 error: 935 ALOGE("Error registering android.net.LocalSocketImpl"); 936 return -1; 937 } 938 939 }; 940