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