mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			400 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			400 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
| /* VMNetworkInterface.c - Native methods for NetworkInterface class
 | |
|    Copyright (C) 2003, 2005, 2006, 2008 Free Software Foundation, Inc.
 | |
| 
 | |
| This file is part of GNU Classpath.
 | |
| 
 | |
| GNU Classpath is free software; you can redistribute it and/or modify
 | |
| it under the terms of the GNU General Public License as published by
 | |
| the Free Software Foundation; either version 2, or (at your option)
 | |
| any later version.
 | |
|  
 | |
| GNU Classpath is distributed in the hope that it will be useful, but
 | |
| WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
| General Public License for more details.
 | |
| 
 | |
| You should have received a copy of the GNU General Public License
 | |
| along with GNU Classpath; see the file COPYING.  If not, write to the
 | |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | |
| 02110-1301 USA.
 | |
| 
 | |
| Linking this library statically or dynamically with other modules is
 | |
| making a combined work based on this library.  Thus, the terms and
 | |
| conditions of the GNU General Public License cover the whole
 | |
| combination.
 | |
| 
 | |
| As a special exception, the copyright holders of this library give you
 | |
| permission to link this library with independent modules to produce an
 | |
| executable, regardless of the license terms of these independent
 | |
| modules, and to copy and distribute the resulting executable under
 | |
| terms of your choice, provided that you also meet, for each linked
 | |
| independent module, the terms and conditions of the license of that
 | |
| module.  An independent module is a module which is not derived from
 | |
| or based on this library.  If you modify this library, you may extend
 | |
| this exception to your version of the library, but you are not
 | |
| obligated to do so.  If you do not wish to do so, delete this
 | |
| exception statement from your version. */
 | |
| 
 | |
| #ifdef HAVE_CONFIG_H
 | |
| #include <config.h>
 | |
| #endif /* HAVE_CONFIG_H */
 | |
| 
 | |
| #include <sys/types.h>
 | |
| #include <sys/socket.h>
 | |
| #ifdef HAVE_IFADDRS_H
 | |
| #include <ifaddrs.h>
 | |
| #endif
 | |
| #include <netinet/in.h>
 | |
| #include <errno.h>
 | |
| #include <stdlib.h>
 | |
| #include <stdio.h>
 | |
| #include <string.h>
 | |
| 
 | |
| #include <net/if.h>
 | |
| #include <sys/ioctl.h>
 | |
| /* Required on Solaris. */
 | |
| #include <unistd.h>
 | |
| 
 | |
| #ifdef HAVE_SYS_SOCKIO_H
 | |
| # include <sys/sockio.h>
 | |
| #endif
 | |
| 
 | |
| #include <jni.h>
 | |
| #include <jcl.h>
 | |
| 
 | |
| #include <cpnative.h>
 | |
| #include <cpnet.h>
 | |
| 
 | |
| #include "java_net_VMNetworkInterface.h"
 | |
| 
 | |
| int iff_flags(JNIEnv *, jstring, jint *);
 | |
| 
 | |
| static jmethodID java_net_VMNetworkInterface_init;
 | |
| static jmethodID java_net_VMNetworkInterface_addAddress;
 | |
| 
 | |
| /*
 | |
|  * Initialize our static method ID's.
 | |
|  *
 | |
|  * Class:     java_net_VMNetworkInterface
 | |
|  * Method:    initIds
 | |
|  * Signature: ()V
 | |
|  */
 | |
| JNIEXPORT void JNICALL
 | |
| Java_java_net_VMNetworkInterface_initIds (JNIEnv *env, jclass clazz)
 | |
