X-Git-Url: http://git.megacz.com/?p=nestedvm.git;a=blobdiff_plain;f=src%2Forg%2Fibex%2Fnestedvm%2FUnixRuntime.java;h=a4b1991dde398d7182d6c2b05b1d0ce1a9992c3d;hp=0bed8ed27ef330538112c773149dacc134fec68d;hb=615390526d6598c4124370fdd77b55894413cd1d;hpb=2db6b04d7557a26e3b9e7440e7968aaec262216f diff --git a/src/org/ibex/nestedvm/UnixRuntime.java b/src/org/ibex/nestedvm/UnixRuntime.java index 0bed8ed..a4b1991 100644 --- a/src/org/ibex/nestedvm/UnixRuntime.java +++ b/src/org/ibex/nestedvm/UnixRuntime.java @@ -3,6 +3,7 @@ package org.ibex.nestedvm; import org.ibex.nestedvm.util.*; import java.io.*; import java.util.*; +import java.net.*; // FEATURE: vfork @@ -40,19 +41,18 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { ? userdir.substring(1) : ""; } - // NOTE: getDisplayName() is a Java2 function private static String posixTZ() { StringBuffer sb = new StringBuffer(); TimeZone zone = TimeZone.getDefault(); int off = zone.getRawOffset() / 1000; - sb.append(zone.getDisplayName(false,TimeZone.SHORT)); + sb.append(Platform.timeZoneGetDisplayName(zone,false,false)); if(off > 0) sb.append("-"); else off = -off; sb.append(off/3600); off = off%3600; if(off > 0) sb.append(":").append(off/60); off=off%60; if(off > 0) sb.append(":").append(off); if(zone.useDaylightTime()) - sb.append(zone.getDisplayName(true,TimeZone.SHORT)); + sb.append(Platform.timeZoneGetDisplayName(zone,true,false)); return sb.toString(); } @@ -92,7 +92,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { synchronized(parent.children) { int i = parent.activeChildren.indexOf(prev); if(i == -1) throw new Error("should never happen"); - parent.activeChildren.set(i,this); + parent.activeChildren.setElementAt(this,i); } } else { int newpid = -1; @@ -107,7 +107,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { } } - int _syscall(int syscall, int a, int b, int c, int d) throws ErrnoException, FaultException { + int _syscall(int syscall, int a, int b, int c, int d, int e, int f) throws ErrnoException, FaultException { switch(syscall) { case SYS_kill: return sys_kill(a,b); case SYS_fork: return sys_fork(); @@ -124,8 +124,18 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { case SYS_getdents: return sys_getdents(a,b,c,d); case SYS_unlink: return sys_unlink(a); case SYS_getppid: return sys_getppid(); + case SYS_socket: return sys_socket(a,b,c); + case SYS_connect: return sys_connect(a,b,c); + case SYS_resolve_hostname: return sys_resolve_hostname(a,b,c); + case SYS_setsockopt: return sys_setsockopt(a,b,c,d,e); + case SYS_getsockopt: return sys_getsockopt(a,b,c,d,e); + case SYS_bind: return sys_bind(a,b,c); + case SYS_listen: return sys_listen(a,b); + case SYS_accept: return sys_accept(a,b,c); + case SYS_shutdown: return sys_shutdown(a,b); + case SYS_sysctl: return sys_sysctl(a,b,c,d,e,f); - default: return super._syscall(syscall,a,b,c,d); + default: return super._syscall(syscall,a,b,c,d,e,f); } } @@ -160,7 +170,8 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { case 28: // SIGWINCH break; default: - return syscall(SYS_exit,128+signal,0,0,0); + // FEATURE: This is ugly, make a clean interface to sys_exit + return syscall(SYS_exit,128+signal,0,0,0,0,0); } return 0; } @@ -182,12 +193,15 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { synchronized(children) { for(;;) { if(pid == -1) { - if(exitedChildren.size() > 0) done = (UnixRuntime)exitedChildren.remove(exitedChildren.size() - 1); + if(exitedChildren.size() > 0) { + done = (UnixRuntime)exitedChildren.elementAt(exitedChildren.size() - 1); + exitedChildren.removeElementAt(exitedChildren.size() - 1); + } } else if(pid > 0) { UnixRuntime t = gs.tasks[pid]; if(t.parent != this) return -ECHILD; if(t.state == EXITED) { - if(!exitedChildren.remove(t)) throw new Error("should never happen"); + if(!exitedChildren.removeElement(t)) throw new Error("should never happen"); done = t; } } else { @@ -215,12 +229,12 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { UnixRuntime child = (UnixRuntime) e.nextElement(); gs.tasks[child.pid] = null; } - exitedChildren.clear(); + exitedChildren.removeAllElements(); for(Enumeration e = activeChildren.elements(); e.hasMoreElements(); ) { UnixRuntime child = (UnixRuntime) e.nextElement(); child.parent = null; } - activeChildren.clear(); + activeChildren.removeAllElements(); } UnixRuntime _parent = parent; @@ -231,8 +245,8 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { if(parent == null) { gs.tasks[pid] = null; } else { - if(!parent.activeChildren.remove(this)) throw new Error("should never happen _exited: pid: " + pid); - parent.exitedChildren.add(this); + if(!parent.activeChildren.removeElement(this)) throw new Error("should never happen _exited: pid: " + pid); + parent.exitedChildren.addElement(this); parent.children.notify(); } } @@ -275,7 +289,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { activeChildren = new Vector(); exitedChildren = new Vector(); } - activeChildren.add(r); + activeChildren.addElement(r); state.r[V0] = 0; // return 0 to child state.pc += 4; // skip over syscall instruction @@ -502,10 +516,10 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { private int sys_chdir(int addr) throws ErrnoException, FaultException { String path = normalizePath(cstring(addr)); - //System.err.println("Chdir: " + cstring(addr) + " -> " + path + " pwd: " + cwd); - if(gs.stat(this,path).type() != FStat.S_IFDIR) return -ENOTDIR; + FStat st = gs.stat(this,path); + if(st == null) return -ENOENT; + if(st.type() != FStat.S_IFDIR) return -ENOTDIR; cwd = path; - //System.err.println("Now: [" + cwd + "]"); return 0; } @@ -519,6 +533,435 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { return n; } + // FIXME: UDP is totally broken + + 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; + Object o; + InetAddress bindAddr; + int bindPort = -1; + DatagramPacket dp; + InputStream is; + OutputStream os; + + public SocketFD(int type) { flags = type; } + + public void setOptions() { + try { + if(o != null && type() == TYPE_STREAM && !listen()) { + Platform.socketSetKeepAlive((Socket)o,(options & SO_KEEPALIVE) != 0); + } + } catch(SocketException e) { + if(STDERR_DIAG) e.printStackTrace(); + } + } + + public void _close() { + if(o != null) { + try { + if(type() == TYPE_STREAM) { + if(listen()) ((ServerSocket)o).close(); + else ((Socket)o).close(); + } else { + ((DatagramSocket)o).close(); + } + } catch(IOException e) { + /* ignore */ + } + } + } + + public int read(byte[] a, int off, int length) throws ErrnoException { + if(type() == TYPE_STREAM) { + 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); + } + } else { + if(off != 0) throw new IllegalArgumentException("off must be 0"); + DatagramSocket ds = (DatagramSocket) o; + dp.setData(a); + dp.setLength(length); + try { + ds.receive(dp); + } catch(IOException e) { + throw new ErrnoException(EIO); + } + return dp.getLength(); + } + } + + public int write(byte[] a, int off, int length) throws ErrnoException { + if(type() == TYPE_STREAM) { + if(os == null) throw new ErrnoException(EPIPE); + try { + os.write(a,off,length); + return length; + } catch(IOException e) { + throw new ErrnoException(EIO); + } + } else { + if(off != 0) throw new IllegalArgumentException("off must be 0"); + DatagramSocket ds = (DatagramSocket) o; + dp.setData(a); + dp.setLength(length); + try { + ds.send(dp); + } catch(IOException e) { + throw new ErrnoException(EIO); + } + return dp.getLength(); + } + } + + // FEATURE: Check that these are correct + public int flags() { + if(is != null && os != null) return O_RDWR; + if(is != null) return O_RDONLY; + if(os != null) return O_WRONLY; + return 0; + } + + // FEATURE: Populate this properly + public FStat _fstat() { return new FStat(); } + } + + private int sys_socket(int domain, int type, int proto) { + if(domain != AF_INET || (type != SOCK_STREAM && type != SOCK_DGRAM)) return -EPROTONOSUPPORT; + return addFD(new SocketFD(type == SOCK_STREAM ? SocketFD.TYPE_STREAM : SocketFD.TYPE_DGRAM)); + } + + private SocketFD getSocketFD(int fdn) throws ErrnoException { + if(fdn < 0 || fdn >= OPEN_MAX) throw new ErrnoException(EBADFD); + if(fds[fdn] == null) throw new ErrnoException(EBADFD); + if(!(fds[fdn] instanceof SocketFD)) throw new ErrnoException(ENOTSOCK); + + return (SocketFD) fds[fdn]; + } + + private int sys_connect(int fdn, int addr, int namelen) throws ErrnoException, FaultException { + SocketFD fd = getSocketFD(fdn); + + if(fd.type() == SocketFD.TYPE_STREAM && fd.o != null) return -EISCONN; + int word1 = memRead(addr); + if( ((word1 >>> 16)&0xff) != AF_INET) return -EAFNOSUPPORT; + int port = word1 & 0xffff; + byte[] ip = new byte[4]; + copyin(addr+4,ip,4); + + InetAddress inetAddr; + try { + inetAddr = Platform.inetAddressFromBytes(ip); + } catch(UnknownHostException e) { + return -EADDRNOTAVAIL; + } + + try { + switch(fd.type()) { + case SocketFD.TYPE_STREAM: { + Socket s = new Socket(inetAddr,port); + fd.o = s; + fd.setOptions(); + fd.is = s.getInputStream(); + fd.os = s.getOutputStream(); + break; + } + case SocketFD.TYPE_DGRAM: { + if(fd.dp == null) fd.dp = new DatagramPacket(null,0); + fd.dp.setAddress(inetAddr); + fd.dp.setPort(port); + break; + } + default: + throw new Error("should never happen"); + } + } catch(IOException e) { + return -ECONNREFUSED; + } + + return 0; + } + + private int sys_resolve_hostname(int chostname, int addr, int sizeAddr) throws FaultException { + String hostname = cstring(chostname); + int size = memRead(sizeAddr); + InetAddress[] inetAddrs; + try { + inetAddrs = InetAddress.getAllByName(hostname); + } catch(UnknownHostException e) { + return HOST_NOT_FOUND; + } + int count = min(size/4,inetAddrs.length); + for(int i=0;i>> 16)&0xff) != AF_INET) return -EAFNOSUPPORT; + int port = word1 & 0xffff; + InetAddress inetAddr = null; + if(memRead(addr+4) != 0) { + byte[] ip = new byte[4]; + copyin(addr+4,ip,4); + + try { + inetAddr = Platform.inetAddressFromBytes(ip); + } catch(UnknownHostException e) { + return -EADDRNOTAVAIL; + } + } + + switch(fd.type()) { + case SocketFD.TYPE_STREAM: { + fd.bindAddr = inetAddr; + fd.bindPort = port; + return 0; + } + case SocketFD.TYPE_DGRAM: { + DatagramSocket s = (DatagramSocket) fd.o; + if(s != null) s.close(); + try { + fd.o = inetAddr != null ? new DatagramSocket(port,inetAddr) : new DatagramSocket(port); + } catch(IOException e) { + return -EADDRINUSE; + } + return 0; + } + default: + throw new Error("should never happen"); + } + } + + private int sys_listen(int fdn, int backlog) throws ErrnoException { + SocketFD fd = getSocketFD(fdn); + if(fd.type() != SocketFD.TYPE_STREAM) return -EOPNOTSUPP; + if(fd.o != null) return -EISCONN; + if(fd.bindPort < 0) return -EOPNOTSUPP; + + try { + fd.o = new ServerSocket(fd.bindPort,backlog,fd.bindAddr); + fd.flags |= SocketFD.LISTEN; + return 0; + } catch(IOException e) { + return -EADDRINUSE; + } + + } + + private int sys_accept(int fdn, int addr, int lenaddr) throws ErrnoException, FaultException { + SocketFD fd = getSocketFD(fdn); + if(fd.type() != SocketFD.TYPE_STREAM) return -EOPNOTSUPP; + if(!fd.listen()) return -EOPNOTSUPP; + + int size = memRead(lenaddr); + + ServerSocket s = (ServerSocket) fd.o; + Socket client; + try { + client = s.accept(); + } catch(IOException e) { + return -EIO; + } + + if(size >= 8) { + memWrite(addr,(6 << 24) | (AF_INET << 16) | client.getPort()); + byte[] b = client.getInetAddress().getAddress(); + copyout(b,addr+4,4); + memWrite(lenaddr,8); + } + + SocketFD clientFD = new SocketFD(SocketFD.TYPE_STREAM); + clientFD.o = client; + try { + clientFD.is = client.getInputStream(); + clientFD.os = client.getOutputStream(); + } catch(IOException e) { + return -EIO; + } + int n = addFD(clientFD); + if(n == -1) { clientFD.close(); return -ENFILE; } + return n; + } + + private int sys_shutdown(int fdn, int how) throws ErrnoException { + SocketFD fd = getSocketFD(fdn); + if(fd.type() != SocketFD.TYPE_STREAM || fd.listen()) return -EOPNOTSUPP; + if(fd.o == null) return -ENOTCONN; + + Socket s = (Socket) fd.o; + + try { + if(how == SHUT_RD || how == SHUT_RDWR) Platform.socketHalfClose(s,false); + if(how == SHUT_WR || how == SHUT_RDWR) Platform.socketHalfClose(s,true); + } catch(IOException e) { + return -EIO; + } + + return 0; + } + + private static String hostName() { + try { + return InetAddress.getLocalHost().getHostName(); + } catch(UnknownHostException e) { + return "darkstar"; + } + } + + private int sys_sysctl(int nameaddr, int namelen, int oldp, int oldlenaddr, int newp, int newlen) throws FaultException { + if(newp != 0) return -EPERM; + if(namelen == 0) return -ENOENT; + if(oldp == 0) return 0; + + Object o = null; + switch(memRead(nameaddr)) { + case CTL_KERN: + if(namelen != 2) break; + switch(memRead(nameaddr+4)) { + case KERN_OSTYPE: o = "NestedVM"; break; + case KERN_HOSTNAME: o = hostName(); break; + case KERN_OSRELEASE: o = VERSION; break; + case KERN_VERSION: o = "NestedVM Kernel Version " + VERSION; break; + } + break; + case CTL_HW: + if(namelen != 2) break; + switch(memRead(nameaddr+4)) { + case HW_MACHINE: o = "NestedVM Virtual Machine"; break; + } + break; + } + if(o == null) return -ENOENT; + int len = memRead(oldlenaddr); + if(o instanceof String) { + byte[] b = getNullTerminatedBytes((String)o); + if(len < b.length) return -ENOMEM; + len = b.length; + copyout(b,oldp,len); + memWrite(oldlenaddr,len); + } else if(o instanceof Integer) { + if(len < 4) return -ENOMEM; + memWrite(oldp,((Integer)o).intValue()); + } else { + throw new Error("should never happen"); + } + return 0; + } + + + /*public int sys_opensocket(int cstring, int port) throws FaultException, ErrnoException { + String hostname = cstring(cstring); + try { + FD fd = new SocketFD(new Socket(hostname,port)); + int n = addFD(fd); + if(n == -1) fd.close(); + return n; + } catch(IOException e) { + return -EIO; + } + } + + private static class ListenSocketFD extends FD { + ServerSocket s; + public ListenSocketFD(ServerSocket s) { this.s = s; } + public int flags() { return 0; } + // FEATURE: What should these be? + public FStat _fstat() { return new FStat(); } + public void _close() { try { s.close(); } catch(IOException e) { } } + } + + public int sys_listensocket(int port) { + try { + ListenSocketFD fd = new ListenSocketFD(new ServerSocket(port)); + int n = addFD(fd); + if(n == -1) fd.close(); + return n; + } catch(IOException e) { + return -EIO; + } + } + + public int sys_accept(int fdn) { + if(fdn < 0 || fdn >= OPEN_MAX) return -EBADFD; + if(fds[fdn] == null) return -EBADFD; + if(!(fds[fdn] instanceof ListenSocketFD)) return -EBADFD; + try { + ServerSocket s = ((ListenSocketFD)fds[fdn]).s; + SocketFD fd = new SocketFD(s.accept()); + int n = addFD(fd); + if(n == -1) fd.close(); + return n; + } catch(IOException e) { + return -EIO; + } + }*/ + // FEATURE: Run through the fork/wait stuff one more time public static class GlobalState { protected static final int OPEN = 1; @@ -543,7 +986,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { } } - private static class MP { + private static class MP implements Sort.Comparable { public MP(String path, FS fs) { this.path = path; this.fs = fs; } public String path; public FS fs; @@ -575,7 +1018,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { MP[] newMPS = new MP[oldLength + 1]; if(oldLength != 0) System.arraycopy(mps,0,newMPS,0,oldLength); newMPS[oldLength] = new MP(path,fs); - Arrays.sort(newMPS); + Sort.sort(newMPS); mps = newMPS; int highdevno = 0; for(int i=0;i