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