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