1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18#include "JNIHelp.h" 19#include "jni.h" 20#include "errno.h" 21 22#include <string.h> 23#include <stdlib.h> 24#include <unistd.h> 25#include <stdio.h> 26#include <sys/socket.h> 27#include <net/if.h> 28#include <netinet/in.h> 29#include <sys/ioctl.h> 30 31//-------------------------------------------------------------------- 32// TODO copied from OSNetworkSystem. Might get into a separate .h file 33/** 34 * Throws an IOException with the given message. 35 */ 36static void throwSocketException(JNIEnv *env, const char *message) { 37 jclass exClass = (*env)->FindClass(env, "java/net/SocketException"); 38 39 if(exClass == NULL) { 40 LOGE("Unable to find class java/net/SocketException"); 41 } else { 42 (*env)->ThrowNew(env, exClass, message); 43 } 44} 45 46 47/** 48 * Throws a NullPointerException. 49 */ 50static void throwNullPointerException(JNIEnv *env) { 51 jclass exClass = (*env)->FindClass(env, "java/lang/NullPointerException"); 52 53 if(exClass == NULL) { 54 LOGE("Unable to find class java/lang/NullPointerException"); 55 } else { 56 (*env)->ThrowNew(env, exClass, NULL); 57 } 58} 59 60/** 61 * @name Socket Errors 62 * Error codes for socket operations 63 * 64 * @internal SOCKERR* range from -200 to -299 avoid overlap 65 */ 66#define SOCKERR_BADSOCKET -200 /* generic error */ 67#define SOCKERR_NOTINITIALIZED -201 /* socket library uninitialized */ 68#define SOCKERR_BADAF -202 /* bad address family */ 69#define SOCKERR_BADPROTO -203 /* bad protocol */ 70#define SOCKERR_BADTYPE -204 /* bad type */ 71#define SOCKERR_SYSTEMBUSY -205 /* system busy handling requests */ 72#define SOCKERR_SYSTEMFULL -206 /* too many sockets */ 73#define SOCKERR_NOTCONNECTED -207 /* socket is not connected */ 74#define SOCKERR_INTERRUPTED -208 /* the call was cancelled */ 75#define SOCKERR_TIMEOUT -209 /* the operation timed out */ 76#define SOCKERR_CONNRESET -210 /* the connection was reset */ 77#define SOCKERR_WOULDBLOCK -211 /* the socket is marked as nonblocking operation would block */ 78#define SOCKERR_ADDRNOTAVAIL -212 /* address not available */ 79#define SOCKERR_ADDRINUSE -213 /* address already in use */ 80#define SOCKERR_NOTBOUND -214 /* the socket is not bound */ 81#define SOCKERR_UNKNOWNSOCKET -215 /* resolution of fileDescriptor to socket failed */ 82#define SOCKERR_INVALIDTIMEOUT -216 /* the specified timeout is invalid */ 83#define SOCKERR_FDSETFULL -217 /* Unable to create an FDSET */ 84#define SOCKERR_TIMEVALFULL -218 /* Unable to create a TIMEVAL */ 85#define SOCKERR_REMSOCKSHUTDOWN -219 /* The remote socket has shutdown gracefully */ 86#define SOCKERR_NOTLISTENING -220 /* listen() was not invoked prior to accept() */ 87#define SOCKERR_NOTSTREAMSOCK -221 /* The socket does not support connection-oriented service */ 88#define SOCKERR_ALREADYBOUND -222 /* The socket is already bound to an address */ 89#define SOCKERR_NBWITHLINGER -223 /* The socket is marked non-blocking & SO_LINGER is non-zero */ 90#define SOCKERR_ISCONNECTED -224 /* The socket is already connected */ 91#define SOCKERR_NOBUFFERS -225 /* No buffer space is available */ 92#define SOCKERR_HOSTNOTFOUND -226 /* Authoritative Answer Host not found */ 93#define SOCKERR_NODATA -227 /* Valid name, no data record of requested type */ 94#define SOCKERR_BOUNDORCONN -228 /* The socket has not been bound or is already connected */ 95#define SOCKERR_OPNOTSUPP -229 /* The socket does not support the operation */ 96#define SOCKERR_OPTUNSUPP -230 /* The socket option is not supported */ 97#define SOCKERR_OPTARGSINVALID -231 /* The socket option arguments are invalid */ 98#define SOCKERR_SOCKLEVELINVALID -232 /* The socket level is invalid */ 99#define SOCKERR_TIMEOUTFAILURE -233 100#define SOCKERR_SOCKADDRALLOCFAIL -234 /* Unable to allocate the sockaddr structure */ 101#define SOCKERR_FDSET_SIZEBAD -235 /* The calculated maximum size of the file descriptor set is bad */ 102#define SOCKERR_UNKNOWNFLAG -236 /* The flag is unknown */ 103#define SOCKERR_MSGSIZE -237 /* The datagram was too big to fit the specified buffer & was truncated. */ 104#define SOCKERR_NORECOVERY -238 /* The operation failed with no recovery possible */ 105#define SOCKERR_ARGSINVALID -239 /* The arguments are invalid */ 106#define SOCKERR_BADDESC -240 /* The socket argument is not a valid file descriptor */ 107#define SOCKERR_NOTSOCK -241 /* The socket argument is not a socket */ 108#define SOCKERR_HOSTENTALLOCFAIL -242 /* Unable to allocate the hostent structure */ 109#define SOCKERR_TIMEVALALLOCFAIL -243 /* Unable to allocate the timeval structure */ 110#define SOCKERR_LINGERALLOCFAIL -244 /* Unable to allocate the linger structure */ 111#define SOCKERR_IPMREQALLOCFAIL -245 /* Unable to allocate the ipmreq structure */ 112#define SOCKERR_FDSETALLOCFAIL -246 /* Unable to allocate the fdset structure */ 113#define SOCKERR_OPFAILED -247 114#define SOCKERR_VALUE_NULL -248 /* The value indexed was NULL */ 115#define SOCKERR_CONNECTION_REFUSED -249 /* connection was refused */ 116#define SOCKERR_ENETUNREACH -250 /* network is not reachable */ 117#define SOCKERR_EACCES -251 /* permissions do not allow action on socket */ 118 119/** 120 * Answer the errorString corresponding to the errorNumber, if available. 121 * This function will answer a default error string, if the errorNumber is not 122 * recognized. 123 * 124 * This function will have to be reworked to handle internationalization properly, removing 125 * the explicit strings. 126 * 127 * @param anErrorNum the error code to resolve to a human readable string 128 * 129 * @return a human readable error string 130 */ 131 132static char * netLookupErrorString(int anErrorNum) { 133 switch(anErrorNum) { 134 case SOCKERR_BADSOCKET: 135 return "Bad socket"; 136 case SOCKERR_NOTINITIALIZED: 137 return "Socket library uninitialized"; 138 case SOCKERR_BADAF: 139 return "Bad address family"; 140 case SOCKERR_BADPROTO: 141 return "Bad protocol"; 142 case SOCKERR_BADTYPE: 143 return "Bad type"; 144 case SOCKERR_SYSTEMBUSY: 145 return "System busy handling requests"; 146 case SOCKERR_SYSTEMFULL: 147 return "Too many sockets allocated"; 148 case SOCKERR_NOTCONNECTED: 149 return "Socket is not connected"; 150 case SOCKERR_INTERRUPTED: 151 return "The call was cancelled"; 152 case SOCKERR_TIMEOUT: 153 return "The operation timed out"; 154 case SOCKERR_CONNRESET: 155 return "The connection was reset"; 156 case SOCKERR_WOULDBLOCK: 157 return "The socket is marked as nonblocking operation would block"; 158 case SOCKERR_ADDRNOTAVAIL: 159 return "The address is not available"; 160 case SOCKERR_ADDRINUSE: 161 return "The address is already in use"; 162 case SOCKERR_NOTBOUND: 163 return "The socket is not bound"; 164 case SOCKERR_UNKNOWNSOCKET: 165 return "Resolution of the FileDescriptor to socket failed"; 166 case SOCKERR_INVALIDTIMEOUT: 167 return "The specified timeout is invalid"; 168 case SOCKERR_FDSETFULL: 169 return "Unable to create an FDSET"; 170 case SOCKERR_TIMEVALFULL: 171 return "Unable to create a TIMEVAL"; 172 case SOCKERR_REMSOCKSHUTDOWN: 173 return "The remote socket has shutdown gracefully"; 174 case SOCKERR_NOTLISTENING: 175 return "Listen() was not invoked prior to accept()"; 176 case SOCKERR_NOTSTREAMSOCK: 177 return "The socket does not support connection-oriented service"; 178 case SOCKERR_ALREADYBOUND: 179 return "The socket is already bound to an address"; 180 case SOCKERR_NBWITHLINGER: 181 return "The socket is marked non-blocking & SO_LINGER is non-zero"; 182 case SOCKERR_ISCONNECTED: 183 return "The socket is already connected"; 184 case SOCKERR_NOBUFFERS: 185 return "No buffer space is available"; 186 case SOCKERR_HOSTNOTFOUND: 187 return "Authoritative Answer Host not found"; 188 case SOCKERR_NODATA: 189 return "Valid name, no data record of requested type"; 190 case SOCKERR_BOUNDORCONN: 191 return "The socket has not been bound or is already connected"; 192 case SOCKERR_OPNOTSUPP: 193 return "The socket does not support the operation"; 194 case SOCKERR_OPTUNSUPP: 195 return "The socket option is not supported"; 196 case SOCKERR_OPTARGSINVALID: 197 return "The socket option arguments are invalid"; 198 case SOCKERR_SOCKLEVELINVALID: 199 return "The socket level is invalid"; 200 case SOCKERR_TIMEOUTFAILURE: 201 return "The timeout operation failed"; 202 case SOCKERR_SOCKADDRALLOCFAIL: 203 return "Failed to allocate address structure"; 204 case SOCKERR_FDSET_SIZEBAD: 205 return "The calculated maximum size of the file descriptor set is bad"; 206 case SOCKERR_UNKNOWNFLAG: 207 return "The flag is unknown"; 208 case SOCKERR_MSGSIZE: 209 return "The datagram was too big to fit the specified buffer, so truncated"; 210 case SOCKERR_NORECOVERY: 211 return "The operation failed with no recovery possible"; 212 case SOCKERR_ARGSINVALID: 213 return "The arguments are invalid"; 214 case SOCKERR_BADDESC: 215 return "The socket argument is not a valid file descriptor"; 216 case SOCKERR_NOTSOCK: 217 return "The socket argument is not a socket"; 218 case SOCKERR_HOSTENTALLOCFAIL: 219 return "Unable to allocate the hostent structure"; 220 case SOCKERR_TIMEVALALLOCFAIL: 221 return "Unable to allocate the timeval structure"; 222 case SOCKERR_LINGERALLOCFAIL: 223 return "Unable to allocate the linger structure"; 224 case SOCKERR_IPMREQALLOCFAIL: 225 return "Unable to allocate the ipmreq structure"; 226 case SOCKERR_FDSETALLOCFAIL: 227 return "Unable to allocate the fdset structure"; 228 case SOCKERR_CONNECTION_REFUSED: 229 return "Connection refused"; 230 231 default: 232 return "unkown error"; 233 } 234} 235 236/** 237 * Converts a native address structure to a 4-byte array. Throws a 238 * NullPointerException or an IOException in case of error. This is 239 * signaled by a return value of -1. The normal return value is 0. 240 */ 241static int structInToJavaAddress( 242 JNIEnv *env, struct in_addr *address, jbyteArray java_address) { 243 244 if(java_address == NULL) { 245 throwNullPointerException(env); 246 return -1; 247 } 248 249 if((*env)->GetArrayLength(env, java_address) != sizeof(address->s_addr)) { 250 jniThrowIOException(env, errno); 251 return -1; 252 } 253 254 jbyte *java_address_bytes; 255 256 java_address_bytes = (*env)->GetByteArrayElements(env, java_address, NULL); 257 258 memcpy(java_address_bytes, &(address->s_addr), sizeof(address->s_addr)); 259 260 (*env)->ReleaseByteArrayElements(env, java_address, java_address_bytes, 0); 261 262 return 0; 263} 264 265static jobject structInToInetAddress(JNIEnv *env, struct in_addr *address) { 266 jbyteArray bytes; 267 int success; 268 269 bytes = (*env)->NewByteArray(env, 4); 270 271 if(bytes == NULL) { 272 return NULL; 273 } 274 275 success = structInToJavaAddress(env, address, bytes); 276 277 if(success < 0) { 278 return NULL; 279 } 280 281 jclass iaddrclass = (*env)->FindClass(env, "java/net/InetAddress"); 282 283 if(iaddrclass == NULL) { 284 LOGE("Can't find java/net/InetAddress"); 285 jniThrowException(env, "java/lang/ClassNotFoundException", "java.net.InetAddress"); 286 return NULL; 287 } 288 289 jmethodID iaddrgetbyaddress = (*env)->GetStaticMethodID(env, iaddrclass, "getByAddress", "([B)Ljava/net/InetAddress;"); 290 291 if(iaddrgetbyaddress == NULL) { 292 LOGE("Can't find method InetAddress.getByAddress(byte[] val)"); 293 jniThrowException(env, "java/lang/NoSuchMethodError", "InetAddress.getByAddress(byte[] val)"); 294 return NULL; 295 } 296 297 return (*env)->CallStaticObjectMethod(env, iaddrclass, iaddrgetbyaddress, bytes); 298} 299//-------------------------------------------------------------------- 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322/* structure for returning either and IPV4 or IPV6 ip address */ 323typedef struct ipAddress_struct { 324 union { 325 char bytes[sizeof(struct in_addr)]; 326 struct in_addr inAddr; 327 } addr; 328 unsigned int length; 329 unsigned int scope; 330} ipAddress_struct; 331 332/* structure for returning network interface information */ 333typedef struct NetworkInterface_struct { 334 char *name; 335 char *displayName; 336 unsigned int numberAddresses; 337 unsigned int index; 338 struct ipAddress_struct *addresses; 339} NetworkInterface_struct; 340 341/* array of network interface structures */ 342typedef struct NetworkInterfaceArray_struct { 343 unsigned int length; 344 struct NetworkInterface_struct *elements; 345} NetworkInterfaceArray_struct; 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373/** 374 * Frees the memory allocated for the hyNetworkInterface_struct array passed in 375 * 376 * @param[in] portLibrary The port library. 377 * @param[in] handle Pointer to array of network interface structures to be freed 378 * 379 * @return 0 on success 380*/ 381int sock_free_network_interface_struct (struct NetworkInterfaceArray_struct *array) { 382 unsigned int i = 0; 383 384 if((array != NULL) && (array->elements != NULL)) { 385 386 /* free the allocated memory in each of the structures */ 387 for(i = 0; i < array->length; i++) { 388 389 /* free the name, displayName and addresses */ 390 if(array->elements[i].name != NULL) { 391 free(array->elements[i].name); 392 } 393 394 if(array->elements[i].displayName != NULL) { 395 free(array->elements[i].displayName); 396 } 397 398 if(array->elements[i].addresses != NULL) { 399 free(array->elements[i].addresses); 400 } 401 } 402 403 /* now free the array itself */ 404 free(array->elements); 405 } 406 407 return 0; 408} 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438/** 439 * Queries and returns the information for the network interfaces that are currently active within the system. 440 * Applications are responsible for freeing the memory returned via the handle. 441 * 442 * @param[in] portLibrary The port library. 443 * @param[in,out] array Pointer to structure with array of network interface entries 444 * @param[in] boolean which indicates if we should prefer the IPv4 stack or not 445 * 446 * @return The number of elements in handle on success, negatvie portable error code on failure. 447 -WSANO_RECOVERY if system calls required to get the info fail, -WSAENOBUFS if memory allocation fails 448 * @note A return value of 0 indicates no interfaces exist 449*/ 450int sockGetNetworkInterfaces(struct NetworkInterfaceArray_struct * array) { 451 452 struct NetworkInterface_struct *interfaces = NULL; 453 unsigned int nameLength = 0; 454 unsigned int currentAdapterIndex = 0; 455 unsigned int counter = 0; 456 unsigned int result = 0; 457 unsigned int numAddresses = 0; 458 unsigned int currentIPAddressIndex = 0; 459 unsigned int numAdapters = 0; 460 int err = 0; 461 462 struct ifconf ifc; 463 int len = 32 * sizeof(struct ifreq); 464 int socketP = 0; 465 unsigned int totalInterfaces = 0; 466 struct ifreq reqCopy; 467 unsigned int counter2 = 0; 468 char *lastName = NULL; 469 470 int ifconfCommand = SIOCGIFCONF; 471 472 /* this method is not guarranteed to return the IPV6 addresses. Code is include so that if the platform returns IPV6 addresses 473 in reply to the SIOCGIFCONF they will be included. Howerver, it is not guarranteed or even expected that many platforms will 474 include the IPV6 addresses. For this reason there are other specific implementations that will return the IPV6 addresses */ 475 /* first get the list of interfaces. We do not know how long the buffer needs to be so we try with one that allows for 476 32 interfaces. If this turns out not to be big enough then we expand the buffer to be able to support another 477 32 interfaces and try again. We do this until the result indicates that the result fit into the buffer provided */ 478 /* we need socket to do the ioctl so create one */ 479 socketP = socket(PF_INET, SOCK_DGRAM, 0); 480 if(socketP < 0) { 481 return socketP; 482 } 483 for(;;) { 484 char *data = (char *)malloc(len * sizeof(char)); 485 if(data == NULL) { 486 close(socketP); 487 return SOCKERR_NOBUFFERS; 488 } 489 ifc.ifc_len = len; 490 ifc.ifc_buf = data; 491 errno = 0; 492 if(ioctl(socketP, ifconfCommand, &ifc) != 0) { 493 err = errno; 494 free(ifc.ifc_buf); 495 close(socketP); 496 return SOCKERR_NORECOVERY; 497 } 498 if(ifc.ifc_len < len) 499 break; 500 /* the returned data was likely truncated, expand the buffer and try again */ 501 free(ifc.ifc_buf); 502 len += 32 * sizeof(struct ifreq); 503 } 504 505 /* get the number of distinct interfaces */ 506 if(ifc.ifc_len != 0) { 507 totalInterfaces = ifc.ifc_len / sizeof(struct ifreq); 508 } 509 lastName = NULL; 510 for(counter = 0; counter < totalInterfaces; counter++) { 511 if((NULL == lastName) || (strncmp(lastName, ifc.ifc_req[counter].ifr_name, IFNAMSIZ) != 0)) { 512 /* make sure the interface is up */ 513 reqCopy = ifc.ifc_req[counter]; 514 ioctl(socketP, SIOCGIFFLAGS, &reqCopy); 515 if((reqCopy.ifr_flags) & (IFF_UP == IFF_UP)) { 516 numAdapters++; 517 } 518 } 519 lastName = ifc.ifc_req[counter].ifr_name; 520 } 521 522 /* now allocate the space for the hyNetworkInterface structs and fill it in */ 523 interfaces = malloc(numAdapters * sizeof(NetworkInterface_struct)); 524 if(NULL == interfaces) { 525 free(ifc.ifc_buf); 526 close(socketP); 527 return SOCKERR_NOBUFFERS; 528 } 529 530 /* initialize the structure so that we can free allocated if a failure occurs */ 531 for(counter = 0; counter < numAdapters; counter++) { 532 interfaces[counter].name = NULL; 533 interfaces[counter].displayName = NULL; 534 interfaces[counter].addresses = NULL; 535 } 536 537 /* set up the return stucture */ 538 array->elements = interfaces; 539 array->length = numAdapters; 540 lastName = NULL; 541 for(counter = 0; counter < totalInterfaces; counter++) { 542 /* make sure the interface is still up */ 543 reqCopy = ifc.ifc_req[counter]; 544 ioctl(socketP, SIOCGIFFLAGS, &reqCopy); 545 if((reqCopy.ifr_flags) & (IFF_UP == IFF_UP)) { 546 /* since this function can return multiple entries for the same name, only do it for the first one with any given name */ 547 if((NULL == lastName) || (strncmp(lastName, ifc.ifc_req[counter].ifr_name, IFNAMSIZ) != 0)) { 548 549 /* get the index for the interface. This is only truely necessary on platforms that support IPV6 */ 550 interfaces[currentAdapterIndex].index = 0; 551 /* get the name and display name for the adapter */ 552 /* there only seems to be one name so use it for both the name and the display name */ 553 nameLength = strlen(ifc.ifc_req[counter].ifr_name); 554 interfaces[currentAdapterIndex].name = malloc(nameLength + 1); 555 556 if(NULL == interfaces[currentAdapterIndex].name) { 557 free(ifc.ifc_buf); 558 sock_free_network_interface_struct(array); 559 close(socketP); 560 return SOCKERR_NOBUFFERS; 561 } 562 strncpy(interfaces[currentAdapterIndex].name, ifc.ifc_req[counter].ifr_name, nameLength); 563 interfaces[currentAdapterIndex].name[nameLength] = 0; 564 nameLength = strlen(ifc.ifc_req[counter].ifr_name); 565 interfaces[currentAdapterIndex].displayName = malloc(nameLength + 1); 566 if(NULL == interfaces[currentAdapterIndex].displayName) { 567 free(ifc.ifc_buf); 568 sock_free_network_interface_struct(array); 569 close(socketP); 570 return SOCKERR_NOBUFFERS; 571 } 572 strncpy(interfaces[currentAdapterIndex].displayName, ifc.ifc_req[counter].ifr_name, nameLength); 573 interfaces[currentAdapterIndex].displayName[nameLength] = 0; 574 575 /* check how many addresses/aliases this adapter has. aliases show up as adaptors with the same name */ 576 numAddresses = 0; 577 for(counter2 = counter; counter2 < totalInterfaces; counter2++) { 578 if(strncmp(ifc.ifc_req[counter].ifr_name, ifc.ifc_req[counter2].ifr_name, IFNAMSIZ) == 0) { 579 if(ifc.ifc_req[counter2].ifr_addr.sa_family == AF_INET) { 580 numAddresses++; 581 } 582 } else { 583 break; 584 } 585 } 586 587 /* allocate space for the addresses */ 588 interfaces[currentAdapterIndex].numberAddresses = numAddresses; 589 interfaces[currentAdapterIndex].addresses = malloc(numAddresses * sizeof(ipAddress_struct)); 590 if(NULL == interfaces[currentAdapterIndex].addresses) { 591 free(ifc.ifc_buf); 592 sock_free_network_interface_struct(array); 593 close(socketP); 594 return SOCKERR_NOBUFFERS; 595 } 596 597 /* now get the addresses */ 598 currentIPAddressIndex = 0; 599 lastName = ifc.ifc_req[counter].ifr_name; 600 601 for(;;) { 602 if(ifc.ifc_req[counter].ifr_addr.sa_family == AF_INET) { 603 interfaces[currentAdapterIndex].addresses[currentIPAddressIndex].addr.inAddr.s_addr = ((struct sockaddr_in *) (&ifc.ifc_req[counter].ifr_addr))->sin_addr.s_addr; 604 interfaces[currentAdapterIndex].addresses[currentIPAddressIndex].length = sizeof(struct in_addr); 605 interfaces[currentAdapterIndex].addresses[currentIPAddressIndex].scope = 0; 606 currentIPAddressIndex++; 607 } 608 609 /* we mean to increment the outside counter here as we want to skip the next entry as it is for the same interface 610 as we are currently working on */ 611 if((counter + 1 < totalInterfaces) && (strncmp(ifc.ifc_req[counter + 1].ifr_name, lastName, IFNAMSIZ) == 0)) { 612 counter++; 613 } else { 614 break; 615 } 616 617 } 618 currentAdapterIndex++; 619 } 620 } 621 } /* for over all interfaces */ 622 /* now an interface might have been taken down since we first counted them */ 623 array->length = currentAdapterIndex; 624 /* free the memory now that we are done with it */ 625 free(ifc.ifc_buf); 626 close(socketP); 627 628 return 0; 629} 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685/** 686 * Answer an array of NetworkInterface objects. One for each network interface within the system 687 * 688 * @param env pointer to the JNI library 689 * @param clazz the class of the object invoking the JNI function 690 * 691 * @return an array of NetworkInterface objects of length 0 or more 692 */ 693 694static jobjectArray getNetworkInterfacesImpl(JNIEnv * env, jclass clazz) { 695 696 /* variables to store network interfac edata returned by call to port library */ 697 struct NetworkInterfaceArray_struct networkInterfaceArray; 698 int result = 0; 699 700 /* variables for class and method objects needed to create bridge to java */ 701 jclass networkInterfaceClass = NULL; 702 jclass inetAddressClass = NULL; 703 jclass utilClass = NULL; 704 jmethodID methodID = NULL; 705 jmethodID utilMid = NULL; 706 707 /* JNI objects used to return values from native call */ 708 jstring name = NULL; 709 jstring displayName = NULL; 710 jobjectArray addresses = NULL; 711 jobjectArray networkInterfaces = NULL; 712 jbyteArray bytearray = NULL; 713 714 /* jobjects used to build the object arrays returned */ 715 jobject currentInterface = NULL; 716 jobject element = NULL; 717 718 /* misc variables needed for looping and determining inetAddress info */ 719 unsigned int i = 0; 720 unsigned int j = 0; 721 unsigned int nameLength = 0; 722 723 /* get the classes and methods that we need for later calls */ 724 networkInterfaceClass = (*env)->FindClass(env, "java/net/NetworkInterface"); 725 if(networkInterfaceClass == NULL) { 726 throwSocketException(env, netLookupErrorString(SOCKERR_NORECOVERY)); 727 return NULL; 728 } 729 730 inetAddressClass = (*env)->FindClass(env, "java/net/InetAddress"); 731 if(inetAddressClass == NULL) { 732 throwSocketException(env, netLookupErrorString(SOCKERR_NORECOVERY)); 733 return NULL; 734 } 735 736 methodID = (*env)->GetMethodID(env, networkInterfaceClass, "<init>", 737 "(Ljava/lang/String;Ljava/lang/String;[Ljava/net/InetAddress;I)V"); 738 if(methodID == NULL) { 739 throwSocketException(env, netLookupErrorString(SOCKERR_NORECOVERY)); 740 return NULL; 741 } 742 743 utilClass = (*env)->FindClass(env, "org/apache/harmony/luni/util/Util"); 744 if(!utilClass) { 745 return NULL; 746 } 747 748 utilMid = ((*env)->GetStaticMethodID(env, utilClass, "toString", 749 "([BII)Ljava/lang/String;")); 750 if(!utilMid) { 751 return NULL; 752 } 753 754 result = sockGetNetworkInterfaces(&networkInterfaceArray); 755 756 if(result < 0) { 757 /* this means an error occured. The value returned is the socket error that should be returned */ 758 throwSocketException(env, netLookupErrorString(result)); 759 return NULL; 760 } 761 762 /* now loop through the interfaces and extract the information to be returned */ 763 for(j = 0; j < networkInterfaceArray.length; j++) { 764 /* set the name and display name and reset the addresses object array */ 765 addresses = NULL; 766 name = NULL; 767 displayName = NULL; 768 769 if(networkInterfaceArray.elements[j].name != NULL) { 770 nameLength = strlen(networkInterfaceArray.elements[j].name); 771 bytearray = (*env)->NewByteArray(env, nameLength); 772 if(bytearray == NULL) { 773 /* NewByteArray should have thrown an exception */ 774 return NULL; 775 } 776 (*env)->SetByteArrayRegion(env, bytearray, (jint) 0, nameLength, 777 (jbyte *)networkInterfaceArray.elements[j].name); 778 name = (*env)->CallStaticObjectMethod(env, utilClass, utilMid, 779 bytearray, (jint) 0, nameLength); 780 if((*env)->ExceptionCheck(env)) { 781 return NULL; 782 } 783 } 784 785 if(networkInterfaceArray.elements[j].displayName != NULL) { 786 nameLength = strlen(networkInterfaceArray.elements[j].displayName); 787 bytearray = (*env)->NewByteArray(env, nameLength); 788 if(bytearray == NULL) { 789 /* NewByteArray should have thrown an exception */ 790 return NULL; 791 } 792 (*env)->SetByteArrayRegion(env, bytearray, (jint) 0, nameLength, 793 (jbyte *)networkInterfaceArray.elements[j].displayName); 794 displayName = (*env)->CallStaticObjectMethod(env, utilClass, utilMid, 795 bytearray, (jint) 0, nameLength); 796 if((*env)->ExceptionCheck(env)) { 797 return NULL; 798 } 799 } 800 801 /* generate the object with the inet addresses for the itnerface */ 802 for(i = 0; i < networkInterfaceArray.elements[j].numberAddresses; i++) { 803 element = structInToInetAddress(env, (struct in_addr *) &(networkInterfaceArray.elements[j].addresses[i].addr.inAddr)); 804 if(i == 0) { 805 addresses = (*env)->NewObjectArray(env, 806 networkInterfaceArray.elements[j].numberAddresses, 807 inetAddressClass, element); 808 } else { 809 (*env)->SetObjectArrayElement(env, addresses, i, element); 810 } 811 } 812 813 /* now create the NetworkInterface object for this interface and then add it it ot the arrary that will be returned */ 814 currentInterface = (*env)->NewObject(env, networkInterfaceClass, 815 methodID, name, displayName, addresses, 816 networkInterfaceArray.elements[j].index); 817 818 if(j == 0) { 819 networkInterfaces = (*env)->NewObjectArray(env, 820 networkInterfaceArray.length, networkInterfaceClass, 821 currentInterface); 822 } else { 823 (*env)->SetObjectArrayElement(env, networkInterfaces, j, currentInterface); 824 } 825 } 826 827 /* free the memory for the interfaces struct and return the new NetworkInterface List */ 828 sock_free_network_interface_struct(&networkInterfaceArray); 829 return networkInterfaces; 830} 831 832 833/* 834 * JNI registration 835 */ 836static JNINativeMethod gMethods[] = { 837 /* name, signature, funcPtr */ 838 { "getNetworkInterfacesImpl", "()[Ljava/net/NetworkInterface;", getNetworkInterfacesImpl } 839}; 840int register_java_net_NetworkInterface(JNIEnv* env) { 841 return jniRegisterNativeMethods(env, "java/net/NetworkInterface", 842 gMethods, NELEM(gMethods)); 843 844} 845