| {
 | |
|   java_net_VMNetworkInterface_init =
 | |
|     (*env)->GetMethodID (env, clazz, "<init>", "(Ljava/lang/String;)V");
 | |
|   if (java_net_VMNetworkInterface_init == NULL)
 | |
|     {
 | |
|       if (!(*env)->ExceptionCheck (env))
 | |
|         JCL_ThrowException (env, "java/lang/NoSuchMethodError",
 | |
|                             "VMNetworkinterface.addAddress");
 | |
|       return;
 | |
|     }
 | |
|   java_net_VMNetworkInterface_addAddress =
 | |
|     (*env)->GetMethodID (env, clazz, "addAddress", "(Ljava/nio/ByteBuffer;)V");
 | |
|   if (java_net_VMNetworkInterface_addAddress == NULL)
 | |
|     {
 | |
|       if (!(*env)->ExceptionCheck (env))
 | |
|         JCL_ThrowException (env, "java/lang/NoSuchMethodError",
 | |
|                             "VMNetworkinterface.addAddress");
 | |
|     }
 | |
| }
 | |
| 
 | |
| struct netif_entry
 | |
| {
 | |
|   char *name;
 | |
|   jobject netif;
 | |
|   int numaddrs;
 | |
|   struct netif_entry *next;
 | |
| };
 | |
| 
 | |
| #if defined (HAVE_IFADDRS_H) && defined (HAVE_GETIFADDRS)
 | |
| static void
 | |
| free_netif_list (JNIEnv *env, struct netif_entry *list)
 | |
