+
+ if (cmd == F_GETLK) {
+ // The simple Java file locking below will happily return
+ // a lock that overlaps one already held by the JVM. Thus
+ // we must check over all the locks held by other Runtimes
+ for (int i=0; i < locks.length; i++) {
+ if (locks[i] == null || !s.equals(locks[i].seekable()))
+ continue;
+ if (!locks[i].overlaps(l_start, l_len))
+ continue;
+ if (locks[i].getOwner() == this)
+ continue;
+ if (locks[i].isShared() && l_type == F_RDLCK)
+ continue;
+
+ // overlapping lock held by another process
+ return 0;
+ }
+
+ // check if an area is lockable by attempting to obtain a lock
+ Seekable.Lock lock = s.lock(l_start, l_len, l_type == F_RDLCK);
+
+ if (lock != null) { // no lock exists
+ memWrite(arg, SEEK_SET|(F_UNLCK<<16));
+ lock.release();
+ }
+
+ return 0;
+ }
+
+ // now processing F_SETLK
+ if (cmd != F_SETLK) return -EINVAL;
+
+ if (l_type == F_UNLCK) {
+ // release all locks that fall within the boundaries given
+ for (int i=0; i < locks.length; i++) {
+ if (locks[i] == null || !s.equals(locks[i].seekable()))
+ continue;
+ if (locks[i].getOwner() != this) continue;
+
+ int pos = (int)locks[i].position();
+ if (pos < l_start) continue;
+ if (l_start != 0 && l_len != 0) // start/len 0 means unlock all
+ if (pos + locks[i].size() > l_start + l_len)
+ continue;
+
+ locks[i].release();
+ locks[i] = null;
+ }
+ return 0;
+
+ } else if (l_type == F_RDLCK || l_type == F_WRLCK) {
+ // first see if a lock already exists
+ for (int i=0; i < locks.length; i++) {
+ if (locks[i] == null || !s.equals(locks[i].seekable()))
+ continue;
+
+ if (locks[i].getOwner() == this) {
+ // if this Runtime owns an overlapping lock work with it
+ if (locks[i].contained(l_start, l_len)) {
+ locks[i].release();
+ locks[i] = null;
+ } else if (locks[i].contains(l_start, l_len)) {
+ if (locks[i].isShared() == (l_type == F_RDLCK)) {
+ // return this more general lock
+ memWrite(arg+4, (int)locks[i].position());
+ memWrite(arg+8, (int)locks[i].size());
+ return 0;
+ } else {
+ locks[i].release();
+ locks[i] = null;
+ }
+ }
+ } else {
+ // if another Runtime has an lock and it is exclusive or
+ // we want an exclusive lock then fail
+ if (locks[i].overlaps(l_start, l_len)
+ && (!locks[i].isShared() || l_type == F_WRLCK))
+ return -EAGAIN;
+ }
+ }
+
+ // create the lock
+ Seekable.Lock lock = s.lock(l_start, l_len, l_type == F_RDLCK);
+ if (lock == null) return -EAGAIN;
+ lock.setOwner(this);
+
+ int i;
+ for (i=0; i < locks.length; i++)
+ if (locks[i] == null) break;
+ if (i == locks.length) return -ENOLCK;
+ locks[i] = lock;
+ return 0;
+
+ } else {
+ return -EINVAL;
+ }
+
+ } catch (IOException e) { throw new RuntimeException(e); }
+ }
+
+ static class SocketFD extends FD {
+ public static final int TYPE_STREAM = 0;
+ public static final int TYPE_DGRAM = 1;
+ public static final int LISTEN = 2;
+ public int type() { return flags & 1; }
+ public boolean listen() { return (flags & 2) != 0; }
+
+ int flags;
+ int options;
+
+ Socket s;
+ ServerSocket ss;
+ DatagramSocket ds;
+
+ InetAddress bindAddr;
+ int bindPort = -1;
+ InetAddress connectAddr;
+ int connectPort = -1;
+
+ DatagramPacket dp;
+ InputStream is;
+ OutputStream os;
+
+ private static final byte[] EMPTY = new byte[0];
+ public SocketFD(int type) {
+ flags = type;
+ if(type == TYPE_DGRAM)
+ dp = new DatagramPacket(EMPTY,0);
+ }
+
+ public void setOptions() {
+ try {
+ if(s != null && type() == TYPE_STREAM && !listen()) {
+ Platform.socketSetKeepAlive(s,(options & SO_KEEPALIVE) != 0);
+ }
+ } catch(SocketException e) {
+ if(STDERR_DIAG) e.printStackTrace();
+ }
+ }
+
+ public void _close() {
+ try {
+ if(s != null) s.close();
+ if(ss != null) ss.close();
+ if(ds != null) ds.close();
+ } catch(IOException e) {
+ /* ignore */
+ }
+ }
+
+ public int read(byte[] a, int off, int length) throws ErrnoException {
+ if(type() == TYPE_DGRAM) return recvfrom(a,off,length,null,null);
+ if(is == null) throw new ErrnoException(EPIPE);
+ try {
+ int n = is.read(a,off,length);
+ return n < 0 ? 0 : n;
+ } catch(IOException e) {
+ throw new ErrnoException(EIO);
+ }
+ }
+
+ public int recvfrom(byte[] a, int off, int length, InetAddress[] sockAddr, int[] port) throws ErrnoException {
+ if(type() == TYPE_STREAM) return read(a,off,length);
+
+ if(off != 0) throw new IllegalArgumentException("off must be 0");
+ dp.setData(a);
+ dp.setLength(length);
+ try {
+ if(ds == null) ds = new DatagramSocket();
+ ds.receive(dp);
+ } catch(IOException e) {
+ if(STDERR_DIAG) e.printStackTrace();
+ throw new ErrnoException(EIO);
+ }
+ if(sockAddr != null) {
+ sockAddr[0] = dp.getAddress();
+ port[0] = dp.getPort();
+ }
+ return dp.getLength();
+ }
+
+ public int write(byte[] a, int off, int length) throws ErrnoException {
+ if(type() == TYPE_DGRAM) return sendto(a,off,length,null,-1);
+
+ if(os == null) throw new ErrnoException(EPIPE);
+ try {
+ os.write(a,off,length);
+ return length;
+ } catch(IOException e) {
+ throw new ErrnoException(EIO);
+ }
+ }
+
+ public int sendto(byte[] a, int off, int length, InetAddress destAddr, int destPort) throws ErrnoException {
+ if(off != 0) throw new IllegalArgumentException("off must be 0");
+ if(type() == TYPE_STREAM) return write(a,off,length);
+
+ if(destAddr == null) {
+ destAddr = connectAddr;
+ destPort = connectPort;
+
+ if(destAddr == null) throw new ErrnoException(ENOTCONN);
+ }
+
+ dp.setAddress(destAddr);
+ dp.setPort(destPort);
+ dp.setData(a);
+ dp.setLength(length);
+
+ try {
+ if(ds == null) ds = new DatagramSocket();
+ ds.send(dp);
+ } catch(IOException e) {
+ if(STDERR_DIAG) e.printStackTrace();
+ if("Network is unreachable".equals(e.getMessage())) throw new ErrnoException(EHOSTUNREACH);
+ throw new ErrnoException(EIO);
+ }
+ return dp.getLength();
+ }
+
+ public int flags() { return O_RDWR; }
+ public FStat _fstat() { return new SocketFStat(); }