X-Git-Url: http://git.megacz.com/?p=nestedvm.git;a=blobdiff_plain;f=src%2Forg%2Fibex%2Fnestedvm%2FUnixRuntime.java;h=4c9ed5ab5a12ae6a9bbcf43ad8fd7434b7fe45b6;hp=2b32965eeee982aab2fe03bd94aeb3a64e801d45;hb=37a9506df9dab17552c6c34b62dc4295504b6c8c;hpb=7ee9c4231f8e74adfde9679bc60783a715f69c2a diff --git a/src/org/ibex/nestedvm/UnixRuntime.java b/src/org/ibex/nestedvm/UnixRuntime.java index 2b32965..4c9ed5a 100644 --- a/src/org/ibex/nestedvm/UnixRuntime.java +++ b/src/org/ibex/nestedvm/UnixRuntime.java @@ -3,8 +3,7 @@ package org.ibex.nestedvm; import org.ibex.nestedvm.util.*; import java.io.*; import java.util.*; -import java.net.Socket; -import java.net.ServerSocket; +import java.net.*; // FEATURE: vfork @@ -109,7 +108,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(); @@ -126,11 +125,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_opensocket: return sys_opensocket(a,b); - case SYS_listensocket: return sys_listensocket(a); - case SYS_accept: return sys_accept(a); + 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); } } @@ -165,7 +171,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; } @@ -524,18 +531,383 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { return n; } - private static class SocketFD extends InputOutputStreamFD { - private final Socket s; + 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; } - public SocketFD(Socket s) throws IOException { - super(s.getInputStream(),s.getOutputStream()); - this.s = s; + 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()) { + ((Socket)o).setKeepAlive((options & SO_KEEPALIVE) != 0); + } + } catch(SocketException e) { + if(STDERR_DIAG) e.printStackTrace(); + } } - public void _close() { try { s.close(); } catch(IOException e) { } } + 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 { + DatagramSocket ds = (DatagramSocket) o; + dp.setData(a,off,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 { + DatagramSocket ds = (DatagramSocket) o; + dp.setData(a,off,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 = InetAddress.getByAddress(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: { + DatagramSocket s = (DatagramSocket) fd.o; + if(s == null) s = new DatagramSocket(); + s.connect(inetAddr,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 = InetAddress.getByAddress(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) s.shutdownInput(); + if(how == SHUT_WR || how == SHUT_RDWR) s.shutdownOutput(); + } 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)); @@ -580,7 +952,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { } catch(IOException e) { return -EIO; } - } + }*/ // FEATURE: Run through the fork/wait stuff one more time public static class GlobalState { @@ -926,6 +1298,8 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { public FD open(UnixRuntime r, String path, int flags, int mode) throws ErrnoException { + // FIXME: horrendous, ugly hack needed by TeX... sorry Brian... + path = path.trim(); final File f = hostFile(path); return r.hostFSOpen(f,flags,mode,this); }