| {
 | |
|   while (list != NULL)
 | |
|     {
 | |
|       struct netif_entry *e = list->next;
 | |
|       JCL_free (env, list);
 | |
|       list = e;
 | |
|     }
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*
 | |
|  * Returns all local network interfaces as an array.
 | |
|  */
 | |
| JNIEXPORT jobjectArray JNICALL
 | |
| Java_java_net_VMNetworkInterface_getVMInterfaces (JNIEnv * env,
 | |
|                                                   jclass clazz UNUSED)
 | |
| {
 | |
| #if defined (HAVE_IFADDRS_H) && defined (HAVE_GETIFADDRS)
 | |
|   struct ifaddrs *ifaddrs, *i;
 | |
|   struct netif_entry *iflist = NULL, *e;
 | |
|   jobjectArray netifs;
 | |
|   int numifs = 0;
 | |
|   int k;
 | |
| 
 | |
|   if (getifaddrs (&ifaddrs) == -1)
 | |
|     {
 | |
|       JCL_ThrowException (env, "java/net/SocketException", strerror (errno));
 | |
|       return NULL;
 | |
|     }
 | |
| 
 | |
|   for (i = ifaddrs; i != NULL; i = i->ifa_next)
 | |
|     {
 | |
|       if (iflist == NULL)
 | |
|         {
 | |
|           iflist = JCL_malloc (env, sizeof (struct netif_entry));
 | |
|           if (iflist == NULL)
 | |
|             {
 | |
|               freeifaddrs (ifaddrs);
 | |
|               return NULL;
 | |
|             }
 | |
|           iflist->name = i->ifa_name;
 | |
|           iflist->numaddrs = 0;
 | |
|           iflist->next = NULL;
 | |
|           iflist->netif = (*env)->NewObject (env, clazz, java_net_VMNetworkInterface_init,
 | |
|                                              (*env)->NewStringUTF (env, i->ifa_name));
 | |
|           if (iflist->netif == NULL)
 | |
|             {
 | |
|               freeifaddrs (ifaddrs);
 | |
|               JCL_free (env, iflist);
 | |
|               return NULL;
 | |
|             }
 | |
|           e = iflist;
 | |
|         }
 | |
|       else
 | |
|         {
 | |
|           struct netif_entry *p = NULL;
 | |
|           for (e = iflist; e != NULL; e = e->next)
 | |
|             {
 | |
|               if (strcmp (e->name, i->ifa_name) == 0)
 | |
|                 break;
 | |
|               p = e;
 | |
|             }
 | |
| 
 | |
|           if (e == NULL)
 | |
|             {
 | |
|               p->next = (struct netif_entry *) JCL_malloc (env, sizeof (struct netif_entry));
 | |
|               if (p->next == NULL)
 | |
|                 {
 | |
|                   free_netif_list (env, iflist);
 | |
|                   freeifaddrs (ifaddrs);
 | |
|                   return NULL;
 | |
|                 }
 | |
|               e = p->next;
 | |
|               e->name = i->ifa_name;
 | |
|               e->numaddrs = 0;
 | |
|               e->next = NULL;
 | |
|               e->netif = (*env)->NewObject (env, clazz, java_net_VMNetworkInterface_init,
 | |
|                                             (*env)->NewStringUTF (env, i->ifa_name));
 | |
|               if (e->netif == NULL)
 | |
|                 {
 | |
|                   free_netif_list (env, iflist);
 | |
|                   freeifaddrs (ifaddrs);
 | |
|                   return NULL;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|       if (i->ifa_addr == NULL)
 | |
|         continue;
 | |
| 
 | |
|       if (i->ifa_addr->sa_family == AF_INET)
 | |
|         {
 | |
|           struct sockaddr_in *sin = (struct sockaddr_in *) i->ifa_addr;
 | |
|           jobject buffer = (*env)->NewDirectByteBuffer (env, &(sin->sin_addr.s_addr), 4);
 | |
|           (*env)->CallVoidMethod (env, e->netif, java_net_VMNetworkInterface_addAddress,
 | |
|                                   buffer);
 | |
|           if ((*env)->ExceptionCheck (env))
 | |
|             {
 | |
|               free_netif_list (env, iflist);
 | |
|               freeifaddrs (ifaddrs);
 | |
|               return NULL;
 | |
|             }
 | |
|           (*env)->DeleteLocalRef (env, buffer);
 | |
|           e->numaddrs++;
 | |
|         }
 | |
| #ifdef HAVE_INET6
 | |
|       else if (i->ifa_addr->sa_family == AF_INET6)
 | |
|         {
 | |
|           struct sockaddr_in6 *sin = (struct sockaddr_in6 *) i->ifa_addr;
 | |
|           jobject buffer = (*env)->NewDirectByteBuffer (env, &(sin->sin6_addr.s6_addr), 16);
 | |
|           (*env)->CallVoidMethod (env, e->netif, java_net_VMNetworkInterface_addAddress,
 | |
|                                   buffer);
 | |
|           if ((*env)->ExceptionCheck (env))
 | |
|             {
 | |
|               free_netif_list (env, iflist);
 | |
|               freeifaddrs (ifaddrs);
 | |
|               return NULL;
 | |
|             }
 | |
|           (*env)->DeleteLocalRef (env, buffer);
 | |
|           e->numaddrs++;
 | |
|         }
 | |
| #endif /* HAVE_INET6 */
 | |
|     }
 | |
| 
 | |
|   /* Count how many interfaces we have that have addresses. */
 | |
|   for (e = iflist; e != NULL; e = e->next)
 | |
|     {
 | |
|       if (e->numaddrs != 0)
 | |
|         numifs++;
 | |
|     }
 | |
| 
 | |
|   netifs = (*env)->NewObjectArray (env, numifs, clazz, NULL);
 | |
|   k = 0;
 | |
|   for (e = iflist; e != NULL && k < numifs; e = e->next)
 | |
|     {
 | |
|       if (e->numaddrs != 0)
 | |
|         {
 | |
|           (*env)->SetObjectArrayElement (env, netifs, k, e->netif);
 | |
|           (*env)->DeleteLocalRef (env, e->netif);
 | |
|           k++;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|   free_netif_list (env, iflist);
 | |
|   freeifaddrs (ifaddrs);
 | |
|   return netifs;
 | |
| #else
 | |
|   JCL_ThrowException (env, "java/net/SocketException", "getifaddrs not supported");
 | |
|   return NULL;
 | |
| #endif /* HAVE_IFADDRS_H && HAVE_GETIFADDRS */
 | |
| }
 | |
| 
 | |
| int iff_flags(JNIEnv *env, jstring name, jint *flags)
 | |
| {
 | |
|   struct ifreq iff;
 | |
|   const char *iff_name;
 | |
|   jint socket;
 | |
|   int error, retval;
 | |
| 
 | |
|   if ((error = cpnet_openSocketDatagram(env, &socket, AF_INET)))
 | |
|   {
 | |
|     return error;
 | |
|   }
 | |
| 
 | |
|   iff_name = JCL_jstring_to_cstring(env, name);
 | |
|   memset(&iff, 0, sizeof(iff));
 | |
|   strcpy(iff.ifr_name, iff_name);
 | |
|  
 | |
|   if (ioctl(socket, SIOCGIFFLAGS, &iff) >= 0)
 | |
|   {
 | |
|     *flags = (jint) iff.ifr_flags;
 | |
| 
 | |
|     retval = 0;
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     retval = errno;
 | |
|   }
 | |
| 
 | |
|   cpnet_close(env, socket);
 | |
| 
 | |
|   JCL_free_cstring(env, name, iff_name);
 | |
| 
 | |
|   return retval;
 | |
| }
 | |
| 
 | |
| JNIEXPORT jboolean JNICALL
 | |
| Java_java_net_VMNetworkInterface_isUp (JNIEnv *env, jclass class UNUSED,
 | |
|                                        jstring name)
 | |
| {
 | |
|   jint flags;
 | |
|   int error;
 | |
|   jboolean retval;
 | |
| 
 | |
|   if ((error = iff_flags(env, name, &flags)))
 | |
|   {
 | |
|     JCL_ThrowException(env, "java/net/SocketException",
 | |
|                        cpnative_getErrorString(error));
 | |
| 
 | |
|     retval = JNI_FALSE;
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     retval = (flags & (IFF_UP | IFF_RUNNING))
 | |
|              ? JNI_TRUE
 | |
|              : JNI_FALSE;
 | |
|   }
 | |
| 
 | |
|   return retval;
 | |
| }
 | |
| 
 | |
| JNIEXPORT jboolean JNICALL
 | |
| Java_java_net_VMNetworkInterface_isPointToPoint (JNIEnv *env,
 | |
|                                                  jclass class UNUSED,
 | |
|                                                  jstring name)
 | |
| {
 | |
|   jint flags;
 | |
|   int error;
 | |
|   jboolean retval;
 | |
| 
 | |
|   if ((error = iff_flags(env, name, &flags)))
 | |
|   {
 | |
|     JCL_ThrowException(env, "java/net/SocketException",
 | |
|                        cpnative_getErrorString(error));
 | |
| 
 | |
|     retval = JNI_FALSE;
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     retval = (flags & IFF_POINTOPOINT) ? JNI_TRUE
 | |
|                                        : JNI_FALSE;
 | |
|   }
 | |
| 
 | |
|   return retval;
 | |
| }
 | |
| 
 | |
| JNIEXPORT jboolean JNICALL
 | |
| Java_java_net_VMNetworkInterface_isLoopback (JNIEnv *env,
 | |
|                                              jclass class UNUSED,
 | |
|                                              jstring name)
 | |
| {
 | |
|   jint flags;
 | |
|   int error;
 | |
|   jboolean retval;
 | |
| 
 | |
|   if ((error = iff_flags(env, name, &flags)))
 | |
|   {
 | |
|     JCL_ThrowException(env, "java/net/SocketException",
 | |
|                        cpnative_getErrorString(error));
 | |
| 
 | |
|     retval = JNI_FALSE;
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     retval = (flags & IFF_LOOPBACK) ? JNI_TRUE : JNI_FALSE;
 | |
|   }
 | |
| 
 | |
|   return retval;
 | |
| }
 | |
| 
 | |
| JNIEXPORT jboolean JNICALL
 | |
| Java_java_net_VMNetworkInterface_supportsMulticast (JNIEnv *env,
 | |
|                                                     jclass class UNUSED,
 | |
|                                                     jstring name)
 | |
| {
 | |
|   jint flags;
 | |
|   int error;
 | |
|   jboolean retval;
 | |
| 
 | |
|   if ((error = iff_flags(env, name, &flags)))
 | |
|   {
 | |
|     JCL_ThrowException(env, "java/net/SocketException",
 | |
|                        cpnative_getErrorString(error));
 | |
| 
 | |
|     retval = JNI_FALSE;
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     retval = (flags & IFF_MULTICAST) ? JNI_TRUE : JNI_FALSE;
 | |
|   }
 | |
| 
 | |
|   return retval;
 | |
| }
 | |
| 
 | |
| /* end of file */
 |