带有 JNI 的 ioctl():损坏的文件描述符
ioctl() with JNI : broken file descriptor
我正在尝试与 Java 中的 Linux tun 驱动程序进行交互,如此处所述。
How to interface with the Linux tun driver
但是由于您不能使用 java 调用 ioctl(),我使用的是 Java 本机接口。只要我不在同一个文件中读写,它就可以正常工作。
如果我这样做,我会得到这个异常,我会翻译成 "The FileDescriptor is in a broken state" :
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;
}
请注意,bytes
至少应为接口的 MTU 大小,例如 1500 字节。 tun fd 上的 read()
每次调用时都会准确读取整个数据包。
在写入 tun 设备之前,您应该操作 IP header,尤其是接收数据包的源地址和目标地址。
G。 Fiedler 是对的,读应该至少和接口 MTU 一样大,写不应该超过 MTU。除此之外,我会检查:
- 在您尝试读取或写入之前,接口启动(ip addr add x.x.x.x/xx dev tun0, ip link set tun0 up)
- 您只打开 tun 设备一次,例如使用 RandomAccessFile。在这里,我不确定 inStream 和 outStream 是否具有相同的文件描述符。
文件描述符不是由 new File()
调用创建的,而是在创建 FileInputStream
和 FileOutputStream
对象时创建的。这意味着您的代码打开 /dev/net/tun 文件两次(创建两个不同的文件描述符)。
inStream = new FileInputStream(tunFile);
outStream = new FileOutputStream(tunFile);
因此,ioctl 仅适用于 inStream
,而不适用于 outStream
。
尝试创建 FileOutputStream
,同时使用与 FileInputStream
.
相同的文件描述符
outStream = new FileOutputStream(inStream.getFD());
编辑:FileInputStream 很可能会打开一个只读的 FD。正如 JayTE 所建议的,最好先创建一个 RandomAccessFile
,然后使用其中的 FD 创建两个流。
我正在尝试与 Java 中的 Linux tun 驱动程序进行交互,如此处所述。
How to interface with the Linux tun driver
但是由于您不能使用 java 调用 ioctl(),我使用的是 Java 本机接口。只要我不在同一个文件中读写,它就可以正常工作。
如果我这样做,我会得到这个异常,我会翻译成 "The FileDescriptor is in a broken state" :
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;
}
请注意,bytes
至少应为接口的 MTU 大小,例如 1500 字节。 tun fd 上的 read()
每次调用时都会准确读取整个数据包。
在写入 tun 设备之前,您应该操作 IP header,尤其是接收数据包的源地址和目标地址。
G。 Fiedler 是对的,读应该至少和接口 MTU 一样大,写不应该超过 MTU。除此之外,我会检查:
- 在您尝试读取或写入之前,接口启动(ip addr add x.x.x.x/xx dev tun0, ip link set tun0 up)
- 您只打开 tun 设备一次,例如使用 RandomAccessFile。在这里,我不确定 inStream 和 outStream 是否具有相同的文件描述符。
文件描述符不是由 new File()
调用创建的,而是在创建 FileInputStream
和 FileOutputStream
对象时创建的。这意味着您的代码打开 /dev/net/tun 文件两次(创建两个不同的文件描述符)。
inStream = new FileInputStream(tunFile);
outStream = new FileOutputStream(tunFile);
因此,ioctl 仅适用于 inStream
,而不适用于 outStream
。
尝试创建 FileOutputStream
,同时使用与 FileInputStream
.
outStream = new FileOutputStream(inStream.getFD());
编辑:FileInputStream 很可能会打开一个只读的 FD。正如 JayTE 所建议的,最好先创建一个 RandomAccessFile
,然后使用其中的 FD 创建两个流。