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