1 |
780 |
jeremybenn |
/* VMChannel.java -- Native interface suppling channel operations.
|
2 |
|
|
Copyright (C) 2006 Free Software Foundation, Inc.
|
3 |
|
|
|
4 |
|
|
This file is part of GNU Classpath.
|
5 |
|
|
|
6 |
|
|
GNU Classpath is free software; you can redistribute it and/or modify
|
7 |
|
|
it under the terms of the GNU General Public License as published by
|
8 |
|
|
the Free Software Foundation; either version 2, or (at your option)
|
9 |
|
|
any later version.
|
10 |
|
|
|
11 |
|
|
GNU Classpath is distributed in the hope that it will be useful, but
|
12 |
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14 |
|
|
General Public License for more details.
|
15 |
|
|
|
16 |
|
|
You should have received a copy of the GNU General Public License
|
17 |
|
|
along with GNU Classpath; see the file COPYING. If not, write to the
|
18 |
|
|
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
19 |
|
|
02110-1301 USA.
|
20 |
|
|
|
21 |
|
|
Linking this library statically or dynamically with other modules is
|
22 |
|
|
making a combined work based on this library. Thus, the terms and
|
23 |
|
|
conditions of the GNU General Public License cover the whole
|
24 |
|
|
combination.
|
25 |
|
|
|
26 |
|
|
As a special exception, the copyright holders of this library give you
|
27 |
|
|
permission to link this library with independent modules to produce an
|
28 |
|
|
executable, regardless of the license terms of these independent
|
29 |
|
|
modules, and to copy and distribute the resulting executable under
|
30 |
|
|
terms of your choice, provided that you also meet, for each linked
|
31 |
|
|
independent module, the terms and conditions of the license of that
|
32 |
|
|
module. An independent module is a module which is not derived from
|
33 |
|
|
or based on this library. If you modify this library, you may extend
|
34 |
|
|
this exception to your version of the library, but you are not
|
35 |
|
|
obligated to do so. If you do not wish to do so, delete this
|
36 |
|
|
exception statement from your version. */
|
37 |
|
|
|
38 |
|
|
|
39 |
|
|
package gnu.java.nio;
|
40 |
|
|
|
41 |
|
|
import gnu.classpath.Configuration;
|
42 |
|
|
|
43 |
|
|
import java.io.IOException;
|
44 |
|
|
import java.net.Inet4Address;
|
45 |
|
|
import java.net.Inet6Address;
|
46 |
|
|
import java.net.InetAddress;
|
47 |
|
|
import java.net.InetSocketAddress;
|
48 |
|
|
import java.net.SocketAddress;
|
49 |
|
|
import java.net.SocketException;
|
50 |
|
|
import java.nio.ByteBuffer;
|
51 |
|
|
import java.nio.MappedByteBuffer;
|
52 |
|
|
|
53 |
|
|
/**
|
54 |
|
|
* Native interface to support configuring of channel to run in a non-blocking
|
55 |
|
|
* manner and support scatter/gather io operations.
|
56 |
|
|
*
|
57 |
|
|
* @author Michael Barker <mike@middlesoft.co.uk>
|
58 |
|
|
*
|
59 |
|
|
*/
|
60 |
|
|
public final class VMChannel
|
61 |
|
|
{
|
62 |
|
|
/**
|
63 |
|
|
* Our reference implementation uses an integer to store the native
|
64 |
|
|
* file descriptor. Implementations without such support
|
65 |
|
|
*/
|
66 |
|
|
private final State nfd;
|
67 |
|
|
|
68 |
|
|
private Kind kind;
|
69 |
|
|
|
70 |
|
|
public VMChannel()
|
71 |
|
|
{
|
72 |
|
|
// XXX consider adding security check here, so only Classpath
|
73 |
|
|
// code may create instances.
|
74 |
|
|
this.nfd = new State();
|
75 |
|
|
kind = Kind.OTHER;
|
76 |
|
|
}
|
77 |
|
|
|
78 |
|
|
/**
|
79 |
|
|
* This constructor is used by the POSIX reference implementation;
|
80 |
|
|
* other virtual machines need not support it.
|
81 |
|
|
*
|
82 |
|
|
* <strong>Important:</strong> do not call this in library code that is
|
83 |
|
|
* not specific to Classpath's reference implementation.
|
84 |
|
|
*
|
85 |
|
|
* @param native_fd The native file descriptor integer.
|
86 |
|
|
* @throws IOException
|
87 |
|
|
*/
|
88 |
|
|
VMChannel(final int native_fd) throws IOException
|
89 |
|
|
{
|
90 |
|
|
this();
|
91 |
|
|
this.nfd.setNativeFD(native_fd);
|
92 |
|
|
}
|
93 |
|
|
|
94 |
|
|
public State getState()
|
95 |
|
|
{
|
96 |
|
|
return nfd;
|
97 |
|
|
}
|
98 |
|
|
|
99 |
|
|
static
|
100 |
|
|
{
|
101 |
|
|
// load the shared library needed for native methods.
|
102 |
|
|
if (Configuration.INIT_LOAD_LIBRARY)
|
103 |
|
|
{
|
104 |
|
|
System.loadLibrary ("javanio");
|
105 |
|
|
}
|
106 |
|
|
initIDs();
|
107 |
|
|
}
|
108 |
|
|
|
109 |
|
|
public static VMChannel getStdin() throws IOException
|
110 |
|
|
{
|
111 |
|
|
return new VMChannel(stdin_fd());
|
112 |
|
|
}
|
113 |
|
|
|
114 |
|
|
public static VMChannel getStdout() throws IOException
|
115 |
|
|
{
|
116 |
|
|
return new VMChannel(stdout_fd());
|
117 |
|
|
}
|
118 |
|
|
|
119 |
|
|
public static VMChannel getStderr() throws IOException
|
120 |
|
|
{
|
121 |
|
|
return new VMChannel(stderr_fd());
|
122 |
|
|
}
|
123 |
|
|
|
124 |
|
|
private static native int stdin_fd();
|
125 |
|
|
private static native int stdout_fd();
|
126 |
|
|
private static native int stderr_fd();
|
127 |
|
|
|
128 |
|
|
/**
|
129 |
|
|
* Set the file descriptor to have the required blocking
|
130 |
|
|
* setting.
|
131 |
|
|
*
|
132 |
|
|
* @param blocking The blocking flag to set.
|
133 |
|
|
*/
|
134 |
|
|
public void setBlocking(boolean blocking) throws IOException
|
135 |
|
|
{
|
136 |
|
|
setBlocking(nfd.getNativeFD(), blocking);
|
137 |
|
|
}
|
138 |
|
|
|
139 |
|
|
private static native void setBlocking(int fd, boolean blocking)
|
140 |
|
|
throws IOException;
|
141 |
|
|
|
142 |
|
|
public int available() throws IOException
|
143 |
|
|
{
|
144 |
|
|
return available(nfd.getNativeFD());
|
145 |
|
|
}
|
146 |
|
|
|
147 |
|
|
private static native int available(int native_fd) throws IOException;
|
148 |
|
|
|
149 |
|
|
/**
|
150 |
|
|
* Reads a byte buffer directly using the supplied file descriptor.
|
151 |
|
|
*
|
152 |
|
|
* @param dst Direct Byte Buffer to read to.
|
153 |
|
|
* @return Number of bytes read.
|
154 |
|
|
* @throws IOException If an error occurs or dst is not a direct buffers.
|
155 |
|
|
*/
|
156 |
|
|
public int read(ByteBuffer dst)
|
157 |
|
|
throws IOException
|
158 |
|
|
{
|
159 |
|
|
return read(nfd.getNativeFD(), dst);
|
160 |
|
|
}
|
161 |
|
|
|
162 |
|
|
private static native int read(int fd, ByteBuffer dst) throws IOException;
|
163 |
|
|
|
164 |
|
|
/**
|
165 |
|
|
* Read a single byte.
|
166 |
|
|
*
|
167 |
|
|
* @return The byte read, or -1 on end of file.
|
168 |
|
|
* @throws IOException
|
169 |
|
|
*/
|
170 |
|
|
public int read() throws IOException
|
171 |
|
|
{
|
172 |
|
|
return read(nfd.getNativeFD());
|
173 |
|
|
}
|
174 |
|
|
|
175 |
|
|
private static native int read(int fd) throws IOException;
|
176 |
|
|
|
177 |
|
|
/**
|
178 |
|
|
* Reads into byte buffers directly using the supplied file descriptor.
|
179 |
|
|
* Assumes that the buffer list contains DirectBuffers. Will perform a
|
180 |
|
|
* scattering read.
|
181 |
|
|
*
|
182 |
|
|
* @param dsts An array direct byte buffers.
|
183 |
|
|
* @param offset Index of the first buffer to read to.
|
184 |
|
|
* @param length The number of buffers to read to.
|
185 |
|
|
* @return Number of bytes read.
|
186 |
|
|
* @throws IOException If an error occurs or the dsts are not direct buffers.
|
187 |
|
|
*/
|
188 |
|
|
public long readScattering(ByteBuffer[] dsts, int offset, int length)
|
189 |
|
|
throws IOException
|
190 |
|
|
{
|
191 |
|
|
if (offset + length > dsts.length)
|
192 |
|
|
throw new IndexOutOfBoundsException("offset + length > dsts.length");
|
193 |
|
|
|
194 |
|
|
return readScattering(nfd.getNativeFD(), dsts, offset, length);
|
195 |
|
|
}
|
196 |
|
|
|
197 |
|
|
private static native long readScattering(int fd, ByteBuffer[] dsts,
|
198 |
|
|
int offset, int length)
|
199 |
|
|
throws IOException;
|
200 |
|
|
|
201 |
|
|
/**
|
202 |
|
|
* Receive a datagram on this channel, returning the host address
|
203 |
|
|
* that sent the datagram.
|
204 |
|
|
*
|
205 |
|
|
* @param dst Where to store the datagram.
|
206 |
|
|
* @return The host address that sent the datagram.
|
207 |
|
|
* @throws IOException
|
208 |
|
|
*/
|
209 |
|
|
public SocketAddress receive(ByteBuffer dst) throws IOException
|
210 |
|
|
{
|
211 |
|
|
if (kind != Kind.SOCK_DGRAM)
|
212 |
|
|
throw new SocketException("not a datagram socket");
|
213 |
|
|
ByteBuffer hostPort = ByteBuffer.allocateDirect(18);
|
214 |
|
|
int hostlen = receive(nfd.getNativeFD(), dst, hostPort);
|
215 |
|
|
if (hostlen == 0)
|
216 |
|
|
return null;
|
217 |
|
|
if (hostlen == 4) // IPv4
|
218 |
|
|
{
|
219 |
|
|
byte[] addr = new byte[4];
|
220 |
|
|
hostPort.get(addr);
|
221 |
|
|
int port = hostPort.getShort() & 0xFFFF;
|
222 |
|
|
return new InetSocketAddress(Inet4Address.getByAddress(addr), port);
|
223 |
|
|
}
|
224 |
|
|
if (hostlen == 16) // IPv6
|
225 |
|
|
{
|
226 |
|
|
byte[] addr = new byte[16];
|
227 |
|
|
hostPort.get(addr);
|
228 |
|
|
int port = hostPort.getShort() & 0xFFFF;
|
229 |
|
|
return new InetSocketAddress(Inet6Address.getByAddress(addr), port);
|
230 |
|
|
}
|
231 |
|
|
|
232 |
|
|
throw new SocketException("host address received with invalid length: "
|
233 |
|
|
+ hostlen);
|
234 |
|
|
}
|
235 |
|
|
|
236 |
|
|
private static native int receive (int fd, ByteBuffer dst, ByteBuffer address)
|
237 |
|
|
throws IOException;
|
238 |
|
|
|
239 |
|
|
/**
|
240 |
|
|
* Writes from a direct byte bufer using the supplied file descriptor.
|
241 |
|
|
* Assumes the buffer is a DirectBuffer.
|
242 |
|
|
*
|
243 |
|
|
* @param src The source buffer.
|
244 |
|
|
* @return Number of bytes written.
|
245 |
|
|
* @throws IOException
|
246 |
|
|
*/
|
247 |
|
|
public int write(ByteBuffer src) throws IOException
|
248 |
|
|
{
|
249 |
|
|
return write(nfd.getNativeFD(), src);
|
250 |
|
|
}
|
251 |
|
|
|
252 |
|
|
private native int write(int fd, ByteBuffer src) throws IOException;
|
253 |
|
|
|
254 |
|
|
/**
|
255 |
|
|
* Writes from byte buffers directly using the supplied file descriptor.
|
256 |
|
|
* Assumes the that buffer list constains DirectBuffers. Will perform
|
257 |
|
|
* as gathering write.
|
258 |
|
|
*
|
259 |
|
|
* @param srcs
|
260 |
|
|
* @param offset
|
261 |
|
|
* @param length
|
262 |
|
|
* @return Number of bytes written.
|
263 |
|
|
* @throws IOException
|
264 |
|
|
*/
|
265 |
|
|
public long writeGathering(ByteBuffer[] srcs, int offset, int length)
|
266 |
|
|
throws IOException
|
267 |
|
|
{
|
268 |
|
|
if (offset + length > srcs.length)
|
269 |
|
|
throw new IndexOutOfBoundsException("offset + length > srcs.length");
|
270 |
|
|
|
271 |
|
|
// A gathering write is limited to 16 buffers; when writing, ensure
|
272 |
|
|
// that we have at least one buffer with something in it in the 16
|
273 |
|
|
// buffer window starting at offset.
|
274 |
|
|
while (!srcs[offset].hasRemaining() && offset < srcs.length)
|
275 |
|
|
offset++;
|
276 |
|
|
|
277 |
|
|
// There are no buffers with anything to write.
|
278 |
|
|
if (offset == srcs.length)
|
279 |
|
|
return 0;
|
280 |
|
|
|
281 |
|
|
// If we advanced `offset' so far that we don't have `length'
|
282 |
|
|
// buffers left, reset length to only the remaining buffers.
|
283 |
|
|
if (length > srcs.length - offset)
|
284 |
|
|
length = srcs.length - offset;
|
285 |
|
|
|
286 |
|
|
return writeGathering(nfd.getNativeFD(), srcs, offset, length);
|
287 |
|
|
}
|
288 |
|
|
|
289 |
|
|
private native long writeGathering(int fd, ByteBuffer[] srcs,
|
290 |
|
|
int offset, int length)
|
291 |
|
|
throws IOException;
|
292 |
|
|
|
293 |
|
|
/**
|
294 |
|
|
* Send a datagram to the given address.
|
295 |
|
|
*
|
296 |
|
|
* @param src The source buffer.
|
297 |
|
|
* @param dst The destination address.
|
298 |
|
|
* @return The number of bytes written.
|
299 |
|
|
* @throws IOException
|
300 |
|
|
*/
|
301 |
|
|
public int send(ByteBuffer src, InetSocketAddress dst)
|
302 |
|
|
throws IOException
|
303 |
|
|
{
|
304 |
|
|
InetAddress addr = dst.getAddress();
|
305 |
|
|
if (addr == null)
|
306 |
|
|
throw new NullPointerException();
|
307 |
|
|
if (addr instanceof Inet4Address)
|
308 |
|
|
return send(nfd.getNativeFD(), src, addr.getAddress(), dst.getPort());
|
309 |
|
|
else if (addr instanceof Inet6Address)
|
310 |
|
|
return send6(nfd.getNativeFD(), src, addr.getAddress(), dst.getPort());
|
311 |
|
|
else
|
312 |
|
|
throw new SocketException("unrecognized inet address type");
|
313 |
|
|
}
|
314 |
|
|
|
315 |
|
|
// Send to an IPv4 address.
|
316 |
|
|
private static native int send(int fd, ByteBuffer src, byte[] addr, int port)
|
317 |
|
|
throws IOException;
|
318 |
|
|
|
319 |
|
|
// Send to an IPv6 address.
|
320 |
|
|
private static native int send6(int fd, ByteBuffer src, byte[] addr, int port)
|
321 |
|
|
throws IOException;
|
322 |
|
|
|
323 |
|
|
/**
|
324 |
|
|
* Write a single byte.
|
325 |
|
|
*
|
326 |
|
|
* @param b The byte to write.
|
327 |
|
|
* @throws IOException
|
328 |
|
|
*/
|
329 |
|
|
public void write(int b) throws IOException
|
330 |
|
|
{
|
331 |
|
|
write(nfd.getNativeFD(), b);
|
332 |
|
|
}
|
333 |
|
|
|
334 |
|
|
private static native void write(int fd, int b) throws IOException;
|
335 |
|
|
|
336 |
|
|
private native static void initIDs();
|
337 |
|
|
|
338 |
|
|
// Network (socket) specific methods.
|
339 |
|
|
|
340 |
|
|
/**
|
341 |
|
|
* Create a new socket. This method will initialize the native file
|
342 |
|
|
* descriptor state of this instance.
|
343 |
|
|
*
|
344 |
|
|
* @param stream Whether or not to create a streaming socket, or a datagram
|
345 |
|
|
* socket.
|
346 |
|
|
* @throws IOException If creating a new socket fails, or if this
|
347 |
|
|
* channel already has its native descriptor initialized.
|
348 |
|
|
*/
|
349 |
|
|
public void initSocket(boolean stream) throws IOException
|
350 |
|
|
{
|
351 |
|
|
if (nfd.isValid())
|
352 |
|
|
throw new IOException("native FD already initialized");
|
353 |
|
|
if (stream)
|
354 |
|
|
kind = Kind.SOCK_STREAM;
|
355 |
|
|
else
|
356 |
|
|
kind = Kind.SOCK_DGRAM;
|
357 |
|
|
nfd.setNativeFD(socket(stream));
|
358 |
|
|
}
|
359 |
|
|
|
360 |
|
|
/**
|
361 |
|
|
* Create a new socket, returning the native file descriptor.
|
362 |
|
|
*
|
363 |
|
|
* @param stream Set to true for streaming sockets; false for datagrams.
|
364 |
|
|
* @return The native file descriptor.
|
365 |
|
|
* @throws IOException If creating the socket fails.
|
366 |
|
|
*/
|
367 |
|
|
private static native int socket(boolean stream) throws IOException;
|
368 |
|
|
|
369 |
|
|
/**
|
370 |
|
|
* Connect the underlying socket file descriptor to the remote host.
|
371 |
|
|
*
|
372 |
|
|
* @param saddr The address to connect to.
|
373 |
|
|
* @param timeout The connect timeout to use for blocking connects.
|
374 |
|
|
* @return True if the connection succeeded; false if the file descriptor
|
375 |
|
|
* is in non-blocking mode and the connection did not immediately
|
376 |
|
|
* succeed.
|
377 |
|
|
* @throws IOException If an error occurs while connecting.
|
378 |
|
|
*/
|
379 |
|
|
public boolean connect(InetSocketAddress saddr, int timeout)
|
380 |
|
|
throws SocketException
|
381 |
|
|
{
|
382 |
|
|
int fd;
|
383 |
|
|
|
384 |
|
|
InetAddress addr = saddr.getAddress();
|
385 |
|
|
|
386 |
|
|
// Translates an IOException into a SocketException to conform
|
387 |
|
|
// to the throws clause.
|
388 |
|
|
try
|
389 |
|
|
{
|
390 |
|
|
fd = nfd.getNativeFD();
|
391 |
|
|
}
|
392 |
|
|
catch (IOException ioe)
|
393 |
|
|
{
|
394 |
|
|
throw new SocketException(ioe.getMessage());
|
395 |
|
|
}
|
396 |
|
|
|
397 |
|
|
if (addr instanceof Inet4Address)
|
398 |
|
|
return connect(fd, addr.getAddress(), saddr.getPort(),
|
399 |
|
|
timeout);
|
400 |
|
|
if (addr instanceof Inet6Address)
|
401 |
|
|
return connect6(fd, addr.getAddress(), saddr.getPort(),
|
402 |
|
|
timeout);
|
403 |
|
|
throw new SocketException("unsupported internet address");
|
404 |
|
|
}
|
405 |
|
|
|
406 |
|
|
private static native boolean connect(int fd, byte[] addr, int port, int timeout)
|
407 |
|
|
throws SocketException;
|
408 |
|
|
|
409 |
|
|
private static native boolean connect6(int fd, byte[] addr, int port, int timeout)
|
410 |
|
|
throws SocketException;
|
411 |
|
|
|
412 |
|
|
/**
|
413 |
|
|
* Disconnect this channel, if it is a datagram socket. Disconnecting
|
414 |
|
|
* a datagram channel will disassociate it from any address, so the
|
415 |
|
|
* socket will remain open, but can send and receive datagrams from
|
416 |
|
|
* any address.
|
417 |
|
|
*
|
418 |
|
|
* @throws IOException If disconnecting this channel fails, or if this
|
419 |
|
|
* channel is not a datagram channel.
|
420 |
|
|
*/
|
421 |
|
|
public void disconnect() throws IOException
|
422 |
|
|
{
|
423 |
|
|
if (kind != Kind.SOCK_DGRAM)
|
424 |
|
|
throw new IOException("can only disconnect datagram channels");
|
425 |
|
|
disconnect(nfd.getNativeFD());
|
426 |
|
|
}
|
427 |
|
|
|
428 |
|
|
private static native void disconnect(int fd) throws IOException;
|
429 |
|
|
|
430 |
|
|
public InetSocketAddress getLocalAddress() throws IOException
|
431 |
|
|
{
|
432 |
|
|
if (!nfd.isValid())
|
433 |
|
|
return null;
|
434 |
|
|
ByteBuffer name = ByteBuffer.allocateDirect(18);
|
435 |
|
|
int namelen = getsockname(nfd.getNativeFD(), name);
|
436 |
|
|
if (namelen == 0) // not bound
|
437 |
|
|
return null; // XXX return some wildcard?
|
438 |
|
|
if (namelen == 4)
|
439 |
|
|
{
|
440 |
|
|
byte[] addr = new byte[4];
|
441 |
|
|
name.get(addr);
|
442 |
|
|
int port = name.getShort() & 0xFFFF;
|
443 |
|
|
return new InetSocketAddress(Inet4Address.getByAddress(addr), port);
|
444 |
|
|
}
|
445 |
|
|
if (namelen == 16)
|
446 |
|
|
{
|
447 |
|
|
byte[] addr = new byte[16];
|
448 |
|
|
name.get(addr);
|
449 |
|
|
int port = name.getShort() & 0xFFFF;
|
450 |
|
|
return new InetSocketAddress(Inet6Address.getByAddress(addr), port);
|
451 |
|
|
}
|
452 |
|
|
throw new SocketException("invalid address length");
|
453 |
|
|
}
|
454 |
|
|
|
455 |
|
|
private static native int getsockname(int fd, ByteBuffer name)
|
456 |
|
|
throws IOException;
|
457 |
|
|
|
458 |
|
|
/**
|
459 |
|
|
* Returns the socket address of the remote peer this channel is connected
|
460 |
|
|
* to, or null if this channel is not yet connected.
|
461 |
|
|
*
|
462 |
|
|
* @return The peer address.
|
463 |
|
|
* @throws IOException
|
464 |
|
|
*/
|
465 |
|
|
public InetSocketAddress getPeerAddress() throws IOException
|
466 |
|
|
{
|
467 |
|
|
if (!nfd.isValid())
|
468 |
|
|
return null;
|
469 |
|
|
ByteBuffer name = ByteBuffer.allocateDirect(18);
|
470 |
|
|
int namelen = getpeername (nfd.getNativeFD(), name);
|
471 |
|
|
if (namelen == 0) // not connected yet
|
472 |
|
|
return null;
|
473 |
|
|
if (namelen == 4) // IPv4
|
474 |
|
|
{
|
475 |
|
|
byte[] addr = new byte[4];
|
476 |
|
|
name.get(addr);
|
477 |
|
|
int port = name.getShort() & 0xFFFF;
|
478 |
|
|
return new InetSocketAddress(Inet4Address.getByAddress(addr), port);
|
479 |
|
|
}
|
480 |
|
|
else if (namelen == 16) // IPv6
|
481 |
|
|
{
|
482 |
|
|
byte[] addr = new byte[16];
|
483 |
|
|
name.get(addr);
|
484 |
|
|
int port = name.getShort() & 0xFFFF;
|
485 |
|
|
return new InetSocketAddress(Inet6Address.getByAddress(addr), port);
|
486 |
|
|
}
|
487 |
|
|
throw new SocketException("invalid address length");
|
488 |
|
|
}
|
489 |
|
|
|
490 |
|
|
/*
|
491 |
|
|
* The format here is the peer address, followed by the port number.
|
492 |
|
|
* The returned value is the length of the peer address; thus, there
|
493 |
|
|
* will be LEN + 2 valid bytes put into NAME.
|
494 |
|
|
*/
|
495 |
|
|
private static native int getpeername(int fd, ByteBuffer name)
|
496 |
|
|
throws IOException;
|
497 |
|
|
|
498 |
|
|
/**
|
499 |
|
|
* Accept an incoming connection, returning a new VMChannel, or null
|
500 |
|
|
* if the channel is nonblocking and no connection is pending.
|
501 |
|
|
*
|
502 |
|
|
* @return The accepted connection, or null.
|
503 |
|
|
* @throws IOException If an IO error occurs.
|
504 |
|
|
*/
|
505 |
|
|
public VMChannel accept() throws IOException
|
506 |
|
|
{
|
507 |
|
|
int new_fd = accept(nfd.getNativeFD());
|
508 |
|
|
if (new_fd == -1) // non-blocking accept had no pending connection
|
509 |
|
|
return null;
|
510 |
|
|
return new VMChannel(new_fd);
|
511 |
|
|
}
|
512 |
|
|
|
513 |
|
|
private static native int accept(int native_fd) throws IOException;
|
514 |
|
|
|
515 |
|
|
// File-specific methods.
|
516 |
|
|
|
517 |
|
|
/**
|
518 |
|
|
* Open a file at PATH, initializing the native state to operate on
|
519 |
|
|
* that open file.
|
520 |
|
|
*
|
521 |
|
|
* @param path The absolute file path.
|
522 |
|
|
* @throws IOException If the file cannot be opened, or if this
|
523 |
|
|
* channel was previously initialized.
|
524 |
|
|
*/
|
525 |
|
|
public void openFile(String path, int mode) throws IOException
|
526 |
|
|
{
|
527 |
|
|
if (nfd.isValid() || nfd.isClosed())
|
528 |
|
|
throw new IOException("can't reinitialize this channel");
|
529 |
|
|
int fd = open(path, mode);
|
530 |
|
|
nfd.setNativeFD(fd);
|
531 |
|
|
kind = Kind.FILE;
|
532 |
|
|
}
|
533 |
|
|
|
534 |
|
|
private static native int open(String path, int mode) throws IOException;
|
535 |
|
|
|
536 |
|
|
public long position() throws IOException
|
537 |
|
|
{
|
538 |
|
|
if (kind != Kind.FILE)
|
539 |
|
|
throw new IOException("not a file");
|
540 |
|
|
return position(nfd.getNativeFD());
|
541 |
|
|
}
|
542 |
|
|
|
543 |
|
|
private static native long position(int fd) throws IOException;
|
544 |
|
|
|
545 |
|
|
public void seek(long pos) throws IOException
|
546 |
|
|
{
|
547 |
|
|
if (kind != Kind.FILE)
|
548 |
|
|
throw new IOException("not a file");
|
549 |
|
|
seek(nfd.getNativeFD(), pos);
|
550 |
|
|
}
|
551 |
|
|
|
552 |
|
|
private static native void seek(int fd, long pos) throws IOException;
|
553 |
|
|
|
554 |
|
|
public void truncate(long length) throws IOException
|
555 |
|
|
{
|
556 |
|
|
if (kind != Kind.FILE)
|
557 |
|
|
throw new IOException("not a file");
|
558 |
|
|
truncate(nfd.getNativeFD(), length);
|
559 |
|
|
}
|
560 |
|
|
|
561 |
|
|
private static native void truncate(int fd, long len) throws IOException;
|
562 |
|
|
|
563 |
|
|
public boolean lock(long pos, long len, boolean shared, boolean wait)
|
564 |
|
|
throws IOException
|
565 |
|
|
{
|
566 |
|
|
if (kind != Kind.FILE)
|
567 |
|
|
throw new IOException("not a file");
|
568 |
|
|
return lock(nfd.getNativeFD(), pos, len, shared, wait);
|
569 |
|
|
}
|
570 |
|
|
|
571 |
|
|
private static native boolean lock(int fd, long pos, long len,
|
572 |
|
|
boolean shared, boolean wait)
|
573 |
|
|
throws IOException;
|
574 |
|
|
|
575 |
|
|
public void unlock(long pos, long len) throws IOException
|
576 |
|
|
{
|
577 |
|
|
if (kind != Kind.FILE)
|
578 |
|
|
throw new IOException("not a file");
|
579 |
|
|
unlock(nfd.getNativeFD(), pos, len);
|
580 |
|
|
}
|
581 |
|
|
|
582 |
|
|
private static native void unlock(int fd, long pos, long len) throws IOException;
|
583 |
|
|
|
584 |
|
|
public long size() throws IOException
|
585 |
|
|
{
|
586 |
|
|
if (kind != Kind.FILE)
|
587 |
|
|
throw new IOException("not a file");
|
588 |
|
|
return size(nfd.getNativeFD());
|
589 |
|
|
}
|
590 |
|
|
|
591 |
|
|
private static native long size(int fd) throws IOException;
|
592 |
|
|
|
593 |
|
|
public MappedByteBuffer map(char mode, long position, int size)
|
594 |
|
|
throws IOException
|
595 |
|
|
{
|
596 |
|
|
if (kind != Kind.FILE)
|
597 |
|
|
throw new IOException("not a file");
|
598 |
|
|
return map(nfd.getNativeFD(), mode, position, size);
|
599 |
|
|
}
|
600 |
|
|
|
601 |
|
|
private static native MappedByteBuffer map(int fd, char mode,
|
602 |
|
|
long position, int size)
|
603 |
|
|
throws IOException;
|
604 |
|
|
|
605 |
|
|
public boolean flush(boolean metadata) throws IOException
|
606 |
|
|
{
|
607 |
|
|
if (kind != Kind.FILE)
|
608 |
|
|
throw new IOException("not a file");
|
609 |
|
|
return flush(nfd.getNativeFD(), metadata);
|
610 |
|
|
}
|
611 |
|
|
|
612 |
|
|
private static native boolean flush(int fd, boolean metadata) throws IOException;
|
613 |
|
|
|
614 |
|
|
// Close.
|
615 |
|
|
|
616 |
|
|
/**
|
617 |
|
|
* Close this socket. The socket is also automatically closed when this
|
618 |
|
|
* object is finalized.
|
619 |
|
|
*
|
620 |
|
|
* @throws IOException If closing the socket fails, or if this object has
|
621 |
|
|
* no open socket.
|
622 |
|
|
*/
|
623 |
|
|
public void close() throws IOException
|
624 |
|
|
{
|
625 |
|
|
nfd.close();
|
626 |
|
|
}
|
627 |
|
|
|
628 |
|
|
static native void close(int native_fd) throws IOException;
|
629 |
|
|
|
630 |
|
|
/**
|
631 |
|
|
* <p>Provides a simple mean for the JNI code to find out whether the
|
632 |
|
|
* current thread was interrupted by a call to Thread.interrupt().</p>
|
633 |
|
|
*
|
634 |
|
|
* @return
|
635 |
|
|
*/
|
636 |
|
|
static boolean isThreadInterrupted()
|
637 |
|
|
{
|
638 |
|
|
return Thread.currentThread().isInterrupted();
|
639 |
|
|
}
|
640 |
|
|
|
641 |
|
|
// Inner classes.
|
642 |
|
|
|
643 |
|
|
/**
|
644 |
|
|
* A wrapper for a native file descriptor integer. This tracks the state
|
645 |
|
|
* of an open file descriptor, and ensures that
|
646 |
|
|
*
|
647 |
|
|
* This class need not be fully supported by virtual machines; if a
|
648 |
|
|
* virtual machine does not use integer file descriptors, or does and
|
649 |
|
|
* wishes to hide that, then the methods of this class may be stubbed out.
|
650 |
|
|
*
|
651 |
|
|
* System-specific classes that depend on access to native file descriptor
|
652 |
|
|
* integers SHOULD declare this fact.
|
653 |
|
|
*/
|
654 |
|
|
public final class State
|
655 |
|
|
{
|
656 |
|
|
private int native_fd;
|
657 |
|
|
private boolean valid;
|
658 |
|
|
private boolean closed;
|
659 |
|
|
|
660 |
|
|
State()
|
661 |
|
|
{
|
662 |
|
|
native_fd = -1;
|
663 |
|
|
valid = false;
|
664 |
|
|
closed = false;
|
665 |
|
|
}
|
666 |
|
|
|
667 |
|
|
public boolean isValid()
|
668 |
|
|
{
|
669 |
|
|
return valid;
|
670 |
|
|
}
|
671 |
|
|
|
672 |
|
|
public boolean isClosed()
|
673 |
|
|
{
|
674 |
|
|
return closed;
|
675 |
|
|
}
|
676 |
|
|
|
677 |
|
|
public int getNativeFD() throws IOException
|
678 |
|
|
{
|
679 |
|
|
if (!valid)
|
680 |
|
|
throw new IOException("invalid file descriptor");
|
681 |
|
|
return native_fd;
|
682 |
|
|
}
|
683 |
|
|
|
684 |
|
|
void setNativeFD(final int native_fd) throws IOException
|
685 |
|
|
{
|
686 |
|
|
if (valid)
|
687 |
|
|
throw new IOException("file descriptor already initialized");
|
688 |
|
|
this.native_fd = native_fd;
|
689 |
|
|
valid = true;
|
690 |
|
|
}
|
691 |
|
|
|
692 |
|
|
public void close() throws IOException
|
693 |
|
|
{
|
694 |
|
|
if (!valid)
|
695 |
|
|
throw new IOException("invalid file descriptor");
|
696 |
|
|
try
|
697 |
|
|
{
|
698 |
|
|
VMChannel.close(native_fd);
|
699 |
|
|
}
|
700 |
|
|
finally
|
701 |
|
|
{
|
702 |
|
|
valid = false;
|
703 |
|
|
closed = true;
|
704 |
|
|
}
|
705 |
|
|
}
|
706 |
|
|
|
707 |
|
|
public String toString()
|
708 |
|
|
{
|
709 |
|
|
if (closed)
|
710 |
|
|
return "<<closed>>";
|
711 |
|
|
if (!valid)
|
712 |
|
|
return "<<invalid>>";
|
713 |
|
|
return String.valueOf(native_fd);
|
714 |
|
|
}
|
715 |
|
|
|
716 |
|
|
protected void finalize() throws Throwable
|
717 |
|
|
{
|
718 |
|
|
try
|
719 |
|
|
{
|
720 |
|
|
if (valid)
|
721 |
|
|
close();
|
722 |
|
|
}
|
723 |
|
|
finally
|
724 |
|
|
{
|
725 |
|
|
super.finalize();
|
726 |
|
|
}
|
727 |
|
|
}
|
728 |
|
|
}
|
729 |
|
|
|
730 |
|
|
/**
|
731 |
|
|
* An enumeration of possible kinds of channel.
|
732 |
|
|
*/
|
733 |
|
|
static class Kind // XXX enum
|
734 |
|
|
{
|
735 |
|
|
/** A streaming (TCP) socket. */
|
736 |
|
|
static final Kind SOCK_STREAM = new Kind();
|
737 |
|
|
|
738 |
|
|
/** A datagram (UDP) socket. */
|
739 |
|
|
static final Kind SOCK_DGRAM = new Kind();
|
740 |
|
|
|
741 |
|
|
/** A file. */
|
742 |
|
|
static final Kind FILE = new Kind();
|
743 |
|
|
|
744 |
|
|
/** Something else; not a socket or file. */
|
745 |
|
|
static final Kind OTHER = new Kind();
|
746 |
|
|
|
747 |
|
|
private Kind() { }
|
748 |
|
|
}
|
749 |
|
|
}
|