【问题标题】:ioctl() with JNI : broken file descriptor带有 JNI 的 ioctl() :损坏的文件描述符
【发布时间】:2017-05-29 15:31:14
【问题描述】:

我正在尝试与 Java 中的 Linux tun 驱动程序交互,正如这里所解释的那样。

How to interface with the Linux tun driver

但是由于你不能用 java 调用 ioctl(),我使用的是 Java Native Interface。只要我不在同一个文件中读写,它就可以正常工作。

如果我这样做,我会得到这个异常,我将其翻译为“FileDescriptor 处于损坏状态”:

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)

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

    }

这是 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;
}

【问题讨论】:

  • new FileOutputStream(...) 肯定会尝试创建一个新文件。尝试使用 one RandomAccessFile 而不是两个文件流。

标签: java linux java-native-interface ioctl


【解决方案1】:

G. Fiedler 是对的,read 至少应该和 interface MTU 一样大,write 不应该超过 MTU。除此之外,我会检查:

  • 在您尝试读取或写入之前,接口已启动(ip addr add x.x.x.x/xx dev tun0, ip link set tun0 up)
  • 您只打开一次 tun 设备,例如使用 RandomAccessFile。在这里,我不确定 inStream 和 outStream 是否具有相同的文件描述符。

【讨论】:

    【解决方案2】:

    文件描述符不是由new File() 调用创建的,而是在创建FileInputStreamFileOutputStream 对象时创建的。这意味着您的代码会两次打开 /dev/net/tun 文件(创建两个不同的文件描述符)。

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

    因此,ioctl 仅适用于inStream,而不适用于outStream。 尝试使用与FileInputStream 相同的文件描述符来创建FileOutputStream

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

    编辑:FileInputStream 很可能会打开一个只读 FD。正如 JayTE 建议的那样,最好先创建一个RandomAccessFile,然后使用其中的 FD 创建两个流。

    【讨论】:

      【解决方案3】:

      请注意,bytes 至少应为接口的 MTU 大小,例如 1500 字节。 tun fd 上的read() 每次调用时都会准确读取整个数据包。

      在写入 tun 设备之前,您应该操作 IP 标头,尤其是接收数据包的源地址和目标地址。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-08-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多