2017-05-29 3 views
1

J'essaye de m'interfacer avec le pilote de tuner Linux en Java comme il est expliqué ici.ioctl() avec JNI: descripteur de fichier brisé

How to interface with the Linux tun driver

Mais puisque vous ne pouvez pas appeler ioctl() avec java, j'utilise Java Native Interface. Cela fonctionne bien tant que je ne lis pas et n'écris pas dans le même fichier.

Si je le fais, je reçois cette exception, que je traduirais par "Le FileDescriptor est dans un état cassé":

java.io.IOException: Le descripteur du fichier est dans un mauvais état 
    at java.io.FileOutputStream.writeBytes(Native Method) 
    at java.io.FileOutputStream.write(FileOutputStream.java:326) 
    at WriterThread.main(WriterThread.java:54) 

Voici le code java:

public static void main(String[] arg){ 
     File tunFile = new File("/dev/net/tun"); 
     FileOutputStream outStream; 
     FileInputStream inStream; 

     try { 

      inStream = new FileInputStream(tunFile); 
      outStream = new FileOutputStream(tunFile); 
      FileDescriptor fd = inStream.getFD(); 

      //getting the file descriptor 

      Field f = fd.getClass().getDeclaredField("fd"); 
      f.setAccessible(true); 
      int descriptor = f.getInt(fd); 


      //use of Java Native Interface 
      new TestOuvertureFichier().ioctl(descriptor); 

      while(true){ 
       System.out.println("reading"); 
       byte[] bytes = new byte[500]; 
       int l = 0; 
       l = inStream.read(bytes); 

       //the problem seems to come from here 
       outStream.write(bytes,0,l); 

      } 

     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

    } 

Voici le code C:

JNIEXPORT void JNICALL Java_TestOuvertureFichier_ioctl(JNIEnv *env,jobject obj, jint descriptor){ 
     struct ifreq ifr; 
     memset(&ifr, 0, sizeof(ifr)); 
     ifr.ifr_flags = IFF_TUN; 
     strncpy(ifr.ifr_name, "tun0", IFNAMSIZ); 
     int err; 

     if ((err = ioctl(descriptor, TUNSETIFF, (void *) &ifr)) == -1) { 
      perror("ioctl TUNSETIFF");exit(1); 
     } 
     return; 
} 
+0

'new FileOutputStream (...)' va sûrement essayer de créer un nouveau fichier. Essayez d'utiliser * un * 'RandomAccessFile' à la place des deux flux de fichiers. – EJP

Répondre

0

Le descripteur de fichier n'est pas créé par l'appel new File() mais lors de la création des FileInputStream et FileOutputStream objets. Ce qui signifie que votre code ouvre le fichier/dev/net/tun deux fois (en créant deux descripteurs de fichiers différents).

inStream = new FileInputStream(tunFile); 
outStream = new FileOutputStream(tunFile); 

Par conséquent, l'ioctl est appliquée uniquement à inStream, et non à outStream. Essayez de créer le FileOutputStream en utilisant le même descripteur de fichier que le FileInputStream. Edit: Il est probable que FileInputStream ouvre un FD en lecture seule. Comme JayTE l'a proposé, il est probablement préférable de créer d'abord un RandomAccessFile, et d'utiliser le FD pour créer les deux flux.

0

Notez que bytes devrait être d'au moins la taille MTU du interfac e, par exemple 1500 octets. Le read() sur le tun fd lit exactement un paquet entier chaque fois qu'il est appelé. Avant d'écrire sur le dispositif tun, vous devez manipuler l'en-tête IP, en particulier l'adresse source et l'adresse de destination du paquet reçu.

1

G. Fiedler a raison, la lecture devrait être au moins aussi grande que l'interface MTU, et l'écriture ne doit pas dépasser le MTU. En plus de cela, je voudrais vérifier que:

  • Avant d'essayer de lire ou d'écrire, l'interface est en place (ip addr add xxxx/xx dev tun0, set ip link tun0 up)
  • Vous ouvrez le tun une seule fois, en utilisant par exemple un RandomAccessFile. Ici, je ne suis pas sûr que l'inStream et l'outStream ont le même descripteur de fichier.