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