2017-05-29 6 views
1

Ich versuche, mit dem Linux tun Treiber in Java zu interagieren, wie es hier erklärt wird.ioctl() mit JNI: defekter Dateideskriptor

How to interface with the Linux tun driver

Aber da Sie nicht ioctl() mit Java nennen, kann ich das Java Native Interface verwende. Es funktioniert gut, solange ich nicht in derselben Datei lese und schreibe.

Wenn ich mir diese Ausnahme kann so erhalten, die ich von übersetzen würde "The FileDescriptor ist in einem gebrochenen Zustand":

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) 

Hier wird der Java-Code:

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(); 
     } 

    } 

Hier der C-Code:

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

'neue FileOutputStream (...)' wird sicherlich versuchen, eine neue Datei zu erstellen. Versuchen Sie, * one * 'RandomAccessFile' anstelle der beiden Dateiströme zu verwenden. – EJP

Antwort

0

Der Dateideskriptor wird durch den new File() Anruf nicht erstellt, aber wenn die FileInputStream und FileOutputStream Objekte zu schaffen. Das bedeutet, dass Ihr Code die Datei/dev/net/tun zweimal öffnet (zwei unterschiedliche Dateideskriptoren erzeugt).

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

Daher wird die ioctl nur auf inStream angewendet und nicht auf outStream. Versuchen Sie, FileOutputStream zu erstellen, während Sie denselben Dateideskriptor wie FileInputStream verwenden.

outStream = new FileOutputStream(inStream.getFD());  

Bearbeiten: Es ist wahrscheinlich, dass FileInputStream eine schreibgeschützte FD öffnen wird. Wie JayTE vorgeschlagen hat, ist es wahrscheinlich besser, zuerst eine RandomAccessFile zu erstellen und die FD daraus zu verwenden, um die zwei Ströme zu erzeugen.

0

Beachten Sie, dass bytes sollte mindestens die MTU-Größe des interfac sein e, zB 1500 Bytes. Die read() auf dem tun fd liest jedes Mal genau ein ganzes Paket, wenn es aufgerufen wird.

Bevor Sie in das tun-Gerät schreiben, sollten Sie den IP-Header bearbeiten, insbesondere die Quell- und Zieladresse des empfangenen Pakets.

1

G. Fiedler hat recht, die Lese sollte mindestens so groß sein wie die Schnittstelle MTU, und der Schreibvorgang sollte die MTU nicht überschreiten. Hinzu kommt, dass, würde ich prüfen:

  • Bevor Sie zu lesen oder schreiben versuchen, die Schnittstelle aktiviert ist (ip addr add xxxx/xx dev tun0, ip link set tun0 up)
  • Sie öffnen die Tun Gerät nur einmal, mit zum Beispiel eine RandomAccessFile. Ich bin mir nicht sicher, ob inStream und outStream den gleichen Dateideskriptor haben.