From ec1fc787665e2b2964203c683f89f34222f97f43 Mon Sep 17 00:00:00 2001 From: Falco Duersch Date: Fri, 11 Jan 2019 12:27:30 +0100 Subject: [PATCH 1/9] Refactor socket plugin to NIO --- .../swa/graal/squeak/test/tests.properties | 131 +- .../squeak/nodes/plugins/SocketPlugin.java | 1151 ----------------- .../nodes/plugins/network/Resolver.java | 82 ++ .../nodes/plugins/network/SocketPlugin.java | 708 ++++++++++ .../nodes/plugins/network/SqSocket.java | 205 +++ .../nodes/plugins/network/TCPSocket.java | 208 +++ .../nodes/plugins/network/UDPSocket.java | 118 ++ .../primitives/PrimitiveNodeFactory.java | 2 +- 8 files changed, 1387 insertions(+), 1218 deletions(-) delete mode 100644 src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/SocketPlugin.java create mode 100644 src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/Resolver.java create mode 100644 src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SocketPlugin.java create mode 100644 src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SqSocket.java create mode 100644 src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/TCPSocket.java create mode 100644 src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/UDPSocket.java diff --git a/src/de.hpi.swa.graal.squeak.test/src/de/hpi/swa/graal/squeak/test/tests.properties b/src/de.hpi.swa.graal.squeak.test/src/de/hpi/swa/graal/squeak/test/tests.properties index 004c210a3..64aa44a12 100644 --- a/src/de.hpi.swa.graal.squeak.test/src/de/hpi/swa/graal/squeak/test/tests.properties +++ b/src/de.hpi.swa.graal.squeak.test/src/de/hpi/swa/graal/squeak/test/tests.properties @@ -28,7 +28,7 @@ AllocationTest>>testOneGigAllocation=passing AllocationTest>>testOneMegAllocation=passing AllocationTest>>testOutOfMemorySignal=ignored AppRegistryTest>>test01AppsAreBehaviors=passing -ArbitraryObjectSocketTestCase>>testBasics=failing +ArbitraryObjectSocketTestCase>>testBasics=passing ArrayLiteralTest>>testReservedIdentifiers=passing ArrayLiteralTest>>testSymbols=passing ArrayTest>>testAtWrap=passing @@ -3550,54 +3550,60 @@ SmartRefStreamTest>>testLargeIntergers=passing SmartRefStreamTest>>testNotTooLargeIntergers=passing SmartRefStreamTest>>testSmallInteger=passing SMTPClientTest>>testMailFrom=passing -SocketStreamTest>>testClassComment=ignored -SocketStreamTest>>testCoverage=ignored -SocketStreamTest>>testNew=ignored -SocketStreamTest>>testNextIntoClose=ignored -SocketStreamTest>>testNextIntoCloseNonSignaling=ignored -SocketStreamTest>>testUnCategorizedMethods=ignored -SocketStreamTest>>testUpTo=ignored -SocketStreamTest>>testUpToAfterCloseNonSignaling=ignored -SocketStreamTest>>testUpToAfterCloseSignaling=ignored -SocketStreamTest>>testUpToAll=ignored -SocketStreamTest>>testUpToAllAfterCloseNonSignaling=ignored -SocketStreamTest>>testUpToAllAfterCloseSignaling=ignored -SocketStreamTest>>testUpToAllAsciiVsBinary=ignored -SocketStreamTest>>testUpToAllCrlfAscii=ignored -SocketStreamTest>>testUpToAllCrlfBinary=ignored -SocketStreamTest>>testUpToAllCrlfCrlfAscii=ignored -SocketStreamTest>>testUpToAllCrlfCrlfBinary=ignored -SocketStreamTest>>testUpToAllEmptyPatternAscii=ignored -SocketStreamTest>>testUpToAllEmptyPatternBinary=ignored -SocketStreamTest>>testUpToAllLimit=ignored -SocketStreamTest>>testUpToAllLongPatternAscii=ignored -SocketStreamTest>>testUpToAllLongPatternBinary=ignored -SocketStreamTest>>testUpToAllMediumPatternAscii=ignored -SocketStreamTest>>testUpToAllMediumPatternBinary=ignored -SocketStreamTest>>testUpToAllShortPatternAscii=ignored -SocketStreamTest>>testUpToAllShortPatternAscii2=ignored -SocketStreamTest>>testUpToAllShortPatternBinary=ignored -SocketStreamTest>>testUpToAllShortPatternBinary2=ignored -SocketStreamTest>>testUpToAllTimeout=ignored -SocketStreamTest>>testUpToAsciiVsBinary=ignored -SocketStreamTest>>testUpToEndClose=ignored -SocketStreamTest>>testUpToEndCloseNonSignaling=ignored -SocketStreamTest>>testUpToMax=ignored -SocketStreamTest>>testUpToTimeout=ignored -SocketTest>>testClientConnect=ignored -SocketTest>>testDataReceive=ignored -SocketTest>>testDataSending=ignored -SocketTest>>testLocalAddress=ignored -SocketTest>>testLocalPort=ignored -SocketTest>>testPeerName=ignored -SocketTest>>testReceiveTimeout=ignored -SocketTest>>testRemoteAddress=ignored -SocketTest>>testRemotePort=ignored -SocketTest>>testSendTimeout=ignored -SocketTest>>testServerAccept=ignored +SocketStreamTest>>testClassComment=passing +SocketStreamTest>>testCoverage=passing +SocketStreamTest>>testNew=passing +SocketStreamTest>>testNextIntoClose=passing +SocketStreamTest>>testNextIntoCloseNonSignaling=passing +SocketStreamTest>>testUnCategorizedMethods=passing +SocketStreamTest>>testUpTo=passing +SocketStreamTest>>testUpToAfterCloseNonSignaling=passing +SocketStreamTest>>testUpToAfterCloseSignaling=passing +SocketStreamTest>>testUpToAll=passing +SocketStreamTest>>testUpToAllAfterCloseNonSignaling=passing +SocketStreamTest>>testUpToAllAfterCloseSignaling=passing +SocketStreamTest>>testUpToAllAsciiVsBinary=passing +SocketStreamTest>>testUpToAllCrlfAscii=passing +SocketStreamTest>>testUpToAllCrlfBinary=passing +SocketStreamTest>>testUpToAllCrlfCrlfAscii=passing +SocketStreamTest>>testUpToAllCrlfCrlfBinary=passing +SocketStreamTest>>testUpToAllEmptyPatternAscii=passing +SocketStreamTest>>testUpToAllEmptyPatternBinary=passing +SocketStreamTest>>testUpToAllLimit=passing +SocketStreamTest>>testUpToAllLongPatternAscii=passing +SocketStreamTest>>testUpToAllLongPatternBinary=passing +SocketStreamTest>>testUpToAllMediumPatternAscii=passing +SocketStreamTest>>testUpToAllMediumPatternBinary=passing +SocketStreamTest>>testUpToAllShortPatternAscii=passing +SocketStreamTest>>testUpToAllShortPatternAscii2=passing +SocketStreamTest>>testUpToAllShortPatternBinary=passing +SocketStreamTest>>testUpToAllShortPatternBinary2=passing +SocketStreamTest>>testUpToAllTimeout=passing +SocketStreamTest>>testUpToAsciiVsBinary=passing +SocketStreamTest>>testUpToEndClose=passing +SocketStreamTest>>testUpToEndCloseNonSignaling=passing +SocketStreamTest>>testUpToMax=passing +SocketStreamTest>>testUpToTimeout=passing +SocketTest>>testClientConnect=passing +SocketTest>>testDataReceive=passing +SocketTest>>testDataSending=passing +SocketTest>>testLocalAddress=passing +SocketTest>>testLocalPort=passing +SocketTest>>testPeerName=passing +SocketTest>>testReceiveTimeout=passing +SocketTest>>testRemoteAddress=passing +SocketTest>>testRemotePort=passing +SocketTest>>testSendTimeout=passing +SocketTest>>testServerAccept=passing + +# In principal, socket options are implemented. +# However, the purpose of test remainder (involving 2 UDP sockets) remains unclear and does not +# even pass on OSVM. Second, StandardSocketOptions#SO_REUSEPORT is only available in Java 9+, +# so test failures on JDK 8 are possible. SocketTest>>testSocketReuse=ignored -SocketTest>>testStringFromAddress=ignored -SocketTest>>testUDP=ignored + +SocketTest>>testStringFromAddress=passing +SocketTest>>testUDP=passing SortedCollectionTest>>testAdd=passing SortedCollectionTest>>testAddAll=passing SortedCollectionTest>>testAddAll2=passing @@ -3654,10 +3660,7 @@ SqNumberParserTest>>testScaledDecimalWithTrailingZeroes=passing SqNumberParserTest>>testUnCategorizedMethods=passing SqueakSSLTest>>testConnectAccept=passing SqueakSSLTest>>testEncryptDecrypt=passing - -# Broken test? I cannot figure out why failure is expected. -# self shouldnt: [ webClient httpGet: 'https://graph.facebook.com' ] -SqueakSSLTest>>testFaceBookAPI=broken_in_squeak +SqueakSSLTest>>testFaceBookAPI=passing # Broken test, or changed requirements from Google, and JDK dependent. # On JDK 11, the response indicates that SNI has to be used, however, the test does not supply the server name. @@ -3668,17 +3671,13 @@ SqueakSSLTest>>testGooglePopStream=broken_in_squeak SqueakSSLTest>>testMultiFrameDecrypt=passing SqueakSSLTest>>testSingleByteDecrypt=passing - -# may depend on socket plugin stability -SqueakSSLTest>>testSocketAccept=ignored -SqueakSSLTest>>testSocketConnect=ignored -SqueakSSLTest>>testSplitTlsFrameRead=ignored -SqueakSSLTest>>testSSLSockets=ignored - -SqueakSSLTest>>testStreamAccept=ignored -SqueakSSLTest>>testStreamConnect=ignored -SqueakSSLTest>>testStreamTransfer=ignored - +SqueakSSLTest>>testSocketAccept=passing +SqueakSSLTest>>testSocketConnect=passing +SqueakSSLTest>>testSplitTlsFrameRead=passing +SqueakSSLTest>>testSSLSockets=passing +SqueakSSLTest>>testStreamAccept=passing +SqueakSSLTest>>testStreamConnect=passing +SqueakSSLTest>>testStreamTransfer=passing ST80MenusTest>>testSupplyAnswerOfFillInTheBlank=passing ST80MenusTest>>testSupplySpecificAnswerToQuestion=passing ST80MenusTest>>testSuppressInform=passing @@ -3717,9 +3716,9 @@ StopwatchTest>>testReset=passing StopwatchTest>>testSingleTiming=passing StopwatchTest>>testStartStop=passing StopwatchTest>>testUnCategorizedMethods=passing -StringSocketTestCase>>testBasics=failing -StringSocketTestCase>>testBogusInput1=failing -StringSocketTestCase>>testBogusInput2=failing +StringSocketTestCase>>testBasics=passing +StringSocketTestCase>>testBogusInput1=passing +StringSocketTestCase>>testBogusInput2=passing StringTest>>testAsCamelCase=passing StringTest>>testAsDecomposedUnicode=passing StringTest>>testAsInteger=passing diff --git a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/SocketPlugin.java b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/SocketPlugin.java deleted file mode 100644 index 280033502..000000000 --- a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/SocketPlugin.java +++ /dev/null @@ -1,1151 +0,0 @@ -package de.hpi.swa.graal.squeak.nodes.plugins; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.DatagramPacket; -import java.net.DatagramSocket; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.SocketAddress; -import java.net.SocketException; -import java.net.UnknownHostException; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; - -import org.graalvm.collections.EconomicMap; - -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.api.dsl.GenerateNodeFactory; -import com.oracle.truffle.api.dsl.NodeFactory; -import com.oracle.truffle.api.dsl.Specialization; - -import de.hpi.swa.graal.squeak.exceptions.PrimitiveExceptions.PrimitiveFailed; -import de.hpi.swa.graal.squeak.exceptions.SqueakExceptions.SqueakException; -import de.hpi.swa.graal.squeak.model.AbstractSqueakObject; -import de.hpi.swa.graal.squeak.model.CompiledCodeObject; -import de.hpi.swa.graal.squeak.model.CompiledMethodObject; -import de.hpi.swa.graal.squeak.model.NativeObject; -import de.hpi.swa.graal.squeak.model.NotProvided; -import de.hpi.swa.graal.squeak.model.PointersObject; -import de.hpi.swa.graal.squeak.nodes.primitives.AbstractPrimitiveFactoryHolder; -import de.hpi.swa.graal.squeak.nodes.primitives.AbstractPrimitiveNode; -import de.hpi.swa.graal.squeak.nodes.primitives.PrimitiveInterfaces.BinaryPrimitive; -import de.hpi.swa.graal.squeak.nodes.primitives.PrimitiveInterfaces.QuaternaryPrimitive; -import de.hpi.swa.graal.squeak.nodes.primitives.PrimitiveInterfaces.QuinaryPrimitive; -import de.hpi.swa.graal.squeak.nodes.primitives.PrimitiveInterfaces.SenaryPrimitive; -import de.hpi.swa.graal.squeak.nodes.primitives.PrimitiveInterfaces.SeptenaryPrimitive; -import de.hpi.swa.graal.squeak.nodes.primitives.PrimitiveInterfaces.TernaryPrimitive; -import de.hpi.swa.graal.squeak.nodes.primitives.PrimitiveInterfaces.UnaryPrimitive; -import de.hpi.swa.graal.squeak.nodes.primitives.SqueakPrimitive; - -public final class SocketPlugin extends AbstractPrimitiveFactoryHolder { - - private static final EconomicMap sockets = EconomicMap.create(); - private static final boolean debugPrints = false; - - private static byte[] lastNameLookup; - private static String lastAddressLookup; - - @SuppressWarnings("unused") - private static final class ResolverStatus { - private static final long Uninitialized = 0; - private static final long Ready = 1; - private static final long Busy = 2; - private static final long Error = 3; - } - - private static final class SocketStatus { - private static final long InvalidSocket = -1; - private static final long Unconnected = 0; - private static final long WaitingForConnection = 1; - private static final long Connected = 2; - private static final long OtherEndClosed = 3; - private static final long ThisEndClosed = 4; - } - - private static final class SocketType { - private static final long TCPSocketType = 0; - private static final long UDPSocketType = 1; - } - - private static final class Resolver { - @SuppressWarnings("unused") - public static byte[] getLocalAddress() throws UnknownHostException { - return new byte[]{127, 0, 0, 1}; - } - - public static InetAddress getLocalHostInetAddress() throws IOException { - return InetAddress.getByAddress(Resolver.getLocalAddress()); - } - } - - private static final class SocketImpl { - @CompilationFinal private static int timeoutMillis = -1; - - private final CompiledCodeObject code; - private final int id; - - private final long socketType; - private Socket clientSocket; - private ServerSocket serverSocket; - private DatagramSocket datagramSocket; - private Socket acceptedConnection; - - private Map options = new TreeMap<>(); - private boolean listening = false; - private long noDataSince = -1; - - SocketImpl(final CompiledCodeObject code, final long netType) { - this.code = code; - this.id = this.hashCode(); - this.socketType = netType; - if (this.socketType == SocketType.TCPSocketType) { - print(">> Creating TCP Socket"); - } else { - print(">> Creating UDP Socket"); - } - } - - private int getTimeout() { - if (timeoutMillis < 0) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - // Use shorter timeout to speed up testing. - timeoutMillis = code.image.isTesting() ? 2000 : 30000; - } - return timeoutMillis; - } - - public void print(final Object message) { - if (debugPrints) { - code.image.printToStdOut(id, ":", message); - } - } - - public void error(final Object message) { - code.image.printToStdErr(id, ":", message); - } - - @TruffleBoundary - public void listenOn(final int port) throws IOException { - if (listening) { - return; - } - print(">> Listening on " + port); - - if (socketType == SocketType.UDPSocketType) { - listening = true; - datagramSocket = new DatagramSocket(port); - } else { - serverSocket = new ServerSocket(port, 1, Resolver.getLocalHostInetAddress()); - print(">> Actually listening on " + Resolver.getLocalHostInetAddress() + ":" + serverSocket.getLocalPort()); - final SocketImpl self = this; - final Thread listenerThread = new Thread() { - @Override - public void run() { - listening = true; - try { - while (serverSocket != null) { - acceptedConnection = serverSocket.accept(); - } - } catch (SocketException se) { - // The socket has been closed while listening - // This is fine - listening = false; - print(">> Stopped listening"); - } catch (IOException e) { - self.error(e); - } - } - }; - listenerThread.start(); - } - } - - @TruffleBoundary - public SocketImpl accept() throws IOException { - print(">> Accepting"); - final SocketImpl connectionImpl = new SocketImpl(code, SocketType.TCPSocketType); - if (acceptedConnection == null) { - error("No connection was accepted"); - throw new IOException("No connection was accepted"); - } - - connectionImpl.clientSocket = acceptedConnection; - acceptedConnection = null; - return connectionImpl; - } - - @TruffleBoundary - public void connectTo(final String host, final long port) throws IOException { - print(">> Connecting to " + host + ":" + port); - if (socketType == SocketType.TCPSocketType) { - if (clientSocket != null) { - clientSocket.close(); - } - // clientSocket = new Socket(host, (int) port, - // Resolver.getLocalHostInetAddress(), 0); - clientSocket = new Socket(host, (int) port); - } else /* if (netType == SocketType.UDPSocketType) */ { - if (datagramSocket != null) { - datagramSocket.close(); - } - this.datagramSocket = new DatagramSocket(); - this.datagramSocket.connect(InetAddress.getByName(host), (int) port); - } - } - - @TruffleBoundary - public boolean isDataAvailable() throws IOException { - boolean available = false; - if (clientSocket != null) { - if (!clientSocket.isClosed() || clientSocket.isConnected()) { - final InputStream inputStream = clientSocket.getInputStream(); - if (inputStream != null) { - available = inputStream.available() > 0; - } - } - } else if (datagramSocket != null) { - return true; - // TODO - } - print(">> Data available: " + available); - return available; - } - - @TruffleBoundary - public int receiveData(final byte[] data, final int startIndex, final int count) throws IOException { - print(">> Receive data, buffer length: " + data.length + ", start: " + startIndex + ", count: " + count); - final int actualCount = count; - if (clientSocket != null) { - if (isDataAvailable()) { - final int bytesRead = clientSocket.getInputStream().read(data, startIndex, actualCount); - print(">> Bytes read: " + bytesRead); - return bytesRead >= 0 ? bytesRead : 0; - } else { - print(">> No data available"); - return 0; - } - } else if (datagramSocket != null) { - final DatagramPacket p = new DatagramPacket(data, startIndex, actualCount); - datagramSocket.receive(p); - return p.getLength(); - } else { - throw new IOException("Socket not connected!"); - } - } - - @TruffleBoundary - public void sendData(final byte[] data, final int startIndex, final int count) throws IOException { - print(">> Send Data"); - if (clientSocket != null) { - if (!clientSocket.isConnected()) { - throw new IOException("Client socket is not connected!"); - } - final OutputStream outputStream = clientSocket.getOutputStream(); - outputStream.write(data, startIndex, count); - outputStream.flush(); - } else if (datagramSocket != null) { - if (!datagramSocket.isConnected()) { - throw new IOException("Datagram socket is not connected!"); - } - print("Send to " + datagramSocket.getRemoteSocketAddress()); - final DatagramPacket p = new DatagramPacket(data, startIndex, count); - this.datagramSocket.send(p); - } else { - throw new IOException("Not Connected!"); - } - } - - @TruffleBoundary - public void close() throws IOException { - print(">> Closing"); - if (clientSocket != null) { - clientSocket.close(); - clientSocket = null; - } - if (serverSocket != null) { - serverSocket.close(); - serverSocket = null; - } - if (datagramSocket != null) { - datagramSocket.close(); - datagramSocket = null; - } - } - - @TruffleBoundary - public long getStatus() throws IOException { - long status = SocketStatus.Unconnected; - - if (clientSocket == null && serverSocket == null && datagramSocket == null) { - status = SocketStatus.Unconnected; - } - - if (serverSocket != null) { - if (listening && acceptedConnection == null) { - status = SocketStatus.WaitingForConnection; - } else if (acceptedConnection != null) { - status = SocketStatus.Connected; - } else if (!listening) { - status = SocketStatus.Unconnected; - } else { - throw new IOException("Undefined Socket Status"); - } - } - - if (clientSocket != null) { - if (clientSocket.isInputShutdown()) { - status = SocketStatus.ThisEndClosed; - } else if (clientSocket.isOutputShutdown()) { - status = SocketStatus.OtherEndClosed; - } else if (!clientSocket.isConnected()) { - status = SocketStatus.Unconnected; - } else if (clientSocket.isClosed()) { - status = SocketStatus.ThisEndClosed; - } else { - try { - if (clientSocket.getInputStream().available() > 0) { - status = SocketStatus.Connected; - } else { - if (noDataSince < 0) { - noDataSince = System.currentTimeMillis(); - status = SocketStatus.Connected; - } else { - if (System.currentTimeMillis() - noDataSince > getTimeout()) { - status = SocketStatus.OtherEndClosed; - } else { - status = SocketStatus.Connected; - } - } - } - } catch (IOException e) { - error(e); - status = SocketStatus.Unconnected; - } - } - } - - if (datagramSocket != null) { - if (listening) { - status = SocketStatus.WaitingForConnection; - } else if (datagramSocket.isConnected()) { - status = SocketStatus.Connected; - } else { - status = SocketStatus.Unconnected; - } - } - - String statusString = "Undefined"; - - if (status == SocketStatus.Connected) { - statusString = "Connected"; - } else if (status == SocketStatus.InvalidSocket) { - statusString = "InvalidSocket"; - } else if (status == SocketStatus.Unconnected) { - statusString = "Unconnected"; - } else if (status == SocketStatus.WaitingForConnection) { - statusString = "WaitingForConnection"; - } else if (status == SocketStatus.OtherEndClosed) { - statusString = "OtherEndClosed"; - } else if (status == SocketStatus.ThisEndClosed) { - statusString = "ThisEndClosed"; - } - - print(">> SocketStatus: " + statusString); - return status; - } - - @SuppressWarnings("static-method") - public long getError() { - return 0L; - } - - @TruffleBoundary - public byte[] getRemoteAddress() { - if (clientSocket != null) { - final SocketAddress socketAddress = clientSocket.getRemoteSocketAddress(); - if (socketAddress instanceof InetSocketAddress) { - final InetSocketAddress inetAddress = (InetSocketAddress) socketAddress; - return inetAddress.getAddress().getAddress(); - } else { - throw new SqueakException("Could not retrieve remote address"); - } - } else if (serverSocket != null) { - return new byte[]{0, 0, 0, 0}; - } else if (datagramSocket != null) { - final SocketAddress socketAddress = datagramSocket.getRemoteSocketAddress(); - if (socketAddress instanceof InetSocketAddress) { - final InetSocketAddress inetAddress = (InetSocketAddress) socketAddress; - return inetAddress.getAddress().getAddress(); - } else { - throw new SqueakException("Could not retrieve remote address"); - } - } else { - return new byte[]{0, 0, 0, 0}; - } - } - - @TruffleBoundary - public long getRemotePort() { - if (clientSocket != null) { - final InetSocketAddress address = (InetSocketAddress) clientSocket.getRemoteSocketAddress(); - if (address != null) { - return address.getPort(); - } else { - return 0L; - } - } else if (datagramSocket != null) { - final InetSocketAddress address = (InetSocketAddress) datagramSocket.getRemoteSocketAddress(); - if (address != null) { - return address.getPort(); - } else { - return 0L; - } - } else { - return 0L; - } - } - - @TruffleBoundary - public Object getLocalAddress() throws UnknownHostException { - byte[] address; - if (clientSocket != null) { - address = clientSocket.getLocalAddress().getAddress(); - } else if (serverSocket != null) { - final SocketAddress socketAddress = serverSocket.getLocalSocketAddress(); - if (socketAddress instanceof InetSocketAddress) { - address = ((InetSocketAddress) socketAddress).getAddress().getAddress(); - } else { - print(">> Socket local address: 0"); - return 0; - } - } else if (datagramSocket != null) { - address = datagramSocket.getLocalAddress().getAddress(); - } else { - print(">> Socket local address: 0"); - return 0; - } - if (address[0] == 0 && address[1] == 0 && address[2] == 0 && address[3] == 0) { - address = Resolver.getLocalAddress(); - } - print(">> Socket local address: " + addressBytesToString(address)); - return address; - - } - - @TruffleBoundary - public Object getOption(final String option) { - return options.get(option); - } - - @TruffleBoundary - public void setOption(final String option, final Object value) { - options.put(option, value); - } - - @TruffleBoundary - public int getLocalPort() { - int localPort = 0; - if (clientSocket != null) { - localPort = clientSocket.getLocalPort(); - } else if (serverSocket != null) { - localPort = serverSocket.getLocalPort(); - } else if (datagramSocket != null) { - localPort = datagramSocket.getLocalPort(); - } - - print(">> Local port: " + localPort); - return localPort; - } - - public boolean isSendDone() { - print(">> Send Done: true"); - return true; - } - } - - public static String addressBytesToString(final byte[] address) throws UnknownHostException { - return InetAddress.getByAddress(address).getHostAddress(); - } - - protected abstract static class AbstractSocketPluginPrimitiveNode extends AbstractPrimitiveNode { - - protected AbstractSocketPluginPrimitiveNode(final CompiledMethodObject method) { - super(method); - } - - protected final void error(final Object o) { - code.image.printToStdErr(o); - } - - protected final void print(final Object o) { - if (debugPrints) { - code.image.printToStdOut(o); - } - } - } - - @GenerateNodeFactory - @SqueakPrimitive(names = "primitiveResolverStatus") - protected abstract static class PrimResolverStatusNode extends AbstractSocketPluginPrimitiveNode implements UnaryPrimitive { - protected PrimResolverStatusNode(final CompiledMethodObject method) { - super(method); - } - - @Specialization - protected static final long doWork(@SuppressWarnings("unused") final AbstractSqueakObject receiver) { - return ResolverStatus.Ready; - } - } - - @GenerateNodeFactory - @SqueakPrimitive(names = "primitiveInitializeNetwork") - protected abstract static class PrimInitializeNetworkNode extends AbstractSocketPluginPrimitiveNode implements UnaryPrimitive { - protected PrimInitializeNetworkNode(final CompiledMethodObject method) { - super(method); - } - - @Specialization - protected static final Object doWork(final AbstractSqueakObject receiver) { - return receiver; - } - } - - @TruffleBoundary - private static SocketImpl getSocketImplOrPrimFail(final long socketHandle) { - final SocketImpl socketImpl = sockets.get(socketHandle); - if (socketImpl == null) { - throw new PrimitiveFailed(); - } - return socketImpl; - } - - @GenerateNodeFactory - @SqueakPrimitive(names = "primitiveResolverStartNameLookup") - protected abstract static class PrimResolverStartNameLookupNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { - protected PrimResolverStartNameLookupNode(final CompiledMethodObject method) { - super(method); - } - - // Look up the given host name in the Domain Name Server to find its address. This call - // is - // asynchronous. To get the results, wait for it to complete or time out and then use - // primNameLookupResult. - @Specialization(guards = "hostName.isByteType()") - @TruffleBoundary - protected final Object doWork(final Object receiver, final NativeObject hostName) { - print(">> Starting lookup for host name " + hostName); - InetAddress address = null; - final String hostNameString = hostName.asString(); - - try { - if ("localhost".equals(hostNameString)) { - lastNameLookup = Resolver.getLocalAddress(); - return receiver; - } - address = InetAddress.getByName(hostNameString); - lastNameLookup = address.getAddress(); - - } catch (UnknownHostException e) { - error(e); - lastNameLookup = null; - } - - return receiver; - } - } - - @GenerateNodeFactory - @SqueakPrimitive(names = "primitiveResolverStartAddressLookup") - protected abstract static class PrimResolverStartAddressLookupNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { - - protected PrimResolverStartAddressLookupNode(final CompiledMethodObject method) { - super(method); - } - - // Look up the given host address in the Domain Name Server to find its name. This call - // is - // asynchronous. To get the results, wait for it to complete or time out and then use - // primAddressLookupResult. - @Specialization(guards = "address.isByteType()") - @TruffleBoundary - protected final Object doWork(final Object receiver, final NativeObject address) { - print("Starting lookup for address " + address); - try { - lastAddressLookup = InetAddress.getByAddress(address.getByteStorage()).getHostName(); - } catch (UnknownHostException e) { - error(e); - lastAddressLookup = null; - } - return receiver; - } - } - - @GenerateNodeFactory - @SqueakPrimitive(names = "primitiveResolverNameLookupResult") - protected abstract static class PrimResolverNameLookupResultNode extends AbstractSocketPluginPrimitiveNode implements UnaryPrimitive { - protected PrimResolverNameLookupResultNode(final CompiledMethodObject method) { - super(method); - } - - // Return the host address found by the last host name lookup. Returns nil if the last - // lookup was unsuccessful. - @Specialization - @TruffleBoundary - protected final Object doWork(@SuppressWarnings("unused") final AbstractSqueakObject receiver) { - if (lastNameLookup == null) { - print(">> Name Lookup Result: " + null); - return code.image.nil; - } else { - try { - print(">> Name Lookup Result: " + addressBytesToString(lastNameLookup)); - return code.image.wrap(lastNameLookup); - } catch (UnknownHostException e) { - error(e); - } - print(">> Name Lookup Result: " + null); - return null; - } - } - } - - @GenerateNodeFactory - @SqueakPrimitive(names = "primitiveResolverAddressLookupResult") - protected abstract static class PrimResolverAddressLookupResultNode extends AbstractSocketPluginPrimitiveNode implements UnaryPrimitive { - protected PrimResolverAddressLookupResultNode(final CompiledMethodObject method) { - super(method); - } - - // Return the host name found by the last host address lookup. - // Returns nil if the last lookup was unsuccessful. - @Specialization - protected final Object doWork(@SuppressWarnings("unused") final AbstractSqueakObject receiver) { - print(">> Address Lookup Result"); - if (lastAddressLookup == null) { - return code.image.nil; - } else { - return code.image.wrap(lastAddressLookup); - } - } - } - - @GenerateNodeFactory - @SqueakPrimitive(names = "primitiveResolverLocalAddress") - protected abstract static class PrimResolverLocalAddressNode extends AbstractSocketPluginPrimitiveNode implements UnaryPrimitive { - protected PrimResolverLocalAddressNode(final CompiledMethodObject method) { - super(method); - } - - @Specialization - @TruffleBoundary - protected final Object doWork(@SuppressWarnings("unused") final AbstractSqueakObject receiver) { - try { - final byte[] address = Resolver.getLocalAddress(); - print(">> Local Address: " + addressBytesToString(address)); - return code.image.wrap(address); - } catch (UnknownHostException e) { - error(e); - throw new PrimitiveFailed(); - } - } - } - - @GenerateNodeFactory - @SqueakPrimitive(names = "primitiveSocketLocalPort") - protected abstract static class PrimSocketLocalPortNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { - protected PrimSocketLocalPortNode(final CompiledMethodObject method) { - super(method); - } - - // Return the local port for this socket, or zero if no port has yet been assigned. - @Specialization - @TruffleBoundary - protected static final Long doWork(@SuppressWarnings("unused") final Object receiver, final long socketID) { - return (long) getSocketImplOrPrimFail(socketID).getLocalPort(); - } - } - - @GenerateNodeFactory - @SqueakPrimitive(names = "primitiveSocketListenWithOrWithoutBacklog") - protected abstract static class PrimSocketListenWithOrWithoutBacklogNode extends AbstractSocketPluginPrimitiveNode implements QuaternaryPrimitive { - protected PrimSocketListenWithOrWithoutBacklogNode(final CompiledMethodObject method) { - super(method); - } - - // Method 1: - // Set the local port associated with a UDP socket. - // Note: this primitive is overloaded. The primitive will not fail on a TCP socket, but - // the effects will not be what was desired. Best solution would be to split Socket into - // two subclasses, TCPSocket and UDPSocket. - // Method 2: - // Listen for a connection on the given port. This is an asynchronous call; query the - // socket status to discover if and when the connection is actually completed. - // Method 3: - // Primitive. Set up the socket to listen on the given port. - // Will be used in conjunction with #accept only. - @Specialization - @TruffleBoundary - protected final Object doWork(final Object receiver, final long socketID, - final long port, - @SuppressWarnings("unused") final NotProvided backlogSize) { - try { - getSocketImplOrPrimFail(socketID).listenOn((int) port); - } catch (IOException e) { - error(e); - throw new PrimitiveFailed(); - } - return receiver; - } - - @Specialization - @TruffleBoundary - protected final Object doWork(final Object receiver, final long socketID, - final long port, - @SuppressWarnings("unused") final Object backlogSize) { - try { - getSocketImplOrPrimFail(socketID).listenOn((int) port); - } catch (IOException e) { - error(e); - throw new PrimitiveFailed(); - } - return receiver; - } - } - - @GenerateNodeFactory - @SqueakPrimitive(names = "primitiveSocketListenOnPortBacklogInterface") - protected abstract static class PrimSocketListenOnPortBacklogInterfaceNode extends AbstractSocketPluginPrimitiveNode implements QuinaryPrimitive { - protected PrimSocketListenOnPortBacklogInterfaceNode(final CompiledMethodObject method) { - super(method); - } - - // Primitive. Set up the socket to listen on the given port. - // Will be used in conjunction with #accept only. - @SuppressWarnings("unused") - @Specialization - @TruffleBoundary - protected final Object doWork(final Object receiver, - final long socketID, - final long port, - final Object backlogSize, - final Object interfaceAddress) { - try { - getSocketImplOrPrimFail(socketID).listenOn((int) port); - } catch (IOException e) { - error(e); - throw new PrimitiveFailed(); - } - return receiver; - } - } - - @GenerateNodeFactory - @SqueakPrimitive(names = "primitiveSocketSetOptions") - protected abstract static class PrimSocketSetOptionsNode extends AbstractSocketPluginPrimitiveNode implements QuaternaryPrimitive { - protected PrimSocketSetOptionsNode(final CompiledMethodObject method) { - super(method); - } - - @Specialization(guards = "option.isByteType()") - @TruffleBoundary - protected static final Object doWork(final Object receiver, final long socketID, final NativeObject option, final NativeObject value) { - final SocketImpl socketImpl = getSocketImplOrPrimFail(socketID); - socketImpl.setOption(option.asString(), value); - return receiver; - } - } - - @GenerateNodeFactory - @SqueakPrimitive(names = "primitiveSocketConnectToPort") - protected abstract static class PrimSocketConnectToPortNode extends AbstractSocketPluginPrimitiveNode implements QuaternaryPrimitive { - protected PrimSocketConnectToPortNode(final CompiledMethodObject method) { - super(method); - } - - @Specialization(guards = "hostAddress.isByteType()") - @TruffleBoundary - protected final long doWork(@SuppressWarnings("unused") final Object receiver, final long socketID, final NativeObject hostAddress, final long port) { - final SocketImpl socketImpl = getSocketImplOrPrimFail(socketID); - - try { - final byte[] bytes = hostAddress.getByteStorage(); - final String hostAddressString = addressBytesToString(bytes); - socketImpl.connectTo(hostAddressString, (int) port); - } catch (IOException e) { - error(e); - throw new PrimitiveFailed(); - } - return 0; - } - } - - @GenerateNodeFactory - @SqueakPrimitive(names = "primitiveSocketConnectionStatus") - protected abstract static class PrimSocketConnectionStatusNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { - protected PrimSocketConnectionStatusNode(final CompiledMethodObject method) { - super(method); - } - - @Specialization - @TruffleBoundary - protected final long doWork(@SuppressWarnings("unused") final PointersObject receiver, final long socketID) { - if (!sockets.containsKey(socketID)) { - return SocketStatus.Unconnected; - } - final SocketImpl socketImpl = getSocketImplOrPrimFail(socketID); - try { - return socketImpl.getStatus(); - } catch (IOException e) { - error(e); - throw new PrimitiveFailed(); - } - } - } - - @GenerateNodeFactory - @SqueakPrimitive(names = "primitiveSocketRemoteAddress") - protected abstract static class PrimSocketRemoteAddressNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { - protected PrimSocketRemoteAddressNode(final CompiledMethodObject method) { - super(method); - } - - @Specialization - @TruffleBoundary - protected final Object doWork(@SuppressWarnings("unused") final Object receiver, final long socketID) { - return code.image.wrap(getSocketImplOrPrimFail(socketID).getRemoteAddress()); - } - } - - @GenerateNodeFactory - @SqueakPrimitive(names = "primitiveSocketRemotePort") - protected abstract static class PrimSocketRemotePortNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { - protected PrimSocketRemotePortNode(final CompiledMethodObject method) { - super(method); - } - - @Specialization - @TruffleBoundary - protected static final Object doWork(@SuppressWarnings("unused") final Object receiver, final long socketID) { - final SocketImpl socketImpl = getSocketImplOrPrimFail(socketID); - return socketImpl.getRemotePort(); - } - } - - @GenerateNodeFactory - @SqueakPrimitive(names = "primitiveSocketGetOptions") - protected abstract static class PrimSocketGetOptionsNode extends AbstractSocketPluginPrimitiveNode implements TernaryPrimitive { - protected PrimSocketGetOptionsNode(final CompiledMethodObject method) { - super(method); - } - - // Get some option information on this socket. Refer to the UNIX - // man pages for valid SO, TCP, IP, UDP options. In case of doubt - // refer to the source code. - // TCP_NODELAY, SO_KEEPALIVE are valid options for example - // returns an array containing the error code and the option value - - // options := { - // 'SO_DEBUG'. 'SO_REUSEADDR'. 'SO_REUSEPORT'. 'SO_DONTROUTE'. - // 'SO_BROADCAST'. 'SO_SNDBUF'. 'SO_RCVBUF'. 'SO_KEEPALIVE'. - // 'SO_OOBINLINE'. 'SO_PRIORITY'. 'SO_LINGER'. 'SO_RCVLOWAT'. - // 'SO_SNDLOWAT'. 'IP_TTL'. 'IP_HDRINCL'. 'IP_RCVOPTS'. - // 'IP_RCVDSTADDR'. 'IP_MULTICAST_IF'. 'IP_MULTICAST_TTL'. - // 'IP_MULTICAST_LOOP'. 'UDP_CHECKSUM'. 'TCP_MAXSEG'. - // 'TCP_NODELAY'. 'TCP_ABORT_THRESHOLD'. 'TCP_CONN_NOTIFY_THRESHOLD'. - // 'TCP_CONN_ABORT_THRESHOLD'. 'TCP_NOTIFY_THRESHOLD'. - // 'TCP_URGENT_PTR_TYPE'}. - @Specialization(guards = "option.isByteType()") - @TruffleBoundary - protected final Object doWork(@SuppressWarnings("unused") final Object receiver, final long socketID, final NativeObject option) { - final SocketImpl socketImpl = getSocketImplOrPrimFail(socketID); - final Object value = socketImpl.getOption(option.asString()); - final Long errorCode = socketImpl.getError(); - final Object[] result = new Object[]{errorCode, value}; - return code.image.wrap(result); - } - } - - @GenerateNodeFactory - @SqueakPrimitive(names = "primitiveSocketReceiveDataAvailable") - protected abstract static class PrimSocketReceiveDataAvailableNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { - protected PrimSocketReceiveDataAvailableNode(final CompiledMethodObject method) { - super(method); - } - - @Specialization - @TruffleBoundary - protected final boolean doWork(@SuppressWarnings("unused") final Object receiver, final long socketID) { - final SocketImpl socketImpl = getSocketImplOrPrimFail(socketID); - try { - return socketImpl.isDataAvailable(); - } catch (IOException e) { - error(e); - return code.image.sqFalse; - } - } - } - - @GenerateNodeFactory - @SqueakPrimitive(names = "primitiveSocketError") - protected abstract static class PrimSocketErrorNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { - protected PrimSocketErrorNode(final CompiledMethodObject method) { - super(method); - } - - @Specialization - @TruffleBoundary - protected static final long doWork(@SuppressWarnings("unused") final Object receiver, final long socketID) { - final SocketImpl socketImpl = getSocketImplOrPrimFail(socketID); - return socketImpl.getError(); - } - } - - @GenerateNodeFactory - @SqueakPrimitive(names = "primitiveSocketLocalAddress") - protected abstract static class PrimSocketLocalAddressNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { - protected PrimSocketLocalAddressNode(final CompiledMethodObject method) { - super(method); - } - - @Specialization - @TruffleBoundary - protected final Object doWork(@SuppressWarnings("unused") final Object receiver, final long socketID) { - final SocketImpl socketImpl = getSocketImplOrPrimFail(socketID); - try { - final Object result = socketImpl.getLocalAddress(); - if (result instanceof byte[]) { - return code.image.wrap((byte[]) result); - } else { - return (long) result; - } - - } catch (UnknownHostException e) { - error(e); - throw new PrimitiveFailed(); - } - } - } - - @GenerateNodeFactory - @SqueakPrimitive(names = "primitiveSocketSendDataBufCount") - protected abstract static class PrimSocketSendDataBufCountNode extends AbstractSocketPluginPrimitiveNode implements QuinaryPrimitive { - protected PrimSocketSendDataBufCountNode(final CompiledMethodObject method) { - super(method); - } - - // Send data to the remote host through the given socket starting with the given byte - // index - // of the given byte array. The data sent is 'pushed' immediately. Return the number of - // bytes of data actually sent; any remaining data should be re-submitted for sending - // after - // the current send operation has completed. - // Note: In general, it many take several sendData calls to transmit a large data array - // since the data is sent in send-buffer-sized chunks. The size of the send buffer is - // determined when the socket is created. - @Specialization(guards = "aStringOrByteArray.isByteType()") - @TruffleBoundary - protected final long doWork(@SuppressWarnings("unused") final Object receiver, - final long socketID, - final NativeObject aStringOrByteArray, - final long startIndex, - final long count) { - final SocketImpl socketImpl = getSocketImplOrPrimFail(socketID); - try { - final byte[] data = aStringOrByteArray.getByteStorage(); - socketImpl.sendData(data, (int) (startIndex - 1), (int) count); - return count; - } catch (Exception e) { - error(e); - throw new PrimitiveFailed(); - } - } - } - - @GenerateNodeFactory - @SqueakPrimitive(names = "primitiveSocketCloseConnection") - protected abstract static class PrimSocketCloseConnectionNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { - protected PrimSocketCloseConnectionNode(final CompiledMethodObject method) { - super(method); - } - - @Specialization - @TruffleBoundary - protected final Object doWork(final Object receiver, final long socketID) { - try { - getSocketImplOrPrimFail(socketID).close(); - } catch (IOException e) { - error(e); - throw new PrimitiveFailed(); - } - return receiver; - } - } - - @GenerateNodeFactory - @SqueakPrimitive(names = "primitiveSocketAbortConnection") - protected abstract static class PrimSocketAbortConnectionNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { - protected PrimSocketAbortConnectionNode(final CompiledMethodObject method) { - super(method); - } - - @Specialization - @TruffleBoundary - protected final Object doWork(final Object receiver, final long socketID) { - try { - getSocketImplOrPrimFail(socketID).close(); - } catch (IOException e) { - error(e); - throw new PrimitiveFailed(); - } - return receiver; - } - } - - @GenerateNodeFactory - @SqueakPrimitive(names = "primitiveSocketSendDone") - protected abstract static class PrimSocketSendDoneNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { - protected PrimSocketSendDoneNode(final CompiledMethodObject method) { - super(method); - } - - @Specialization - @TruffleBoundary - protected final Object doWork(@SuppressWarnings("unused") final Object receiver, final long socketID) { - return code.image.wrap(getSocketImplOrPrimFail(socketID).isSendDone()); - } - } - - @GenerateNodeFactory - @SqueakPrimitive(names = "primitiveSocketReceiveDataBufCount") - protected abstract static class PrimSocketReceiveDataBufCountNode extends AbstractSocketPluginPrimitiveNode implements QuinaryPrimitive { - protected PrimSocketReceiveDataBufCountNode(final CompiledMethodObject method) { - super(method); - } - - // Receive data from the given socket into the given array starting at the given index. - // Return the number of bytes read or zero if no data is available. - @Specialization(guards = "receiveBuffer.isByteType()") - @TruffleBoundary - protected final long doWork(@SuppressWarnings("unused") final Object receiver, final long socketID, final NativeObject receiveBuffer, final long startIndex, final long count) { - final SocketImpl socketImpl = getSocketImplOrPrimFail(socketID); - final byte[] buffer = receiveBuffer.getByteStorage(); - final long readBytes; - try { - readBytes = socketImpl.receiveData(buffer, (int) (startIndex - 1), (int) count); - } catch (IOException e) { - error(e); - throw new PrimitiveFailed(); - } - return readBytes; - } - } - - @GenerateNodeFactory - @SqueakPrimitive(names = "primitiveSocketDestroy") - protected abstract static class PrimSocketDestroyNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { - protected PrimSocketDestroyNode(final CompiledMethodObject method) { - super(method); - } - - @Specialization - @TruffleBoundary - protected final long doWork(@SuppressWarnings("unused") final Object receiver, final long socketID) { - final SocketImpl socketImpl = getSocketImplOrPrimFail(socketID); - try { - if (socketImpl != null) { - socketImpl.close(); - sockets.removeKey(socketID); - } - } catch (IOException e) { - error(e); - throw new PrimitiveFailed(); - } - - return 0; - } - } - - @GenerateNodeFactory - @SqueakPrimitive(names = "primitiveSocketCreate3Semaphores") - protected abstract static class PrimSocketCreate3SemaphoresNode extends AbstractSocketPluginPrimitiveNode implements SeptenaryPrimitive { - protected PrimSocketCreate3SemaphoresNode(final CompiledMethodObject method) { - super(method); - } - - @SuppressWarnings("unused") - @TruffleBoundary - @Specialization - protected final long doWork(final PointersObject receiver, - final long netType, - final long socketType, - final long rcvBufSize, - final long semaIndex, - final long aReadSema, - final long aWriteSema) { - final SocketImpl s = new SocketImpl(code, socketType); - sockets.put((long) s.hashCode(), s); - return s.hashCode(); - } - } - - @GenerateNodeFactory - @SqueakPrimitive(names = "primitiveSocketAccept3Semaphores") - protected abstract static class PrimSocketAccept3SemaphoresNode extends AbstractSocketPluginPrimitiveNode implements SeptenaryPrimitive { - protected PrimSocketAccept3SemaphoresNode(final CompiledMethodObject method) { - super(method); - } - - @SuppressWarnings("unused") - @TruffleBoundary - @Specialization - protected final long doWork(final PointersObject receiver, - final long socketID, - final Object receiveBufferSize, - final Object sendBufSize, - final Object semaIndex, - final Object readSemaIndex, - final Object writeSemaIndex) { - try { - final SocketImpl socketImpl = getSocketImplOrPrimFail(socketID); - final SocketImpl s = socketImpl.accept(); - sockets.put((long) s.hashCode(), s); - return s.hashCode(); - } catch (IOException e) { - error(e); - throw new PrimitiveFailed(); - } - } - } - - @GenerateNodeFactory - @SqueakPrimitive(names = "primitiveSocketCreate") - protected abstract static class PrimSocketCreateNode extends AbstractSocketPluginPrimitiveNode implements SenaryPrimitive { - protected PrimSocketCreateNode(final CompiledMethodObject method) { - super(method); - } - - @SuppressWarnings("unused") - @Specialization - protected final long doWork(final PointersObject receiver, - final Object netType, - final Object socketType, - final Object rcvBufSize, - final Object sendBufSize, - final Object semaIndexa) { - error("TODO: primitiveSocketCreate"); - throw new PrimitiveFailed(); - } - - } - - @Override - public List> getFactories() { - return SocketPluginFactory.getFactories(); - } -} diff --git a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/Resolver.java b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/Resolver.java new file mode 100644 index 000000000..8458fad9a --- /dev/null +++ b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/Resolver.java @@ -0,0 +1,82 @@ +package de.hpi.swa.graal.squeak.nodes.plugins.network; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; + +final class Resolver { + + enum Status { + Uninitialized(0), + Ready(1), + Busy(2), + Error(3); + + private final long id; + + Status(final long id) { + this.id = id; + } + + long id() { + return id; + } + } + + private static InetAddress anyLocalAddress = new InetSocketAddress(0).getAddress(); + private static InetAddress loopbackAddress = InetAddress.getLoopbackAddress(); + + private static byte[] lastNameLookup; + private static String lastAddressLookup; + + private Resolver() { + } + + static byte[] getAnyLocalAddress() { + return anyLocalAddress.getAddress(); + } + + static byte[] getLoopbackAddress() { + return loopbackAddress.getAddress(); + } + + static void startHostNameLookUp(final String hostName) throws UnknownHostException { + try { + if ("localhost".equals(hostName)) { + lastNameLookup = Resolver.getLoopbackAddress(); + return; + } + + final InetAddress address = InetAddress.getByName(hostName); + lastNameLookup = address.getAddress(); + } catch (final UnknownHostException e) { + lastNameLookup = null; + throw e; + } + } + + static byte[] lastHostNameLookupResult() { + return lastNameLookup; + } + + static void startAddressLookUp(final byte[] address) throws UnknownHostException { + try { + lastAddressLookup = InetAddress.getByAddress(address).getHostName(); + } catch (final UnknownHostException e) { + lastAddressLookup = null; + throw e; + } + } + + static String lastAddressLookUpResult() { + return lastAddressLookup; + } + + static String addressBytesToString(final byte[] address) { + try { + return InetAddress.getByAddress(address).getHostAddress(); + } catch (final UnknownHostException e) { + return null; + } + } +} diff --git a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SocketPlugin.java b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SocketPlugin.java new file mode 100644 index 000000000..da03164f1 --- /dev/null +++ b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SocketPlugin.java @@ -0,0 +1,708 @@ +package de.hpi.swa.graal.squeak.nodes.plugins.network; + +import de.hpi.swa.graal.squeak.model.ArrayObject; +import java.io.IOException; +import java.net.UnknownHostException; +import java.nio.ByteBuffer; +import java.util.List; + +import org.graalvm.collections.EconomicMap; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.GenerateNodeFactory; +import com.oracle.truffle.api.dsl.NodeFactory; +import com.oracle.truffle.api.dsl.Specialization; + +import de.hpi.swa.graal.squeak.exceptions.PrimitiveExceptions.PrimitiveFailed; +import de.hpi.swa.graal.squeak.model.AbstractSqueakObject; +import de.hpi.swa.graal.squeak.model.CompiledMethodObject; +import de.hpi.swa.graal.squeak.model.NativeObject; +import de.hpi.swa.graal.squeak.model.NotProvided; +import de.hpi.swa.graal.squeak.model.PointersObject; +import de.hpi.swa.graal.squeak.nodes.primitives.AbstractPrimitiveFactoryHolder; +import de.hpi.swa.graal.squeak.nodes.primitives.AbstractPrimitiveNode; +import de.hpi.swa.graal.squeak.nodes.primitives.PrimitiveInterfaces.BinaryPrimitive; +import de.hpi.swa.graal.squeak.nodes.primitives.PrimitiveInterfaces.QuaternaryPrimitive; +import de.hpi.swa.graal.squeak.nodes.primitives.PrimitiveInterfaces.QuinaryPrimitive; +import de.hpi.swa.graal.squeak.nodes.primitives.PrimitiveInterfaces.SenaryPrimitive; +import de.hpi.swa.graal.squeak.nodes.primitives.PrimitiveInterfaces.SeptenaryPrimitive; +import de.hpi.swa.graal.squeak.nodes.primitives.PrimitiveInterfaces.TernaryPrimitive; +import de.hpi.swa.graal.squeak.nodes.primitives.PrimitiveInterfaces.UnaryPrimitive; +import de.hpi.swa.graal.squeak.nodes.primitives.SqueakPrimitive; + +public final class SocketPlugin extends AbstractPrimitiveFactoryHolder { + + private static final EconomicMap SOCKETS = EconomicMap.create(); + private static final boolean debugPrints = false; + + protected abstract static class AbstractSocketPluginPrimitiveNode extends AbstractPrimitiveNode { + + protected AbstractSocketPluginPrimitiveNode(final CompiledMethodObject method) { + super(method); + } + + protected final void error(final Object o) { + code.image.printToStdErr(o); + } + + protected final void print(final Object o) { + if (debugPrints) { + code.image.printToStdOut(o); + } + } + } + + @GenerateNodeFactory + @SqueakPrimitive(names = "primitiveResolverStatus") + protected abstract static class PrimResolverStatusNode extends AbstractSocketPluginPrimitiveNode implements UnaryPrimitive { + protected PrimResolverStatusNode(final CompiledMethodObject method) { + super(method); + } + + @Specialization + protected static long doWork(@SuppressWarnings("unused") final AbstractSqueakObject receiver) { + return Resolver.Status.Ready.id(); + } + } + + @GenerateNodeFactory + @SqueakPrimitive(names = "primitiveInitializeNetwork") + protected abstract static class PrimInitializeNetworkNode extends AbstractSocketPluginPrimitiveNode implements UnaryPrimitive { + protected PrimInitializeNetworkNode(final CompiledMethodObject method) { + super(method); + } + + @Specialization + protected static AbstractSqueakObject doWork(final AbstractSqueakObject receiver) { + return receiver; + } + } + + @TruffleBoundary + private static SqSocket getSocketOrPrimFail(final long socketHandle) { + final SqSocket socket = SOCKETS.get(socketHandle); + if (socket == null) { + throw new PrimitiveFailed(); + } + return socket; + } + + @GenerateNodeFactory + @SqueakPrimitive(names = "primitiveResolverStartNameLookup") + protected abstract static class PrimResolverStartNameLookupNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { + protected PrimResolverStartNameLookupNode(final CompiledMethodObject method) { + super(method); + } + + /** + * Look up the given host name in the Domain Name Server to find its address. This call is + * asynchronous. To get the results, wait for it to complete or time out and then use + * primNameLookupResult. + */ + @Specialization(guards = "hostName.isByteType()") + @TruffleBoundary + protected final Object doWork(final Object receiver, final NativeObject hostName) { + try { + print(">> Starting lookup for host name " + hostName); + Resolver.startHostNameLookUp(hostName.asString()); + } catch (final UnknownHostException e) { + error(e); + } + return receiver; + } + } + + @GenerateNodeFactory + @SqueakPrimitive(names = "primitiveResolverStartAddressLookup") + protected abstract static class PrimResolverStartAddressLookupNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { + + protected PrimResolverStartAddressLookupNode(final CompiledMethodObject method) { + super(method); + } + + /** + * Look up the given host address in the Domain Name Server to find its name. This call is + * asynchronous. To get the results, wait for it to complete or time out and then use + * primAddressLookupResult. + */ + @Specialization(guards = "address.isByteType()") + @TruffleBoundary + protected final Object doWork(final Object receiver, final NativeObject address) { + try { + print("Starting lookup for address " + address); + Resolver.startAddressLookUp(address.getByteStorage()); + } catch (final UnknownHostException e) { + error(e); + } + return receiver; + } + } + + @GenerateNodeFactory + @SqueakPrimitive(names = "primitiveResolverNameLookupResult") + protected abstract static class PrimResolverNameLookupResultNode extends AbstractSocketPluginPrimitiveNode implements UnaryPrimitive { + + protected PrimResolverNameLookupResultNode(final CompiledMethodObject method) { + super(method); + } + + /** + * Return the host address found by the last host name lookup. Returns nil if the last + * lookup was unsuccessful. + */ + @Specialization + @TruffleBoundary + protected final AbstractSqueakObject doWork( + @SuppressWarnings("unused") final AbstractSqueakObject receiver) { + final byte[] lastNameLookup = Resolver.lastHostNameLookupResult(); + print(">> Name Lookup Result: " + Resolver.addressBytesToString(lastNameLookup)); + return lastNameLookup == null ? code.image.nil : code.image.wrap(lastNameLookup); + } + } + + @GenerateNodeFactory + @SqueakPrimitive(names = "primitiveResolverAddressLookupResult") + protected abstract static class PrimResolverAddressLookupResultNode extends AbstractSocketPluginPrimitiveNode implements UnaryPrimitive { + protected PrimResolverAddressLookupResultNode(final CompiledMethodObject method) { + super(method); + } + + /** + * Return the host name found by the last host address lookup. Returns nil if the last + * lookup was unsuccessful. + */ + @Specialization + protected final AbstractSqueakObject doWork(@SuppressWarnings("unused") final AbstractSqueakObject receiver) { + final String lastAddressLookup = Resolver.lastAddressLookUpResult(); + print(">> Address Lookup Result: " + lastAddressLookup); + return lastAddressLookup == null ? code.image.nil : code.image.wrap(lastAddressLookup); + } + } + + @GenerateNodeFactory + @SqueakPrimitive(names = "primitiveResolverLocalAddress") + protected abstract static class PrimResolverLocalAddressNode extends AbstractSocketPluginPrimitiveNode implements UnaryPrimitive { + protected PrimResolverLocalAddressNode(final CompiledMethodObject method) { + super(method); + } + + @Specialization + @TruffleBoundary + protected final AbstractSqueakObject doWork(@SuppressWarnings("unused") final AbstractSqueakObject receiver) { + final byte[] address = Resolver.getLoopbackAddress(); + print(">> Local Address: " + Resolver.addressBytesToString(address)); + return code.image.wrap(address); + } + } + + @GenerateNodeFactory + @SqueakPrimitive(names = "primitiveSocketLocalPort") + protected abstract static class PrimSocketLocalPortNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { + protected PrimSocketLocalPortNode(final CompiledMethodObject method) { + super(method); + } + + /** Return the local port for this socket, or zero if no port has yet been assigned. */ + @Specialization + @TruffleBoundary + protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObject receiver, final long socketID) { + try { + return getSocketOrPrimFail(socketID).getLocalPort(); + } catch (final IOException e) { + error(e); + throw new PrimitiveFailed(); + } + } + } + + @GenerateNodeFactory + @SqueakPrimitive(names = "primitiveSocketListenWithOrWithoutBacklog") + protected abstract static class PrimSocketListenWithOrWithoutBacklogNode extends AbstractSocketPluginPrimitiveNode implements QuaternaryPrimitive { + protected PrimSocketListenWithOrWithoutBacklogNode(final CompiledMethodObject method) { + super(method); + } + + /** + * Listen for a connection on the given port. This is an asynchronous call; query the socket + * status to discover if and when the connection is actually completed. + */ + @Specialization + @TruffleBoundary + protected final AbstractSqueakObject doWork(final AbstractSqueakObject receiver, + final long socketID, + final long port, + @SuppressWarnings("unused") final NotProvided backlogSize) { + try { + getSocketOrPrimFail(socketID).listenOn(port, 0L); + return receiver; + } catch (IOException e) { + error(e); + throw new PrimitiveFailed(); + } + } + + /** + * Set up the socket to listen on the given port. Will be used in conjunction with #accept + * only. + */ + @Specialization + @TruffleBoundary + protected final AbstractSqueakObject doWork(final AbstractSqueakObject receiver, + final long socketID, + final long port, + @SuppressWarnings("unused") final long backlogSize) { + try { + getSocketOrPrimFail(socketID).listenOn(port, backlogSize); + return receiver; + } catch (IOException e) { + error(e); + throw new PrimitiveFailed(); + } + } + } + + @GenerateNodeFactory + @SqueakPrimitive(names = "primitiveSocketListenOnPortBacklogInterface") + protected abstract static class PrimSocketListenOnPortBacklogInterfaceNode extends AbstractSocketPluginPrimitiveNode implements QuinaryPrimitive { + protected PrimSocketListenOnPortBacklogInterfaceNode(final CompiledMethodObject method) { + super(method); + } + + /** + * Set up the socket to listen on the given port. Will be used in conjunction with #accept + * only. + */ + @Specialization(guards = "interfaceAddress.isByteType()") + @TruffleBoundary + protected final AbstractSqueakObject doWork(final AbstractSqueakObject receiver, + final long socketID, + final long port, + @SuppressWarnings("unused") final long backlogSize, + @SuppressWarnings("unused") final NativeObject interfaceAddress) { + try { + getSocketOrPrimFail(socketID).listenOn(port, backlogSize); + return receiver; + } catch (IOException e) { + error(e); + throw new PrimitiveFailed(); + } + } + } + + @GenerateNodeFactory + @SqueakPrimitive(names = "primitiveSocketSetOptions") + protected abstract static class PrimSocketSetOptionsNode extends AbstractSocketPluginPrimitiveNode implements QuaternaryPrimitive { + protected PrimSocketSetOptionsNode(final CompiledMethodObject method) { + super(method); + } + + @Specialization(guards = "option.isByteType()") + @TruffleBoundary + protected final ArrayObject doWork(@SuppressWarnings("unused") final AbstractSqueakObject receiver, final long socketID, final NativeObject option, final NativeObject value) { + try { + final SqSocket socket = getSocketOrPrimFail(socketID); + return setSocketOption(socket, option.asString(), value.asString()); + } catch (final IOException e) { + error(e); + throw new PrimitiveFailed(); + } + } + + private ArrayObject setSocketOption(final SqSocket socket, final String option, final String value) throws IOException { + if (socket.supportsOption(option)) { + socket.setOption(option, value); + return code.image.wrap(0, value); + } + + return code.image.wrap(1, "0"); + } + } + + @GenerateNodeFactory + @SqueakPrimitive(names = "primitiveSocketConnectToPort") + protected abstract static class PrimSocketConnectToPortNode extends AbstractSocketPluginPrimitiveNode implements QuaternaryPrimitive { + protected PrimSocketConnectToPortNode(final CompiledMethodObject method) { + super(method); + } + + @Specialization(guards = "hostAddress.isByteType()") + @TruffleBoundary + protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObject receiver, final long socketID, final NativeObject hostAddress, final long port) { + try { + final SqSocket socket = getSocketOrPrimFail(socketID); + final String host = Resolver.addressBytesToString(hostAddress.getByteStorage()); + socket.connectTo(host, (int) port); + } catch (final IOException e) { + error(e); + throw new PrimitiveFailed(); + } + return 0; + } + } + + @GenerateNodeFactory + @SqueakPrimitive(names = "primitiveSocketConnectionStatus") + protected abstract static class PrimSocketConnectionStatusNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { + protected PrimSocketConnectionStatusNode(final CompiledMethodObject method) { + super(method); + } + + @Specialization + @TruffleBoundary + protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObject receiver, final long socketID) { + if (!SOCKETS.containsKey(socketID)) { + return SqSocket.Status.Unconnected.id(); + } + + try { + final SqSocket socket = getSocketOrPrimFail(socketID); + return socket.getStatus().id(); + } catch (IOException e) { + error(e); + throw new PrimitiveFailed(); + } + } + } + + @GenerateNodeFactory + @SqueakPrimitive(names = "primitiveSocketRemoteAddress") + protected abstract static class PrimSocketRemoteAddressNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { + protected PrimSocketRemoteAddressNode(final CompiledMethodObject method) { + super(method); + } + + @Specialization + @TruffleBoundary + protected final AbstractSqueakObject doWork(@SuppressWarnings("unused") final AbstractSqueakObject receiver, final long socketID) { + try { + return code.image.wrap(getSocketOrPrimFail(socketID).getRemoteAddress()); + } catch (final IOException e) { + error(e); + throw new PrimitiveFailed(); + } + } + } + + @GenerateNodeFactory + @SqueakPrimitive(names = "primitiveSocketRemotePort") + protected abstract static class PrimSocketRemotePortNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { + protected PrimSocketRemotePortNode(final CompiledMethodObject method) { + super(method); + } + + @Specialization + @TruffleBoundary + protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObject receiver, final long socketID) { + try { + return getSocketOrPrimFail(socketID).getRemotePort(); + } catch (final IOException e) { + error(e); + throw new PrimitiveFailed(); + } + } + } + + @GenerateNodeFactory + @SqueakPrimitive(names = "primitiveSocketGetOptions") + protected abstract static class PrimSocketGetOptionsNode extends AbstractSocketPluginPrimitiveNode implements TernaryPrimitive { + protected PrimSocketGetOptionsNode(final CompiledMethodObject method) { + super(method); + } + + /** + * Get some option information on this socket. Refer to the UNIX man pages for valid SO, + * TCP, IP, UDP options. In case of doubt refer to the source code. TCP_NODELAY, + * SO_KEEPALIVE are valid options for example returns an array containing the error code and + * the option value. + */ + @Specialization(guards = "option.isByteType()") + @TruffleBoundary + protected final Object doWork(@SuppressWarnings("unused") final AbstractSqueakObject receiver, final long socketID, final NativeObject option) { + try { + final SqSocket socket = getSocketOrPrimFail(socketID); + final String value = socket.getOption(option.asString()); + return code.image.wrap(0, value); + } catch (final IOException e) { + error(e); + throw new PrimitiveFailed(); + } + } + } + + @GenerateNodeFactory + @SqueakPrimitive(names = "primitiveSocketReceiveDataAvailable") + protected abstract static class PrimSocketReceiveDataAvailableNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { + protected PrimSocketReceiveDataAvailableNode(final CompiledMethodObject method) { + super(method); + } + + @Specialization + @TruffleBoundary + protected final boolean doWork(@SuppressWarnings("unused") final AbstractSqueakObject receiver, final long socketID) { + try { + return getSocketOrPrimFail(socketID).isDataAvailable(); + } catch (final IOException e) { + error(e); + return code.image.sqFalse; + } + } + } + + @GenerateNodeFactory + @SqueakPrimitive(names = "primitiveSocketError") + protected abstract static class PrimSocketErrorNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { + protected PrimSocketErrorNode(final CompiledMethodObject method) { + super(method); + } + + @Specialization + @TruffleBoundary + @SuppressWarnings("unused") + protected static long doWork(final AbstractSqueakObject receiver, final long socketID) { + return 0L; + } + } + + @GenerateNodeFactory + @SqueakPrimitive(names = "primitiveSocketLocalAddress") + protected abstract static class PrimSocketLocalAddressNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { + protected PrimSocketLocalAddressNode(final CompiledMethodObject method) { + super(method); + } + + @Specialization + @TruffleBoundary + protected final AbstractSqueakObject doWork(@SuppressWarnings("unused") final AbstractSqueakObject receiver, final long socketID) { + try { + final SqSocket socket = getSocketOrPrimFail(socketID); + return code.image.wrap(socket.getLocalAddress()); + } catch (final IOException e) { + error(e); + throw new PrimitiveFailed(); + } + } + } + + @GenerateNodeFactory + @SqueakPrimitive(names = "primitiveSocketSendDataBufCount") + protected abstract static class PrimSocketSendDataBufCountNode extends AbstractSocketPluginPrimitiveNode implements QuinaryPrimitive { + protected PrimSocketSendDataBufCountNode(final CompiledMethodObject method) { + super(method); + } + + /** + * Send data to the remote host through the given socket starting with the given byte index + * of the given byte array. The data sent is 'pushed' immediately. Return the number of + * bytes of data actually sent; any remaining data should be re-submitted for sending after + * the current send operation has completed. Note: In general, it many take several sendData + * calls to transmit a large data array since the data is sent in send-buffer-sized chunks. + * The size of the send buffer is determined when the socket is created. + */ + @Specialization(guards = "buffer.isByteType()") + @TruffleBoundary + protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObject receiver, + final long socketID, + final NativeObject buffer, + final long startIndex, + final long count) { + + try { + final SqSocket socket = getSocketOrPrimFail(socketID); + return socket.sendData(ByteBuffer.wrap(buffer.getByteStorage(), (int) startIndex - 1, (int) count)); + } catch (final IOException e) { + error(e); + throw new PrimitiveFailed(); + } + } + } + + @GenerateNodeFactory + @SqueakPrimitive(names = "primitiveSocketCloseConnection") + protected abstract static class PrimSocketCloseConnectionNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { + protected PrimSocketCloseConnectionNode(final CompiledMethodObject method) { + super(method); + } + + @Specialization + @TruffleBoundary + protected final AbstractSqueakObject doWork(final AbstractSqueakObject receiver, final long socketID) { + try { + getSocketOrPrimFail(socketID).close(); + return receiver; + } catch (IOException e) { + error(e); + throw new PrimitiveFailed(); + } + } + } + + @GenerateNodeFactory + @SqueakPrimitive(names = "primitiveSocketAbortConnection") + protected abstract static class PrimSocketAbortConnectionNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { + protected PrimSocketAbortConnectionNode(final CompiledMethodObject method) { + super(method); + } + + @Specialization + @TruffleBoundary + protected final AbstractSqueakObject doWork(final AbstractSqueakObject receiver, final long socketID) { + try { + getSocketOrPrimFail(socketID).close(); + return receiver; + } catch (IOException e) { + error(e); + throw new PrimitiveFailed(); + } + } + } + + @GenerateNodeFactory + @SqueakPrimitive(names = "primitiveSocketSendDone") + protected abstract static class PrimSocketSendDoneNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { + protected PrimSocketSendDoneNode(final CompiledMethodObject method) { + super(method); + } + + @Specialization + @TruffleBoundary + protected final Object doWork(@SuppressWarnings("unused") final AbstractSqueakObject receiver, final long socketID) { + try { + return code.image.wrap(getSocketOrPrimFail(socketID).isSendDone()); + } catch (final IOException e) { + error(e); + throw new PrimitiveFailed(); + } + } + } + + @GenerateNodeFactory + @SqueakPrimitive(names = "primitiveSocketReceiveDataBufCount") + protected abstract static class PrimSocketReceiveDataBufCountNode extends AbstractSocketPluginPrimitiveNode implements QuinaryPrimitive { + protected PrimSocketReceiveDataBufCountNode(final CompiledMethodObject method) { + super(method); + } + + /** + * Receive data from the given socket into the given array starting at the given index. + * Return the number of bytes read or zero if no data is available. + */ + @Specialization(guards = "buffer.isByteType()") + @TruffleBoundary + protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObject receiver, final long socketID, final NativeObject buffer, final long startIndex, final long count) { + try { + final SqSocket socket = getSocketOrPrimFail(socketID); + return socket.receiveData(ByteBuffer.wrap(buffer.getByteStorage(), (int) startIndex - 1, (int) count)); + } catch (IOException e) { + error(e); + throw new PrimitiveFailed(); + } + } + } + + @GenerateNodeFactory + @SqueakPrimitive(names = "primitiveSocketDestroy") + protected abstract static class PrimSocketDestroyNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { + protected PrimSocketDestroyNode(final CompiledMethodObject method) { + super(method); + } + + @Specialization + @TruffleBoundary + protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObject receiver, final long socketID) { + try { + final SqSocket socket = SOCKETS.removeKey(socketID); + if (socket != null) { + socket.close(); + } + return 0; + } catch (IOException e) { + error(e); + throw new PrimitiveFailed(); + } + } + } + + @GenerateNodeFactory + @SqueakPrimitive(names = "primitiveSocketCreate3Semaphores") + protected abstract static class PrimSocketCreate3SemaphoresNode extends AbstractSocketPluginPrimitiveNode implements SeptenaryPrimitive { + protected PrimSocketCreate3SemaphoresNode(final CompiledMethodObject method) { + super(method); + } + + @SuppressWarnings("unused") + @TruffleBoundary + @Specialization + protected final long doWork(final PointersObject receiver, + final long netType, + final long socketType, + final long rcvBufSize, + final long semaphoreIndex, + final long aReadSemaphore, + final long aWriteSemaphore) { + + try { + final SqSocket.Type type = SqSocket.Type.fromId(socketType); + final SqSocket socket = SqSocket.create(type, code.image, debugPrints); + SOCKETS.put(socket.handle(), socket); + return socket.handle(); + } catch (final IOException e) { + throw new PrimitiveFailed(); + } + } + } + + @GenerateNodeFactory + @SqueakPrimitive(names = "primitiveSocketAccept3Semaphores") + protected abstract static class PrimSocketAccept3SemaphoresNode extends AbstractSocketPluginPrimitiveNode implements SeptenaryPrimitive { + protected PrimSocketAccept3SemaphoresNode(final CompiledMethodObject method) { + super(method); + } + + @SuppressWarnings("unused") + @TruffleBoundary + @Specialization + protected final long doWork(final AbstractSqueakObject receiver, + final long socketID, + final long receiveBufferSize, + final long sendBufSize, + final long semaphoreIndex, + final long readSemaphoreIndex, + final long writeSemaphoreIndex) { + try { + final SqSocket socket = getSocketOrPrimFail(socketID); + final SqSocket accepted = socket.accept(); + SOCKETS.put(accepted.handle(), accepted); + return accepted.handle(); + } catch (IOException e) { + error(e); + throw new PrimitiveFailed(); + } + } + } + + @GenerateNodeFactory + @SqueakPrimitive(names = "primitiveSocketCreate") + protected abstract static class PrimSocketCreateNode extends AbstractSocketPluginPrimitiveNode implements SenaryPrimitive { + protected PrimSocketCreateNode(final CompiledMethodObject method) { + super(method); + } + + @SuppressWarnings("unused") + @Specialization + protected final long doWork(final PointersObject receiver, + final long netType, + final long socketType, + final long rcvBufSize, + final long sendBufSize, + final long semaphoreIndex) { + error("TODO: primitiveSocketCreate"); + throw new PrimitiveFailed(); + } + + } + + @Override + public List> getFactories() { + return SocketPluginFactory.getFactories(); + } +} diff --git a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SqSocket.java b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SqSocket.java new file mode 100644 index 000000000..272c8677d --- /dev/null +++ b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SqSocket.java @@ -0,0 +1,205 @@ +package de.hpi.swa.graal.squeak.nodes.plugins.network; + +import de.hpi.swa.graal.squeak.exceptions.SqueakExceptions.SqueakException; +import de.hpi.swa.graal.squeak.image.SqueakImageContext; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.net.SocketOption; +import java.nio.ByteBuffer; +import java.nio.channels.NetworkChannel; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.util.Iterator; +import java.util.Set; + +abstract class SqSocket { + + enum Status { + InvalidSocket(-1), + Unconnected(0), + WaitingForConnection(1), + Connected(2), + OtherEndClosed(3), + ThisEndClosed(4); + + private long id; + + Status(final long id) { + this.id = id; + } + + long id() { + return id; + } + } + + enum Type { + TCP(0), + UDP(1); + + private long id; + + Type(final long id) { + this.id = id; + } + + static Type fromId(final long id) { + for (final Type type : values()) { + if (type.id == id) { + return type; + } + } + throw new SqueakException("Unknown SocketType: " + id); + } + } + + protected final long handle; + protected final boolean debug; + protected final SqueakImageContext image; + protected final Selector selector; + + protected boolean listening; + + protected SqSocket(final SqueakImageContext image, final boolean debug) throws IOException { + this.handle = System.identityHashCode(this); + this.debug = debug; + this.image = image; + this.selector = Selector.open(); + this.listening = false; + } + + protected void print(final String value) { + if (debug) { + image.getOutput().println(handle() + " " + value); + } + } + + protected long handle() { + return handle; + } + + protected abstract NetworkChannel asNetworkChannel(); + + protected abstract byte[] getLocalAddress() throws IOException; + + protected abstract long getLocalPort() throws IOException; + + protected abstract byte[] getRemoteAddress() throws IOException; + + protected abstract long getRemotePort() throws IOException; + + protected abstract Status getStatus() throws IOException; + + protected abstract void connectTo(String address, long port) throws IOException; + + protected abstract void listenOn(long port, long backlogSize) throws IOException; + + protected abstract SqSocket accept() throws IOException; + + protected abstract boolean isSendDone() throws IOException; + + protected long sendData(final ByteBuffer buffer) throws IOException { + selector.selectNow(); + final Iterator keys = selector.selectedKeys().iterator(); + while (keys.hasNext()) { + final SelectionKey key = keys.next(); + if (key.isWritable()) { + final long written = sendDataTo(buffer, key); + print("written: " + written); + keys.remove(); + return written; + } + } + + throw new IOException("No writable key found"); + } + + protected abstract long sendDataTo(ByteBuffer data, SelectionKey key) throws IOException; + + protected boolean isDataAvailable() throws IOException { + selector.selectNow(); + final Set keys = selector.selectedKeys(); + for (final SelectionKey key : keys) { + if (key.isReadable()) { + print("data available"); + return true; + } + } + + print("no data available"); + return false; + } + + protected long receiveData(final ByteBuffer buffer) throws IOException { + selector.selectNow(); + final Iterator keys = selector.selectedKeys().iterator(); + while (keys.hasNext()) { + final SelectionKey key = keys.next(); + + if (key.isReadable()) { + final long received = receiveDataFrom(key, buffer); + print("received: " + received); + keys.remove(); + return received; + } + } + return 0; + } + + protected abstract long receiveDataFrom(SelectionKey key, ByteBuffer data) throws IOException; + + protected boolean supportsOption(final String name) { + return asNetworkChannel().supportedOptions().stream().anyMatch(o -> o.name().equals(name)); + } + + protected String getOption(final String name) throws IOException { + final SocketOption option = socketOptionFromString(name); + final Object value = asNetworkChannel().getOption(option); + if (value instanceof Boolean) { + return ((boolean) value) ? "1" : "0"; + } + return String.valueOf(value); + } + + protected void setOption(final String name, final String value) throws IOException { + final Boolean enabled = value.equals("1"); + final SocketOption option = socketOptionFromString(name); + sneakySetOption(option, enabled); + } + + protected SocketOption socketOptionFromString(final String name) { + return asNetworkChannel().supportedOptions().stream().filter(o -> o.name().equals(name)).findFirst().orElseThrow(() -> new UnsupportedOperationException("Unknown socket option: " + name)); + } + + @SuppressWarnings("unchecked") + private void sneakySetOption(final SocketOption opt, final Object value) throws IOException { + asNetworkChannel().setOption(opt, (T) value); + } + + protected void close() throws IOException { + selector.close(); + } + + protected static InetSocketAddress castAddress(final SocketAddress address) { + if (address == null) { + return null; + } + + if (address instanceof InetSocketAddress) { + return (InetSocketAddress) address; + } + throw new SqueakException("Unknown address type"); + } + + protected static SqSocket create(final SqSocket.Type socketType, final SqueakImageContext image, final boolean debug) throws IOException { + switch (socketType) { + case TCP: + return new TCPSocket(image, debug); + case UDP: + return new UDPSocket(image, debug); + default: + throw new SqueakException("Unknown SocketType"); + } + } +} diff --git a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/TCPSocket.java b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/TCPSocket.java new file mode 100644 index 000000000..d0667346a --- /dev/null +++ b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/TCPSocket.java @@ -0,0 +1,208 @@ +package de.hpi.swa.graal.squeak.nodes.plugins.network; + +import de.hpi.swa.graal.squeak.image.SqueakImageContext; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.NetworkChannel; +import java.nio.channels.SelectionKey; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; +import java.util.Iterator; + +final class TCPSocket extends SqSocket { + + private SocketChannel clientChannel; + private ServerSocketChannel serverChannel; + + protected TCPSocket(final SqueakImageContext image, final boolean debug) throws IOException { + super(image, debug); + } + + private TCPSocket(final SqueakImageContext image, final boolean debug, final SocketChannel clientChannel) throws IOException { + super(image, debug); + this.clientChannel = clientChannel; + this.clientChannel.configureBlocking(false); + this.clientChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE); + } + + @Override + protected NetworkChannel asNetworkChannel() { + return listening ? serverChannel : clientChannel; + } + + @Override + protected byte[] getLocalAddress() throws IOException { + if (listening) { + return Resolver.getLoopbackAddress(); + } + + return castAddress(clientChannel.getLocalAddress()).getAddress().getAddress(); + } + + @Override + protected long getLocalPort() throws IOException { + final SocketAddress address = (listening ? serverChannel : clientChannel).getLocalAddress(); + return castAddress(address).getPort(); + } + + @Override + protected byte[] getRemoteAddress() throws IOException { + return listening ? getServerRemoteAddress() : getClientRemoteAddress(); + } + + private static byte[] getServerRemoteAddress() { + return Resolver.getAnyLocalAddress(); + } + + private byte[] getClientRemoteAddress() throws IOException { + if (clientChannel == null || !clientChannel.isConnected()) { + return Resolver.getAnyLocalAddress(); + } + + final SocketAddress address = clientChannel.getRemoteAddress(); + return castAddress(address).getAddress().getAddress(); + } + + @Override + protected long getRemotePort() throws IOException { + if (clientChannel != null && clientChannel.isConnected()) { + return castAddress(clientChannel.getRemoteAddress()).getPort(); + } + return 0L; + } + + @Override + protected Status getStatus() throws IOException { + if (selector.isOpen()) { + selector.selectNow(); + } + + final Status status = listening ? serverStatus() : clientStatus(); + print(status.name()); + return status; + } + + private Status serverStatus() throws IOException { + if (clientChannel != null) { + return Status.Connected; + } + + final Iterator keys = selector.selectedKeys().iterator(); + while (keys.hasNext()) { + if (keys.next().isAcceptable()) { + clientChannel = serverChannel.accept(); + clientChannel.configureBlocking(false); + clientChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE); + keys.remove(); + return Status.Connected; + } + } + + return Status.WaitingForConnection; + } + + private Status clientStatus() throws IOException { + if (clientChannel == null) { + return Status.Unconnected; + } + + maybeCompleteConnection(); + final Socket socket = clientChannel.socket(); + + if (socket.isInputShutdown()) { + return Status.OtherEndClosed; + } + + if (socket.isOutputShutdown()) { + return Status.ThisEndClosed; + } + + if (!socket.isConnected()) { + return Status.Unconnected; + } + + if (socket.isClosed()) { + return Status.ThisEndClosed; + } + + return Status.Connected; + } + + private void maybeCompleteConnection() throws IOException { + while (clientChannel.isConnectionPending()) { + clientChannel.finishConnect(); + } + } + + @Override + protected void connectTo(final String address, final long port) throws IOException { + clientChannel = SocketChannel.open(); + clientChannel.configureBlocking(false); + clientChannel.register(selector, SelectionKey.OP_CONNECT | SelectionKey.OP_WRITE | SelectionKey.OP_READ); + clientChannel.connect(new InetSocketAddress(address, (int) port)); + } + + @Override + protected void listenOn(final long port, final long backlogSize) throws IOException { + listening = true; + serverChannel = ServerSocketChannel.open(); + serverChannel.configureBlocking(false); + serverChannel.bind(new InetSocketAddress((int) port), (int) backlogSize); + serverChannel.register(selector, SelectionKey.OP_ACCEPT); + } + + @Override + protected SqSocket accept() throws IOException { + if (listening && clientChannel != null) { + clientChannel.keyFor(selector).cancel(); + final SqSocket created = new TCPSocket(image, debug, clientChannel); + clientChannel = null; + return created; + } + + return null; + } + + @Override + protected boolean isSendDone() throws IOException { + selector.selectNow(); + return selector.selectedKeys().stream().anyMatch(SelectionKey::isWritable); + } + + @Override + protected long sendDataTo(final ByteBuffer data, final SelectionKey key) throws IOException { + final SocketChannel channel = (SocketChannel) key.channel(); + if (!channel.isConnected()) { + throw new IOException("Client not connected"); + } + return channel.write(data); + } + + @Override + protected long receiveDataFrom(final SelectionKey key, final ByteBuffer data) throws IOException { + final SocketChannel channel = (SocketChannel) key.channel(); + final long read = channel.read(data); + + if (read == -1) { + channel.shutdownInput(); + key.cancel(); + return 0; + } + + return read; + } + + @Override + protected void close() throws IOException { + super.close(); + if (serverChannel != null) { + serverChannel.close(); + } + if (clientChannel != null) { + clientChannel.close(); + } + } +} diff --git a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/UDPSocket.java b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/UDPSocket.java new file mode 100644 index 000000000..039853a8a --- /dev/null +++ b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/UDPSocket.java @@ -0,0 +1,118 @@ +package de.hpi.swa.graal.squeak.nodes.plugins.network; + +import de.hpi.swa.graal.squeak.image.SqueakImageContext; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.DatagramChannel; +import java.nio.channels.NetworkChannel; +import java.nio.channels.SelectionKey; + +final class UDPSocket extends SqSocket { + + private final DatagramChannel channel; + + UDPSocket(final SqueakImageContext image, final boolean debug) throws IOException { + super(image, debug); + channel = DatagramChannel.open(); + channel.configureBlocking(false); + } + + @Override + protected NetworkChannel asNetworkChannel() { + return channel; + } + + @Override + protected byte[] getLocalAddress() throws IOException { + if (listening) { + return Resolver.getLoopbackAddress(); + } + + return castAddress(channel.getLocalAddress()).getAddress().getAddress(); + } + + @Override + protected long getLocalPort() throws IOException { + final SocketAddress address = channel.getLocalAddress(); + return castAddress(address).getPort(); + } + + @Override + protected byte[] getRemoteAddress() throws IOException { + final SocketAddress address = channel.getRemoteAddress(); + if (channel.isConnected()) { + return castAddress(address).getAddress().getAddress(); + } + return Resolver.getAnyLocalAddress(); + } + + @Override + protected long getRemotePort() throws IOException { + if (listening) { + return 0L; + } + + if (channel.isConnected()) { + return castAddress(channel.getRemoteAddress()).getPort(); + } + + return 0L; + } + + @Override + protected Status getStatus() { + if (listening) { + return Status.WaitingForConnection; + } + + if (channel.isConnected()) { + return Status.Connected; + } + + return Status.Unconnected; + } + + @Override + protected void connectTo(final String address, final long port) throws IOException { + channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE); + channel.connect(new InetSocketAddress(address, (int) port)); + } + + @Override + protected void listenOn(final long port, final long backlogSize) throws IOException { + listening = true; + channel.bind(new InetSocketAddress((int) port)); + channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE); + } + + @Override + protected SqSocket accept() { + throw new UnsupportedOperationException("accept() on UDP socket"); + } + + @Override + protected boolean isSendDone() { + return true; + } + + @Override + protected long sendDataTo(final ByteBuffer data, final SelectionKey key) throws IOException { + final DatagramChannel to = (DatagramChannel) key.channel(); + return to.send(data, to.getRemoteAddress()); + } + + @Override + protected long receiveDataFrom(final SelectionKey key, final ByteBuffer data) throws IOException { + final DatagramChannel from = (DatagramChannel) key.channel(); + from.receive(data); + return data.position(); + } + + @Override + protected void close() throws IOException { + super.close(); + channel.close(); + } +} diff --git a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/primitives/PrimitiveNodeFactory.java b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/primitives/PrimitiveNodeFactory.java index 89c7c202f..541a3115c 100644 --- a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/primitives/PrimitiveNodeFactory.java +++ b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/primitives/PrimitiveNodeFactory.java @@ -25,7 +25,7 @@ import de.hpi.swa.graal.squeak.nodes.plugins.Matrix2x3Plugin; import de.hpi.swa.graal.squeak.nodes.plugins.MiscPrimitivePlugin; import de.hpi.swa.graal.squeak.nodes.plugins.PolyglotPlugin; -import de.hpi.swa.graal.squeak.nodes.plugins.SocketPlugin; +import de.hpi.swa.graal.squeak.nodes.plugins.network.SocketPlugin; import de.hpi.swa.graal.squeak.nodes.plugins.SqueakFFIPrims; import de.hpi.swa.graal.squeak.nodes.plugins.SqueakSSL; import de.hpi.swa.graal.squeak.nodes.plugins.UUIDPlugin; From 57a49b2a278509ecbc7297605e5ef15f6bc420f9 Mon Sep 17 00:00:00 2001 From: Falco Duersch Date: Mon, 28 Jan 2019 13:44:28 +0100 Subject: [PATCH 2/9] Bring back patched test timeout and enable WebClientServerTest --- .../test/AbstractSqueakTestCaseWithImage.java | 4 +- .../swa/graal/squeak/test/tests.properties | 148 +++++++++--------- 2 files changed, 80 insertions(+), 72 deletions(-) diff --git a/src/de.hpi.swa.graal.squeak.test/src/de/hpi/swa/graal/squeak/test/AbstractSqueakTestCaseWithImage.java b/src/de.hpi.swa.graal.squeak.test/src/de/hpi/swa/graal/squeak/test/AbstractSqueakTestCaseWithImage.java index 13662e9f6..3ae4c3acd 100644 --- a/src/de.hpi.swa.graal.squeak.test/src/de/hpi/swa/graal/squeak/test/AbstractSqueakTestCaseWithImage.java +++ b/src/de.hpi.swa.graal.squeak.test/src/de/hpi/swa/graal/squeak/test/AbstractSqueakTestCaseWithImage.java @@ -30,7 +30,7 @@ import de.hpi.swa.graal.squeak.nodes.process.GetActiveProcessNode; public class AbstractSqueakTestCaseWithImage extends AbstractSqueakTestCase { - private static final int TIMEOUT_SECONDS = 50; + private static final int TIMEOUT_SECONDS = 60; private static final int PRIORITY_10_LIST_INDEX = 9; private static PointersObject idleProcess; @@ -66,6 +66,8 @@ private static void patchImageForTesting() { evaluate("Utilities setAuthorInitials: 'GraalSqueak'"); image.getOutput().println("Initializing fresh MorphicUIManager..."); evaluate("Project current instVarNamed: #uiManager put: MorphicUIManager new"); + image.getOutput().println("Increasing default timeout..."); + patchMethod("TestCase", "defaultTimeout", "defaultTimeout ^ " + TIMEOUT_SECONDS); if (!runsOnMXGate()) { // Patch TestCase>>#performTest, so errors are printed to stderr for debugging purposes. patchMethod("TestCase", "performTest", "performTest [self perform: testSelector asSymbol] on: Error do: [:e | e printVerboseOn: FileStream stderr. e signal]"); diff --git a/src/de.hpi.swa.graal.squeak.test/src/de/hpi/swa/graal/squeak/test/tests.properties b/src/de.hpi.swa.graal.squeak.test/src/de/hpi/swa/graal/squeak/test/tests.properties index 64aa44a12..9ff508827 100644 --- a/src/de.hpi.swa.graal.squeak.test/src/de/hpi/swa/graal/squeak/test/tests.properties +++ b/src/de.hpi.swa.graal.squeak.test/src/de/hpi/swa/graal/squeak/test/tests.properties @@ -3836,7 +3836,10 @@ SUnitTest>>testResult=passing SUnitTest>>testRunning=passing SUnitTest>>testShould=passing SUnitTest>>testSuite=passing -SUnitTest>>testTestTimeout=passing + +# We dynamically adjust the test timeout for longer running tests. +SUnitTest>>testTestTimeout=ignored + SUnitTest>>testTestTimeoutLoop=not_terminating SUnitTest>>testTestTimeoutTag=passing SUnitTest>>testWithExceptionDo=passing @@ -4773,76 +4776,79 @@ WeakSetTest>>testIncludes=passing WeakSetTest>>testIncludesNil=passing WeakSetTest>>testNew=passing WeakSetTest>>testUnCategorizedMethods=passing -WebClientServerTest>>testArrays=flaky -WebClientServerTest>>testAuthException=flaky -WebClientServerTest>>testAuthRedirectSession=flaky -WebClientServerTest>>testBasicAuth=flaky -WebClientServerTest>>testBerarerAuth=flaky -WebClientServerTest>>testChunkedLoopback=flaky -WebClientServerTest>>testChunkedLoopbackWithStream=flaky -WebClientServerTest>>testChunkedRequest=flaky -WebClientServerTest>>testChunkedResponse=flaky -WebClientServerTest>>testContentEncodingGZip=flaky -WebClientServerTest>>testContentTypeCharsetEncoding=flaky -WebClientServerTest>>testCookieDomainRules=flaky -WebClientServerTest>>testCookieExpiryParsing=flaky -WebClientServerTest>>testCookieParsing=flaky -WebClientServerTest>>testCookies=flaky -WebClientServerTest>>testDecodeWebSocketKey=flaky -WebClientServerTest>>testDefault404=flaky -WebClientServerTest>>testDictionaries=flaky -WebClientServerTest>>testDigestAuth=flaky -WebClientServerTest>>testDuplicateCookies=flaky -WebClientServerTest>>testGetFields=flaky -WebClientServerTest>>testHmacSha1=flaky -WebClientServerTest>>testHtmlSubmit=flaky -WebClientServerTest>>testHttpDelete=flaky -WebClientServerTest>>testHttpHead=flaky -WebClientServerTest>>testHttpOptions=flaky -WebClientServerTest>>testHttpTrace=flaky -WebClientServerTest>>testInvalidCookies=flaky -WebClientServerTest>>testListenOnInterface=flaky -WebClientServerTest>>testLogging200=flaky -WebClientServerTest>>testLogging404=flaky -WebClientServerTest>>testMD5Digest=flaky -WebClientServerTest>>testMultipartFields=flaky -WebClientServerTest>>testMultipartFiles=flaky -WebClientServerTest>>testMultipartFiles2=flaky -WebClientServerTest>>testNestedAction=flaky -WebClientServerTest>>testNilTrueFalse=flaky -WebClientServerTest>>testNo302Redirect=flaky -WebClientServerTest>>testNumbers=flaky -WebClientServerTest>>testPersistentAuthRedirectSession=flaky -WebClientServerTest>>testPostFields=flaky -WebClientServerTest>>testRedirect=flaky -WebClientServerTest>>testRedirectLoop=flaky -WebClientServerTest>>testRedirectTrailingSlash=flaky -WebClientServerTest>>testResponseUrl=flaky -WebClientServerTest>>testSchemeHandling=flaky -WebClientServerTest>>testServerDestroy=flaky -WebClientServerTest>>testServerError=flaky -WebClientServerTest>>testServerNameAndPort=flaky -WebClientServerTest>>testServerRegistry=flaky -WebClientServerTest>>testSignOAuthGet=flaky -WebClientServerTest>>testSignOAuthGetDupFields=flaky -WebClientServerTest>>testSignOAuthGetFields=flaky -WebClientServerTest>>testSignOAuthPostFields=flaky -WebClientServerTest>>testSignOAuthUrlEncoding=flaky -WebClientServerTest>>testSimpleServerAction=flaky -WebClientServerTest>>testStreaming=flaky -WebClientServerTest>>testStrings=flaky -WebClientServerTest>>testTransientPostContent=flaky -WebClientServerTest>>testUrlEncoding=flaky -WebClientServerTest>>testWebSocketHash07=flaky -WebClientServerTest>>testWebSockets=flaky -WebClientServerTest>>testWebSockets00=flaky -WebClientServerTest>>testWebSockets07=flaky -WebClientServerTest>>testWebSockets07ControlDecode=flaky -WebClientServerTest>>testWebSockets07ControlInterleave=flaky -WebClientServerTest>>testWebSockets07DataDecode=flaky -WebClientServerTest>>testWebSockets07NoMask=flaky -WebClientServerTest>>testWebSockets68=flaky -WebClientServerTest>>testWebSocketsFraming=flaky + +WebClientServerTest>>testArrays=slowly_passing +WebClientServerTest>>testAuthException=slowly_passing +WebClientServerTest>>testAuthRedirectSession=slowly_passing +WebClientServerTest>>testBasicAuth=slowly_passing +WebClientServerTest>>testBerarerAuth=slowly_passing +WebClientServerTest>>testChunkedLoopback=slowly_passing +WebClientServerTest>>testChunkedLoopbackWithStream=slowly_passing +WebClientServerTest>>testChunkedRequest=slowly_passing +WebClientServerTest>>testChunkedResponse=slowly_passing +WebClientServerTest>>testContentEncodingGZip=slowly_passing +WebClientServerTest>>testContentTypeCharsetEncoding=slowly_passing +WebClientServerTest>>testCookieDomainRules=slowly_passing +WebClientServerTest>>testCookieExpiryParsing=slowly_passing +WebClientServerTest>>testCookieParsing=slowly_passing +WebClientServerTest>>testCookies=slowly_passing +WebClientServerTest>>testDecodeWebSocketKey=slowly_passing +WebClientServerTest>>testDefault404=slowly_passing +WebClientServerTest>>testDictionaries=slowly_passing +WebClientServerTest>>testDigestAuth=slowly_passing +WebClientServerTest>>testDuplicateCookies=slowly_passing +WebClientServerTest>>testGetFields=slowly_passing +WebClientServerTest>>testHmacSha1=slowly_passing +WebClientServerTest>>testHtmlSubmit=slowly_passing +WebClientServerTest>>testHttpDelete=slowly_passing +WebClientServerTest>>testHttpHead=slowly_passing +WebClientServerTest>>testHttpOptions=slowly_passing +WebClientServerTest>>testHttpTrace=slowly_passing +WebClientServerTest>>testInvalidCookies=slowly_passing +WebClientServerTest>>testListenOnInterface=slowly_passing +WebClientServerTest>>testLogging200=slowly_passing +WebClientServerTest>>testLogging404=slowly_passing +WebClientServerTest>>testMD5Digest=slowly_passing +WebClientServerTest>>testMultipartFields=slowly_passing +WebClientServerTest>>testMultipartFiles=slowly_passing +WebClientServerTest>>testMultipartFiles2=slowly_passing +WebClientServerTest>>testNestedAction=slowly_passing +WebClientServerTest>>testNilTrueFalse=slowly_passing +WebClientServerTest>>testNo302Redirect=slowly_passing +WebClientServerTest>>testNumbers=slowly_passing +WebClientServerTest>>testPersistentAuthRedirectSession=slowly_passing +WebClientServerTest>>testPostFields=slowly_passing +WebClientServerTest>>testRedirect=slowly_passing +WebClientServerTest>>testRedirectLoop=slowly_passing +WebClientServerTest>>testRedirectTrailingSlash=slowly_passing +WebClientServerTest>>testResponseUrl=slowly_passing +WebClientServerTest>>testSchemeHandling=slowly_passing +WebClientServerTest>>testServerDestroy=slowly_passing +WebClientServerTest>>testServerError=slowly_passing +WebClientServerTest>>testServerNameAndPort=slowly_passing +WebClientServerTest>>testServerRegistry=slowly_passing +WebClientServerTest>>testSignOAuthGet=slowly_passing +WebClientServerTest>>testSignOAuthGetDupFields=slowly_passing +WebClientServerTest>>testSignOAuthGetFields=slowly_passing +WebClientServerTest>>testSignOAuthPostFields=slowly_passing +WebClientServerTest>>testSignOAuthUrlEncoding=slowly_passing +WebClientServerTest>>testSimpleServerAction=slowly_passing +WebClientServerTest>>testStreaming=slowly_passing +WebClientServerTest>>testStrings=slowly_passing +WebClientServerTest>>testTransientPostContent=slowly_passing +WebClientServerTest>>testUrlEncoding=slowly_passing + +WebClientServerTest>>testWebSocketHash07=passing +WebClientServerTest>>testWebSockets=not_terminating +WebClientServerTest>>testWebSockets00=not_terminating +WebClientServerTest>>testWebSockets07=not_terminating +WebClientServerTest>>testWebSockets07ControlDecode=not_terminating +WebClientServerTest>>testWebSockets07ControlInterleave=not_terminating +WebClientServerTest>>testWebSockets07DataDecode=not_terminating +WebClientServerTest>>testWebSockets07NoMask=not_terminating +WebClientServerTest>>testWebSockets68=not_terminating +WebClientServerTest>>testWebSocketsFraming=not_terminating + WeekTest>>testClassComment=passing WeekTest>>testCoverage=passing WeekTest>>testDayNames=passing From 805f9ab23c6c8f6b98109cd0983be980ce237b20 Mon Sep 17 00:00:00 2001 From: Falco Duersch Date: Mon, 28 Jan 2019 13:45:33 +0100 Subject: [PATCH 3/9] fixup! Refactor socket plugin to NIO Use TruffleLogger --- .../nodes/plugins/network/SocketPlugin.java | 2 +- .../nodes/plugins/network/SqSocket.java | 31 +++++++------------ .../nodes/plugins/network/TCPSocket.java | 17 +++++----- .../nodes/plugins/network/UDPSocket.java | 5 ++- 4 files changed, 25 insertions(+), 30 deletions(-) diff --git a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SocketPlugin.java b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SocketPlugin.java index da03164f1..3c96a93dc 100644 --- a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SocketPlugin.java +++ b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SocketPlugin.java @@ -642,7 +642,7 @@ protected final long doWork(final PointersObject receiver, try { final SqSocket.Type type = SqSocket.Type.fromId(socketType); - final SqSocket socket = SqSocket.create(type, code.image, debugPrints); + final SqSocket socket = SqSocket.create(type); SOCKETS.put(socket.handle(), socket); return socket.handle(); } catch (final IOException e) { diff --git a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SqSocket.java b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SqSocket.java index 272c8677d..5b65b5d8b 100644 --- a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SqSocket.java +++ b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SqSocket.java @@ -1,7 +1,8 @@ package de.hpi.swa.graal.squeak.nodes.plugins.network; +import com.oracle.truffle.api.TruffleLogger; import de.hpi.swa.graal.squeak.exceptions.SqueakExceptions.SqueakException; -import de.hpi.swa.graal.squeak.image.SqueakImageContext; +import de.hpi.swa.graal.squeak.shared.SqueakLanguageConfig; import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; @@ -54,27 +55,19 @@ static Type fromId(final long id) { } } + private static final TruffleLogger LOG = TruffleLogger.getLogger(SqueakLanguageConfig.ID, SqSocket.class); + protected final long handle; - protected final boolean debug; - protected final SqueakImageContext image; protected final Selector selector; protected boolean listening; - protected SqSocket(final SqueakImageContext image, final boolean debug) throws IOException { + protected SqSocket() throws IOException { this.handle = System.identityHashCode(this); - this.debug = debug; - this.image = image; this.selector = Selector.open(); this.listening = false; } - protected void print(final String value) { - if (debug) { - image.getOutput().println(handle() + " " + value); - } - } - protected long handle() { return handle; } @@ -106,7 +99,7 @@ protected long sendData(final ByteBuffer buffer) throws IOException { final SelectionKey key = keys.next(); if (key.isWritable()) { final long written = sendDataTo(buffer, key); - print("written: " + written); + LOG.finer(() -> handle + " written: " + written); keys.remove(); return written; } @@ -122,12 +115,12 @@ protected boolean isDataAvailable() throws IOException { final Set keys = selector.selectedKeys(); for (final SelectionKey key : keys) { if (key.isReadable()) { - print("data available"); + LOG.finer(() -> handle + " data available"); return true; } } - print("no data available"); + LOG.finer(() -> handle + " no data available"); return false; } @@ -139,7 +132,7 @@ protected long receiveData(final ByteBuffer buffer) throws IOException { if (key.isReadable()) { final long received = receiveDataFrom(key, buffer); - print("received: " + received); + LOG.finer(() -> handle + " received: " + received); keys.remove(); return received; } @@ -192,12 +185,12 @@ protected static InetSocketAddress castAddress(final SocketAddress address) { throw new SqueakException("Unknown address type"); } - protected static SqSocket create(final SqSocket.Type socketType, final SqueakImageContext image, final boolean debug) throws IOException { + protected static SqSocket create(final SqSocket.Type socketType) throws IOException { switch (socketType) { case TCP: - return new TCPSocket(image, debug); + return new TCPSocket(); case UDP: - return new UDPSocket(image, debug); + return new UDPSocket(); default: throw new SqueakException("Unknown SocketType"); } diff --git a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/TCPSocket.java b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/TCPSocket.java index d0667346a..70bb90d62 100644 --- a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/TCPSocket.java +++ b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/TCPSocket.java @@ -1,6 +1,7 @@ package de.hpi.swa.graal.squeak.nodes.plugins.network; -import de.hpi.swa.graal.squeak.image.SqueakImageContext; +import com.oracle.truffle.api.TruffleLogger; +import de.hpi.swa.graal.squeak.shared.SqueakLanguageConfig; import java.io.IOException; import java.net.InetSocketAddress; import java.net.Socket; @@ -14,15 +15,17 @@ final class TCPSocket extends SqSocket { + private static final TruffleLogger LOG = TruffleLogger.getLogger(SqueakLanguageConfig.ID, TCPSocket.class); + private SocketChannel clientChannel; private ServerSocketChannel serverChannel; - protected TCPSocket(final SqueakImageContext image, final boolean debug) throws IOException { - super(image, debug); + protected TCPSocket() throws IOException { + super(); } - private TCPSocket(final SqueakImageContext image, final boolean debug, final SocketChannel clientChannel) throws IOException { - super(image, debug); + private TCPSocket(final SocketChannel clientChannel) throws IOException { + super(); this.clientChannel = clientChannel; this.clientChannel.configureBlocking(false); this.clientChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE); @@ -81,7 +84,7 @@ protected Status getStatus() throws IOException { } final Status status = listening ? serverStatus() : clientStatus(); - print(status.name()); + LOG.finer(() -> handle + " " + status); return status; } @@ -158,7 +161,7 @@ protected void listenOn(final long port, final long backlogSize) throws IOExcept protected SqSocket accept() throws IOException { if (listening && clientChannel != null) { clientChannel.keyFor(selector).cancel(); - final SqSocket created = new TCPSocket(image, debug, clientChannel); + final SqSocket created = new TCPSocket(clientChannel); clientChannel = null; return created; } diff --git a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/UDPSocket.java b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/UDPSocket.java index 039853a8a..58406c54d 100644 --- a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/UDPSocket.java +++ b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/UDPSocket.java @@ -1,6 +1,5 @@ package de.hpi.swa.graal.squeak.nodes.plugins.network; -import de.hpi.swa.graal.squeak.image.SqueakImageContext; import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; @@ -13,8 +12,8 @@ final class UDPSocket extends SqSocket { private final DatagramChannel channel; - UDPSocket(final SqueakImageContext image, final boolean debug) throws IOException { - super(image, debug); + UDPSocket() throws IOException { + super(); channel = DatagramChannel.open(); channel.configureBlocking(false); } From ce20875583357639a22bbcf63097ef2205876af7 Mon Sep 17 00:00:00 2001 From: Falco Duersch Date: Mon, 28 Jan 2019 14:09:45 +0100 Subject: [PATCH 4/9] fixup! Refactor socket plugin to NIO Use TruffleLogger in SocketPlugin --- .../nodes/plugins/network/SocketPlugin.java | 152 ++++++++---------- 1 file changed, 70 insertions(+), 82 deletions(-) diff --git a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SocketPlugin.java b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SocketPlugin.java index 3c96a93dc..820dc828c 100644 --- a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SocketPlugin.java +++ b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SocketPlugin.java @@ -1,11 +1,15 @@ package de.hpi.swa.graal.squeak.nodes.plugins.network; +import com.oracle.truffle.api.TruffleLogger; +import de.hpi.swa.graal.squeak.SqueakLanguage; import de.hpi.swa.graal.squeak.model.ArrayObject; +import de.hpi.swa.graal.squeak.shared.SqueakLanguageConfig; import java.io.IOException; import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.util.List; +import java.util.logging.Level; import org.graalvm.collections.EconomicMap; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; @@ -32,29 +36,12 @@ public final class SocketPlugin extends AbstractPrimitiveFactoryHolder { + private static final TruffleLogger LOG = TruffleLogger.getLogger(SqueakLanguageConfig.ID, SocketPlugin.class); private static final EconomicMap SOCKETS = EconomicMap.create(); - private static final boolean debugPrints = false; - - protected abstract static class AbstractSocketPluginPrimitiveNode extends AbstractPrimitiveNode { - - protected AbstractSocketPluginPrimitiveNode(final CompiledMethodObject method) { - super(method); - } - - protected final void error(final Object o) { - code.image.printToStdErr(o); - } - - protected final void print(final Object o) { - if (debugPrints) { - code.image.printToStdOut(o); - } - } - } @GenerateNodeFactory @SqueakPrimitive(names = "primitiveResolverStatus") - protected abstract static class PrimResolverStatusNode extends AbstractSocketPluginPrimitiveNode implements UnaryPrimitive { + protected abstract static class PrimResolverStatusNode extends AbstractPrimitiveNode implements UnaryPrimitive { protected PrimResolverStatusNode(final CompiledMethodObject method) { super(method); } @@ -67,7 +54,7 @@ protected static long doWork(@SuppressWarnings("unused") final AbstractSqueakObj @GenerateNodeFactory @SqueakPrimitive(names = "primitiveInitializeNetwork") - protected abstract static class PrimInitializeNetworkNode extends AbstractSocketPluginPrimitiveNode implements UnaryPrimitive { + protected abstract static class PrimInitializeNetworkNode extends AbstractPrimitiveNode implements UnaryPrimitive { protected PrimInitializeNetworkNode(final CompiledMethodObject method) { super(method); } @@ -89,7 +76,7 @@ private static SqSocket getSocketOrPrimFail(final long socketHandle) { @GenerateNodeFactory @SqueakPrimitive(names = "primitiveResolverStartNameLookup") - protected abstract static class PrimResolverStartNameLookupNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { + protected abstract static class PrimResolverStartNameLookupNode extends AbstractPrimitiveNode implements BinaryPrimitive { protected PrimResolverStartNameLookupNode(final CompiledMethodObject method) { super(method); } @@ -103,10 +90,10 @@ protected PrimResolverStartNameLookupNode(final CompiledMethodObject method) { @TruffleBoundary protected final Object doWork(final Object receiver, final NativeObject hostName) { try { - print(">> Starting lookup for host name " + hostName); + LOG.finer(() -> "Starting lookup for host name " + hostName); Resolver.startHostNameLookUp(hostName.asString()); } catch (final UnknownHostException e) { - error(e); + LOG.log(Level.FINE, "Host name lookup failed", e); } return receiver; } @@ -114,7 +101,7 @@ protected final Object doWork(final Object receiver, final NativeObject hostName @GenerateNodeFactory @SqueakPrimitive(names = "primitiveResolverStartAddressLookup") - protected abstract static class PrimResolverStartAddressLookupNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { + protected abstract static class PrimResolverStartAddressLookupNode extends AbstractPrimitiveNode implements BinaryPrimitive { protected PrimResolverStartAddressLookupNode(final CompiledMethodObject method) { super(method); @@ -129,10 +116,10 @@ protected PrimResolverStartAddressLookupNode(final CompiledMethodObject method) @TruffleBoundary protected final Object doWork(final Object receiver, final NativeObject address) { try { - print("Starting lookup for address " + address); + LOG.finer(() -> "Starting lookup for address " + address); Resolver.startAddressLookUp(address.getByteStorage()); } catch (final UnknownHostException e) { - error(e); + LOG.log(Level.FINE, "Address lookup failed", e); } return receiver; } @@ -140,7 +127,7 @@ protected final Object doWork(final Object receiver, final NativeObject address) @GenerateNodeFactory @SqueakPrimitive(names = "primitiveResolverNameLookupResult") - protected abstract static class PrimResolverNameLookupResultNode extends AbstractSocketPluginPrimitiveNode implements UnaryPrimitive { + protected abstract static class PrimResolverNameLookupResultNode extends AbstractPrimitiveNode implements UnaryPrimitive { protected PrimResolverNameLookupResultNode(final CompiledMethodObject method) { super(method); @@ -155,14 +142,14 @@ protected PrimResolverNameLookupResultNode(final CompiledMethodObject method) { protected final AbstractSqueakObject doWork( @SuppressWarnings("unused") final AbstractSqueakObject receiver) { final byte[] lastNameLookup = Resolver.lastHostNameLookupResult(); - print(">> Name Lookup Result: " + Resolver.addressBytesToString(lastNameLookup)); + LOG.finer(() -> "Name Lookup Result: " + Resolver.addressBytesToString(lastNameLookup)); return lastNameLookup == null ? code.image.nil : code.image.wrap(lastNameLookup); } } @GenerateNodeFactory @SqueakPrimitive(names = "primitiveResolverAddressLookupResult") - protected abstract static class PrimResolverAddressLookupResultNode extends AbstractSocketPluginPrimitiveNode implements UnaryPrimitive { + protected abstract static class PrimResolverAddressLookupResultNode extends AbstractPrimitiveNode implements UnaryPrimitive { protected PrimResolverAddressLookupResultNode(final CompiledMethodObject method) { super(method); } @@ -174,14 +161,14 @@ protected PrimResolverAddressLookupResultNode(final CompiledMethodObject method) @Specialization protected final AbstractSqueakObject doWork(@SuppressWarnings("unused") final AbstractSqueakObject receiver) { final String lastAddressLookup = Resolver.lastAddressLookUpResult(); - print(">> Address Lookup Result: " + lastAddressLookup); + LOG.finer(() -> ">> Address Lookup Result: " + lastAddressLookup); return lastAddressLookup == null ? code.image.nil : code.image.wrap(lastAddressLookup); } } @GenerateNodeFactory @SqueakPrimitive(names = "primitiveResolverLocalAddress") - protected abstract static class PrimResolverLocalAddressNode extends AbstractSocketPluginPrimitiveNode implements UnaryPrimitive { + protected abstract static class PrimResolverLocalAddressNode extends AbstractPrimitiveNode implements UnaryPrimitive { protected PrimResolverLocalAddressNode(final CompiledMethodObject method) { super(method); } @@ -190,14 +177,14 @@ protected PrimResolverLocalAddressNode(final CompiledMethodObject method) { @TruffleBoundary protected final AbstractSqueakObject doWork(@SuppressWarnings("unused") final AbstractSqueakObject receiver) { final byte[] address = Resolver.getLoopbackAddress(); - print(">> Local Address: " + Resolver.addressBytesToString(address)); + LOG.finer(() -> "Local Address: " + Resolver.addressBytesToString(address)); return code.image.wrap(address); } } @GenerateNodeFactory @SqueakPrimitive(names = "primitiveSocketLocalPort") - protected abstract static class PrimSocketLocalPortNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { + protected abstract static class PrimSocketLocalPortNode extends AbstractPrimitiveNode implements BinaryPrimitive { protected PrimSocketLocalPortNode(final CompiledMethodObject method) { super(method); } @@ -209,7 +196,7 @@ protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObje try { return getSocketOrPrimFail(socketID).getLocalPort(); } catch (final IOException e) { - error(e); + LOG.log(Level.FINE, "Retrieving local port failed", e); throw new PrimitiveFailed(); } } @@ -217,7 +204,7 @@ protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObje @GenerateNodeFactory @SqueakPrimitive(names = "primitiveSocketListenWithOrWithoutBacklog") - protected abstract static class PrimSocketListenWithOrWithoutBacklogNode extends AbstractSocketPluginPrimitiveNode implements QuaternaryPrimitive { + protected abstract static class PrimSocketListenWithOrWithoutBacklogNode extends AbstractPrimitiveNode implements QuaternaryPrimitive { protected PrimSocketListenWithOrWithoutBacklogNode(final CompiledMethodObject method) { super(method); } @@ -235,8 +222,8 @@ protected final AbstractSqueakObject doWork(final AbstractSqueakObject receiver, try { getSocketOrPrimFail(socketID).listenOn(port, 0L); return receiver; - } catch (IOException e) { - error(e); + } catch (final IOException e) { + LOG.log(Level.FINE, "Listen failed", e); throw new PrimitiveFailed(); } } @@ -254,8 +241,8 @@ protected final AbstractSqueakObject doWork(final AbstractSqueakObject receiver, try { getSocketOrPrimFail(socketID).listenOn(port, backlogSize); return receiver; - } catch (IOException e) { - error(e); + } catch (final IOException e) { + LOG.log(Level.FINE, "Listen failed", e); throw new PrimitiveFailed(); } } @@ -263,7 +250,7 @@ protected final AbstractSqueakObject doWork(final AbstractSqueakObject receiver, @GenerateNodeFactory @SqueakPrimitive(names = "primitiveSocketListenOnPortBacklogInterface") - protected abstract static class PrimSocketListenOnPortBacklogInterfaceNode extends AbstractSocketPluginPrimitiveNode implements QuinaryPrimitive { + protected abstract static class PrimSocketListenOnPortBacklogInterfaceNode extends AbstractPrimitiveNode implements QuinaryPrimitive { protected PrimSocketListenOnPortBacklogInterfaceNode(final CompiledMethodObject method) { super(method); } @@ -282,8 +269,8 @@ protected final AbstractSqueakObject doWork(final AbstractSqueakObject receiver, try { getSocketOrPrimFail(socketID).listenOn(port, backlogSize); return receiver; - } catch (IOException e) { - error(e); + } catch (final IOException e) { + LOG.log(Level.FINE, "Listen failed", e); throw new PrimitiveFailed(); } } @@ -291,7 +278,7 @@ protected final AbstractSqueakObject doWork(final AbstractSqueakObject receiver, @GenerateNodeFactory @SqueakPrimitive(names = "primitiveSocketSetOptions") - protected abstract static class PrimSocketSetOptionsNode extends AbstractSocketPluginPrimitiveNode implements QuaternaryPrimitive { + protected abstract static class PrimSocketSetOptionsNode extends AbstractPrimitiveNode implements QuaternaryPrimitive { protected PrimSocketSetOptionsNode(final CompiledMethodObject method) { super(method); } @@ -303,7 +290,7 @@ protected final ArrayObject doWork(@SuppressWarnings("unused") final AbstractSqu final SqSocket socket = getSocketOrPrimFail(socketID); return setSocketOption(socket, option.asString(), value.asString()); } catch (final IOException e) { - error(e); + LOG.log(Level.FINE, "Set socket option failed", e); throw new PrimitiveFailed(); } } @@ -320,7 +307,7 @@ private ArrayObject setSocketOption(final SqSocket socket, final String option, @GenerateNodeFactory @SqueakPrimitive(names = "primitiveSocketConnectToPort") - protected abstract static class PrimSocketConnectToPortNode extends AbstractSocketPluginPrimitiveNode implements QuaternaryPrimitive { + protected abstract static class PrimSocketConnectToPortNode extends AbstractPrimitiveNode implements QuaternaryPrimitive { protected PrimSocketConnectToPortNode(final CompiledMethodObject method) { super(method); } @@ -333,7 +320,7 @@ protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObje final String host = Resolver.addressBytesToString(hostAddress.getByteStorage()); socket.connectTo(host, (int) port); } catch (final IOException e) { - error(e); + LOG.log(Level.FINE, "Socket connect failed", e); throw new PrimitiveFailed(); } return 0; @@ -342,7 +329,7 @@ protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObje @GenerateNodeFactory @SqueakPrimitive(names = "primitiveSocketConnectionStatus") - protected abstract static class PrimSocketConnectionStatusNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { + protected abstract static class PrimSocketConnectionStatusNode extends AbstractPrimitiveNode implements BinaryPrimitive { protected PrimSocketConnectionStatusNode(final CompiledMethodObject method) { super(method); } @@ -357,8 +344,8 @@ protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObje try { final SqSocket socket = getSocketOrPrimFail(socketID); return socket.getStatus().id(); - } catch (IOException e) { - error(e); + } catch (final IOException e) { + LOG.log(Level.FINE, "Retrieving socket status failed", e); throw new PrimitiveFailed(); } } @@ -366,7 +353,7 @@ protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObje @GenerateNodeFactory @SqueakPrimitive(names = "primitiveSocketRemoteAddress") - protected abstract static class PrimSocketRemoteAddressNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { + protected abstract static class PrimSocketRemoteAddressNode extends AbstractPrimitiveNode implements BinaryPrimitive { protected PrimSocketRemoteAddressNode(final CompiledMethodObject method) { super(method); } @@ -377,7 +364,7 @@ protected final AbstractSqueakObject doWork(@SuppressWarnings("unused") final Ab try { return code.image.wrap(getSocketOrPrimFail(socketID).getRemoteAddress()); } catch (final IOException e) { - error(e); + LOG.log(Level.FINE, "Retrieving remote address failed", e); throw new PrimitiveFailed(); } } @@ -385,7 +372,7 @@ protected final AbstractSqueakObject doWork(@SuppressWarnings("unused") final Ab @GenerateNodeFactory @SqueakPrimitive(names = "primitiveSocketRemotePort") - protected abstract static class PrimSocketRemotePortNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { + protected abstract static class PrimSocketRemotePortNode extends AbstractPrimitiveNode implements BinaryPrimitive { protected PrimSocketRemotePortNode(final CompiledMethodObject method) { super(method); } @@ -396,7 +383,7 @@ protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObje try { return getSocketOrPrimFail(socketID).getRemotePort(); } catch (final IOException e) { - error(e); + LOG.log(Level.FINE, "Retrieving remote port failed", e); throw new PrimitiveFailed(); } } @@ -404,7 +391,7 @@ protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObje @GenerateNodeFactory @SqueakPrimitive(names = "primitiveSocketGetOptions") - protected abstract static class PrimSocketGetOptionsNode extends AbstractSocketPluginPrimitiveNode implements TernaryPrimitive { + protected abstract static class PrimSocketGetOptionsNode extends AbstractPrimitiveNode implements TernaryPrimitive { protected PrimSocketGetOptionsNode(final CompiledMethodObject method) { super(method); } @@ -423,7 +410,7 @@ protected final Object doWork(@SuppressWarnings("unused") final AbstractSqueakOb final String value = socket.getOption(option.asString()); return code.image.wrap(0, value); } catch (final IOException e) { - error(e); + LOG.log(Level.FINE, "Retrieving socket option failed", e); throw new PrimitiveFailed(); } } @@ -431,7 +418,7 @@ protected final Object doWork(@SuppressWarnings("unused") final AbstractSqueakOb @GenerateNodeFactory @SqueakPrimitive(names = "primitiveSocketReceiveDataAvailable") - protected abstract static class PrimSocketReceiveDataAvailableNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { + protected abstract static class PrimSocketReceiveDataAvailableNode extends AbstractPrimitiveNode implements BinaryPrimitive { protected PrimSocketReceiveDataAvailableNode(final CompiledMethodObject method) { super(method); } @@ -442,7 +429,7 @@ protected final boolean doWork(@SuppressWarnings("unused") final AbstractSqueakO try { return getSocketOrPrimFail(socketID).isDataAvailable(); } catch (final IOException e) { - error(e); + LOG.log(Level.FINE, "Checking for available data failed", e); return code.image.sqFalse; } } @@ -450,7 +437,7 @@ protected final boolean doWork(@SuppressWarnings("unused") final AbstractSqueakO @GenerateNodeFactory @SqueakPrimitive(names = "primitiveSocketError") - protected abstract static class PrimSocketErrorNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { + protected abstract static class PrimSocketErrorNode extends AbstractPrimitiveNode implements BinaryPrimitive { protected PrimSocketErrorNode(final CompiledMethodObject method) { super(method); } @@ -465,7 +452,7 @@ protected static long doWork(final AbstractSqueakObject receiver, final long soc @GenerateNodeFactory @SqueakPrimitive(names = "primitiveSocketLocalAddress") - protected abstract static class PrimSocketLocalAddressNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { + protected abstract static class PrimSocketLocalAddressNode extends AbstractPrimitiveNode implements BinaryPrimitive { protected PrimSocketLocalAddressNode(final CompiledMethodObject method) { super(method); } @@ -477,7 +464,7 @@ protected final AbstractSqueakObject doWork(@SuppressWarnings("unused") final Ab final SqSocket socket = getSocketOrPrimFail(socketID); return code.image.wrap(socket.getLocalAddress()); } catch (final IOException e) { - error(e); + LOG.log(Level.FINE, "Retrieving local address failed", e); throw new PrimitiveFailed(); } } @@ -485,7 +472,7 @@ protected final AbstractSqueakObject doWork(@SuppressWarnings("unused") final Ab @GenerateNodeFactory @SqueakPrimitive(names = "primitiveSocketSendDataBufCount") - protected abstract static class PrimSocketSendDataBufCountNode extends AbstractSocketPluginPrimitiveNode implements QuinaryPrimitive { + protected abstract static class PrimSocketSendDataBufCountNode extends AbstractPrimitiveNode implements QuinaryPrimitive { protected PrimSocketSendDataBufCountNode(final CompiledMethodObject method) { super(method); } @@ -510,7 +497,7 @@ protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObje final SqSocket socket = getSocketOrPrimFail(socketID); return socket.sendData(ByteBuffer.wrap(buffer.getByteStorage(), (int) startIndex - 1, (int) count)); } catch (final IOException e) { - error(e); + LOG.log(Level.FINE, "Sending data failed", e); throw new PrimitiveFailed(); } } @@ -518,7 +505,7 @@ protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObje @GenerateNodeFactory @SqueakPrimitive(names = "primitiveSocketCloseConnection") - protected abstract static class PrimSocketCloseConnectionNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { + protected abstract static class PrimSocketCloseConnectionNode extends AbstractPrimitiveNode implements BinaryPrimitive { protected PrimSocketCloseConnectionNode(final CompiledMethodObject method) { super(method); } @@ -529,8 +516,8 @@ protected final AbstractSqueakObject doWork(final AbstractSqueakObject receiver, try { getSocketOrPrimFail(socketID).close(); return receiver; - } catch (IOException e) { - error(e); + } catch (final IOException e) { + LOG.log(Level.FINE, "Closing socket failed", e); throw new PrimitiveFailed(); } } @@ -538,7 +525,7 @@ protected final AbstractSqueakObject doWork(final AbstractSqueakObject receiver, @GenerateNodeFactory @SqueakPrimitive(names = "primitiveSocketAbortConnection") - protected abstract static class PrimSocketAbortConnectionNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { + protected abstract static class PrimSocketAbortConnectionNode extends AbstractPrimitiveNode implements BinaryPrimitive { protected PrimSocketAbortConnectionNode(final CompiledMethodObject method) { super(method); } @@ -549,8 +536,8 @@ protected final AbstractSqueakObject doWork(final AbstractSqueakObject receiver, try { getSocketOrPrimFail(socketID).close(); return receiver; - } catch (IOException e) { - error(e); + } catch (final IOException e) { + LOG.log(Level.FINE, "Closing socket failed", e); throw new PrimitiveFailed(); } } @@ -558,7 +545,7 @@ protected final AbstractSqueakObject doWork(final AbstractSqueakObject receiver, @GenerateNodeFactory @SqueakPrimitive(names = "primitiveSocketSendDone") - protected abstract static class PrimSocketSendDoneNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { + protected abstract static class PrimSocketSendDoneNode extends AbstractPrimitiveNode implements BinaryPrimitive { protected PrimSocketSendDoneNode(final CompiledMethodObject method) { super(method); } @@ -569,7 +556,7 @@ protected final Object doWork(@SuppressWarnings("unused") final AbstractSqueakOb try { return code.image.wrap(getSocketOrPrimFail(socketID).isSendDone()); } catch (final IOException e) { - error(e); + LOG.log(Level.FINE, "Checking completed send failed", e); throw new PrimitiveFailed(); } } @@ -577,7 +564,7 @@ protected final Object doWork(@SuppressWarnings("unused") final AbstractSqueakOb @GenerateNodeFactory @SqueakPrimitive(names = "primitiveSocketReceiveDataBufCount") - protected abstract static class PrimSocketReceiveDataBufCountNode extends AbstractSocketPluginPrimitiveNode implements QuinaryPrimitive { + protected abstract static class PrimSocketReceiveDataBufCountNode extends AbstractPrimitiveNode implements QuinaryPrimitive { protected PrimSocketReceiveDataBufCountNode(final CompiledMethodObject method) { super(method); } @@ -592,8 +579,8 @@ protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObje try { final SqSocket socket = getSocketOrPrimFail(socketID); return socket.receiveData(ByteBuffer.wrap(buffer.getByteStorage(), (int) startIndex - 1, (int) count)); - } catch (IOException e) { - error(e); + } catch (final IOException e) { + LOG.log(Level.FINE, "Receiving data failed", e); throw new PrimitiveFailed(); } } @@ -601,7 +588,7 @@ protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObje @GenerateNodeFactory @SqueakPrimitive(names = "primitiveSocketDestroy") - protected abstract static class PrimSocketDestroyNode extends AbstractSocketPluginPrimitiveNode implements BinaryPrimitive { + protected abstract static class PrimSocketDestroyNode extends AbstractPrimitiveNode implements BinaryPrimitive { protected PrimSocketDestroyNode(final CompiledMethodObject method) { super(method); } @@ -615,8 +602,8 @@ protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObje socket.close(); } return 0; - } catch (IOException e) { - error(e); + } catch (final IOException e) { + LOG.log(Level.FINE, "Destroying socket failed", e); throw new PrimitiveFailed(); } } @@ -624,7 +611,7 @@ protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObje @GenerateNodeFactory @SqueakPrimitive(names = "primitiveSocketCreate3Semaphores") - protected abstract static class PrimSocketCreate3SemaphoresNode extends AbstractSocketPluginPrimitiveNode implements SeptenaryPrimitive { + protected abstract static class PrimSocketCreate3SemaphoresNode extends AbstractPrimitiveNode implements SeptenaryPrimitive { protected PrimSocketCreate3SemaphoresNode(final CompiledMethodObject method) { super(method); } @@ -653,7 +640,7 @@ protected final long doWork(final PointersObject receiver, @GenerateNodeFactory @SqueakPrimitive(names = "primitiveSocketAccept3Semaphores") - protected abstract static class PrimSocketAccept3SemaphoresNode extends AbstractSocketPluginPrimitiveNode implements SeptenaryPrimitive { + protected abstract static class PrimSocketAccept3SemaphoresNode extends AbstractPrimitiveNode implements SeptenaryPrimitive { protected PrimSocketAccept3SemaphoresNode(final CompiledMethodObject method) { super(method); } @@ -673,8 +660,8 @@ protected final long doWork(final AbstractSqueakObject receiver, final SqSocket accepted = socket.accept(); SOCKETS.put(accepted.handle(), accepted); return accepted.handle(); - } catch (IOException e) { - error(e); + } catch (final IOException e) { + LOG.log(Level.FINE, "Accepting socket failed", e); throw new PrimitiveFailed(); } } @@ -682,7 +669,7 @@ protected final long doWork(final AbstractSqueakObject receiver, @GenerateNodeFactory @SqueakPrimitive(names = "primitiveSocketCreate") - protected abstract static class PrimSocketCreateNode extends AbstractSocketPluginPrimitiveNode implements SenaryPrimitive { + protected abstract static class PrimSocketCreateNode extends AbstractPrimitiveNode implements SenaryPrimitive { protected PrimSocketCreateNode(final CompiledMethodObject method) { super(method); } @@ -695,7 +682,8 @@ protected final long doWork(final PointersObject receiver, final long rcvBufSize, final long sendBufSize, final long semaphoreIndex) { - error("TODO: primitiveSocketCreate"); + + LOG.warning("TODO: primitiveSocketCreate"); throw new PrimitiveFailed(); } From 411599433a22fdd99df7ea57f85bf148d7904f28 Mon Sep 17 00:00:00 2001 From: Falco Duersch Date: Mon, 28 Jan 2019 14:26:59 +0100 Subject: [PATCH 5/9] fixup! Refactor socket plugin to NIO Use longs, swap Sq prefix to Squeak --- .../nodes/plugins/network/SocketPlugin.java | 43 +++++++++---------- .../{SqSocket.java => SqueakSocket.java} | 14 +++--- .../{TCPSocket.java => SqueakTCPSocket.java} | 12 +++--- .../{UDPSocket.java => SqueakUDPSocket.java} | 6 +-- 4 files changed, 37 insertions(+), 38 deletions(-) rename src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/{SqSocket.java => SqueakSocket.java} (93%) rename src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/{TCPSocket.java => SqueakTCPSocket.java} (94%) rename src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/{UDPSocket.java => SqueakUDPSocket.java} (95%) diff --git a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SocketPlugin.java b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SocketPlugin.java index 820dc828c..bbb25169b 100644 --- a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SocketPlugin.java +++ b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SocketPlugin.java @@ -1,7 +1,6 @@ package de.hpi.swa.graal.squeak.nodes.plugins.network; import com.oracle.truffle.api.TruffleLogger; -import de.hpi.swa.graal.squeak.SqueakLanguage; import de.hpi.swa.graal.squeak.model.ArrayObject; import de.hpi.swa.graal.squeak.shared.SqueakLanguageConfig; import java.io.IOException; @@ -37,7 +36,7 @@ public final class SocketPlugin extends AbstractPrimitiveFactoryHolder { private static final TruffleLogger LOG = TruffleLogger.getLogger(SqueakLanguageConfig.ID, SocketPlugin.class); - private static final EconomicMap SOCKETS = EconomicMap.create(); + private static final EconomicMap SOCKETS = EconomicMap.create(); @GenerateNodeFactory @SqueakPrimitive(names = "primitiveResolverStatus") @@ -66,8 +65,8 @@ protected static AbstractSqueakObject doWork(final AbstractSqueakObject receiver } @TruffleBoundary - private static SqSocket getSocketOrPrimFail(final long socketHandle) { - final SqSocket socket = SOCKETS.get(socketHandle); + private static SqueakSocket getSocketOrPrimFail(final long socketHandle) { + final SqueakSocket socket = SOCKETS.get(socketHandle); if (socket == null) { throw new PrimitiveFailed(); } @@ -287,7 +286,7 @@ protected PrimSocketSetOptionsNode(final CompiledMethodObject method) { @TruffleBoundary protected final ArrayObject doWork(@SuppressWarnings("unused") final AbstractSqueakObject receiver, final long socketID, final NativeObject option, final NativeObject value) { try { - final SqSocket socket = getSocketOrPrimFail(socketID); + final SqueakSocket socket = getSocketOrPrimFail(socketID); return setSocketOption(socket, option.asString(), value.asString()); } catch (final IOException e) { LOG.log(Level.FINE, "Set socket option failed", e); @@ -295,13 +294,13 @@ protected final ArrayObject doWork(@SuppressWarnings("unused") final AbstractSqu } } - private ArrayObject setSocketOption(final SqSocket socket, final String option, final String value) throws IOException { + private ArrayObject setSocketOption(final SqueakSocket socket, final String option, final String value) throws IOException { if (socket.supportsOption(option)) { socket.setOption(option, value); - return code.image.wrap(0, value); + return code.image.wrap(0L, value); } - return code.image.wrap(1, "0"); + return code.image.wrap(1L, "0"); } } @@ -316,14 +315,14 @@ protected PrimSocketConnectToPortNode(final CompiledMethodObject method) { @TruffleBoundary protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObject receiver, final long socketID, final NativeObject hostAddress, final long port) { try { - final SqSocket socket = getSocketOrPrimFail(socketID); + final SqueakSocket socket = getSocketOrPrimFail(socketID); final String host = Resolver.addressBytesToString(hostAddress.getByteStorage()); socket.connectTo(host, (int) port); } catch (final IOException e) { LOG.log(Level.FINE, "Socket connect failed", e); throw new PrimitiveFailed(); } - return 0; + return 0L; } } @@ -338,11 +337,11 @@ protected PrimSocketConnectionStatusNode(final CompiledMethodObject method) { @TruffleBoundary protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObject receiver, final long socketID) { if (!SOCKETS.containsKey(socketID)) { - return SqSocket.Status.Unconnected.id(); + return SqueakSocket.Status.Unconnected.id(); } try { - final SqSocket socket = getSocketOrPrimFail(socketID); + final SqueakSocket socket = getSocketOrPrimFail(socketID); return socket.getStatus().id(); } catch (final IOException e) { LOG.log(Level.FINE, "Retrieving socket status failed", e); @@ -406,7 +405,7 @@ protected PrimSocketGetOptionsNode(final CompiledMethodObject method) { @TruffleBoundary protected final Object doWork(@SuppressWarnings("unused") final AbstractSqueakObject receiver, final long socketID, final NativeObject option) { try { - final SqSocket socket = getSocketOrPrimFail(socketID); + final SqueakSocket socket = getSocketOrPrimFail(socketID); final String value = socket.getOption(option.asString()); return code.image.wrap(0, value); } catch (final IOException e) { @@ -461,7 +460,7 @@ protected PrimSocketLocalAddressNode(final CompiledMethodObject method) { @TruffleBoundary protected final AbstractSqueakObject doWork(@SuppressWarnings("unused") final AbstractSqueakObject receiver, final long socketID) { try { - final SqSocket socket = getSocketOrPrimFail(socketID); + final SqueakSocket socket = getSocketOrPrimFail(socketID); return code.image.wrap(socket.getLocalAddress()); } catch (final IOException e) { LOG.log(Level.FINE, "Retrieving local address failed", e); @@ -494,7 +493,7 @@ protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObje final long count) { try { - final SqSocket socket = getSocketOrPrimFail(socketID); + final SqueakSocket socket = getSocketOrPrimFail(socketID); return socket.sendData(ByteBuffer.wrap(buffer.getByteStorage(), (int) startIndex - 1, (int) count)); } catch (final IOException e) { LOG.log(Level.FINE, "Sending data failed", e); @@ -577,7 +576,7 @@ protected PrimSocketReceiveDataBufCountNode(final CompiledMethodObject method) { @TruffleBoundary protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObject receiver, final long socketID, final NativeObject buffer, final long startIndex, final long count) { try { - final SqSocket socket = getSocketOrPrimFail(socketID); + final SqueakSocket socket = getSocketOrPrimFail(socketID); return socket.receiveData(ByteBuffer.wrap(buffer.getByteStorage(), (int) startIndex - 1, (int) count)); } catch (final IOException e) { LOG.log(Level.FINE, "Receiving data failed", e); @@ -597,11 +596,11 @@ protected PrimSocketDestroyNode(final CompiledMethodObject method) { @TruffleBoundary protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObject receiver, final long socketID) { try { - final SqSocket socket = SOCKETS.removeKey(socketID); + final SqueakSocket socket = SOCKETS.removeKey(socketID); if (socket != null) { socket.close(); } - return 0; + return 0L; } catch (final IOException e) { LOG.log(Level.FINE, "Destroying socket failed", e); throw new PrimitiveFailed(); @@ -628,8 +627,8 @@ protected final long doWork(final PointersObject receiver, final long aWriteSemaphore) { try { - final SqSocket.Type type = SqSocket.Type.fromId(socketType); - final SqSocket socket = SqSocket.create(type); + final SqueakSocket.Type type = SqueakSocket.Type.fromId(socketType); + final SqueakSocket socket = SqueakSocket.create(type); SOCKETS.put(socket.handle(), socket); return socket.handle(); } catch (final IOException e) { @@ -656,8 +655,8 @@ protected final long doWork(final AbstractSqueakObject receiver, final long readSemaphoreIndex, final long writeSemaphoreIndex) { try { - final SqSocket socket = getSocketOrPrimFail(socketID); - final SqSocket accepted = socket.accept(); + final SqueakSocket socket = getSocketOrPrimFail(socketID); + final SqueakSocket accepted = socket.accept(); SOCKETS.put(accepted.handle(), accepted); return accepted.handle(); } catch (final IOException e) { diff --git a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SqSocket.java b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SqueakSocket.java similarity index 93% rename from src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SqSocket.java rename to src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SqueakSocket.java index 5b65b5d8b..5a641a2e7 100644 --- a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SqSocket.java +++ b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SqueakSocket.java @@ -14,7 +14,7 @@ import java.util.Iterator; import java.util.Set; -abstract class SqSocket { +abstract class SqueakSocket { enum Status { InvalidSocket(-1), @@ -55,14 +55,14 @@ static Type fromId(final long id) { } } - private static final TruffleLogger LOG = TruffleLogger.getLogger(SqueakLanguageConfig.ID, SqSocket.class); + private static final TruffleLogger LOG = TruffleLogger.getLogger(SqueakLanguageConfig.ID, SqueakSocket.class); protected final long handle; protected final Selector selector; protected boolean listening; - protected SqSocket() throws IOException { + protected SqueakSocket() throws IOException { this.handle = System.identityHashCode(this); this.selector = Selector.open(); this.listening = false; @@ -88,7 +88,7 @@ protected long handle() { protected abstract void listenOn(long port, long backlogSize) throws IOException; - protected abstract SqSocket accept() throws IOException; + protected abstract SqueakSocket accept() throws IOException; protected abstract boolean isSendDone() throws IOException; @@ -185,12 +185,12 @@ protected static InetSocketAddress castAddress(final SocketAddress address) { throw new SqueakException("Unknown address type"); } - protected static SqSocket create(final SqSocket.Type socketType) throws IOException { + protected static SqueakSocket create(final SqueakSocket.Type socketType) throws IOException { switch (socketType) { case TCP: - return new TCPSocket(); + return new SqueakTCPSocket(); case UDP: - return new UDPSocket(); + return new SqueakUDPSocket(); default: throw new SqueakException("Unknown SocketType"); } diff --git a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/TCPSocket.java b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SqueakTCPSocket.java similarity index 94% rename from src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/TCPSocket.java rename to src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SqueakTCPSocket.java index 70bb90d62..2a81db1ea 100644 --- a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/TCPSocket.java +++ b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SqueakTCPSocket.java @@ -13,18 +13,18 @@ import java.nio.channels.SocketChannel; import java.util.Iterator; -final class TCPSocket extends SqSocket { +final class SqueakTCPSocket extends SqueakSocket { - private static final TruffleLogger LOG = TruffleLogger.getLogger(SqueakLanguageConfig.ID, TCPSocket.class); + private static final TruffleLogger LOG = TruffleLogger.getLogger(SqueakLanguageConfig.ID, SqueakTCPSocket.class); private SocketChannel clientChannel; private ServerSocketChannel serverChannel; - protected TCPSocket() throws IOException { + protected SqueakTCPSocket() throws IOException { super(); } - private TCPSocket(final SocketChannel clientChannel) throws IOException { + private SqueakTCPSocket(final SocketChannel clientChannel) throws IOException { super(); this.clientChannel = clientChannel; this.clientChannel.configureBlocking(false); @@ -158,10 +158,10 @@ protected void listenOn(final long port, final long backlogSize) throws IOExcept } @Override - protected SqSocket accept() throws IOException { + protected SqueakSocket accept() throws IOException { if (listening && clientChannel != null) { clientChannel.keyFor(selector).cancel(); - final SqSocket created = new TCPSocket(clientChannel); + final SqueakSocket created = new SqueakTCPSocket(clientChannel); clientChannel = null; return created; } diff --git a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/UDPSocket.java b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SqueakUDPSocket.java similarity index 95% rename from src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/UDPSocket.java rename to src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SqueakUDPSocket.java index 58406c54d..c672f0aa9 100644 --- a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/UDPSocket.java +++ b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SqueakUDPSocket.java @@ -8,11 +8,11 @@ import java.nio.channels.NetworkChannel; import java.nio.channels.SelectionKey; -final class UDPSocket extends SqSocket { +final class SqueakUDPSocket extends SqueakSocket { private final DatagramChannel channel; - UDPSocket() throws IOException { + SqueakUDPSocket() throws IOException { super(); channel = DatagramChannel.open(); channel.configureBlocking(false); @@ -87,7 +87,7 @@ protected void listenOn(final long port, final long backlogSize) throws IOExcept } @Override - protected SqSocket accept() { + protected SqueakSocket accept() { throw new UnsupportedOperationException("accept() on UDP socket"); } From a1c9622eca515ec3faa4153fdeafb2c8670ff30b Mon Sep 17 00:00:00 2001 From: Falco Duersch Date: Mon, 28 Jan 2019 14:31:32 +0100 Subject: [PATCH 6/9] fixup! Refactor socket plugin to NIO finals --- .../nodes/plugins/network/SqueakSocket.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SqueakSocket.java b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SqueakSocket.java index 5a641a2e7..55d78dc85 100644 --- a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SqueakSocket.java +++ b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SqueakSocket.java @@ -68,7 +68,7 @@ protected SqueakSocket() throws IOException { this.listening = false; } - protected long handle() { + protected final long handle() { return handle; } @@ -92,7 +92,7 @@ protected long handle() { protected abstract boolean isSendDone() throws IOException; - protected long sendData(final ByteBuffer buffer) throws IOException { + protected final long sendData(final ByteBuffer buffer) throws IOException { selector.selectNow(); final Iterator keys = selector.selectedKeys().iterator(); while (keys.hasNext()) { @@ -110,7 +110,7 @@ protected long sendData(final ByteBuffer buffer) throws IOException { protected abstract long sendDataTo(ByteBuffer data, SelectionKey key) throws IOException; - protected boolean isDataAvailable() throws IOException { + protected final boolean isDataAvailable() throws IOException { selector.selectNow(); final Set keys = selector.selectedKeys(); for (final SelectionKey key : keys) { @@ -124,7 +124,7 @@ protected boolean isDataAvailable() throws IOException { return false; } - protected long receiveData(final ByteBuffer buffer) throws IOException { + protected final long receiveData(final ByteBuffer buffer) throws IOException { selector.selectNow(); final Iterator keys = selector.selectedKeys().iterator(); while (keys.hasNext()) { @@ -142,11 +142,11 @@ protected long receiveData(final ByteBuffer buffer) throws IOException { protected abstract long receiveDataFrom(SelectionKey key, ByteBuffer data) throws IOException; - protected boolean supportsOption(final String name) { + protected final boolean supportsOption(final String name) { return asNetworkChannel().supportedOptions().stream().anyMatch(o -> o.name().equals(name)); } - protected String getOption(final String name) throws IOException { + protected final String getOption(final String name) throws IOException { final SocketOption option = socketOptionFromString(name); final Object value = asNetworkChannel().getOption(option); if (value instanceof Boolean) { @@ -155,13 +155,13 @@ protected String getOption(final String name) throws IOException { return String.valueOf(value); } - protected void setOption(final String name, final String value) throws IOException { + protected final void setOption(final String name, final String value) throws IOException { final Boolean enabled = value.equals("1"); final SocketOption option = socketOptionFromString(name); sneakySetOption(option, enabled); } - protected SocketOption socketOptionFromString(final String name) { + protected final SocketOption socketOptionFromString(final String name) { return asNetworkChannel().supportedOptions().stream().filter(o -> o.name().equals(name)).findFirst().orElseThrow(() -> new UnsupportedOperationException("Unknown socket option: " + name)); } From 6db2c6df2217bbd6731c141f72f851e041326b6a Mon Sep 17 00:00:00 2001 From: Falco Duersch Date: Mon, 28 Jan 2019 14:50:08 +0100 Subject: [PATCH 7/9] fixup! Refactor socket plugin to NIO PrimitiveFailed.andTransferToInterpreter --- .../exceptions/PrimitiveExceptions.java | 21 +++++++++- .../nodes/plugins/network/SocketPlugin.java | 42 +++++++++---------- 2 files changed, 40 insertions(+), 23 deletions(-) diff --git a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/exceptions/PrimitiveExceptions.java b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/exceptions/PrimitiveExceptions.java index 2985e42ba..f8d8225fd 100644 --- a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/exceptions/PrimitiveExceptions.java +++ b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/exceptions/PrimitiveExceptions.java @@ -20,15 +20,32 @@ public final long getReasonCode() { } } + /** + * Primitive failed. + * + *

Below factory methods return {@code PrimitiveFailed}, such that it is possible to substitue a return clause. Example:

+ * + *
+     * long getStatus() {
+     *   try {
+     *     return 0;
+     *   } catch (final IOException e) {
+     *     throw PrimitiveFailed.andTransferToInterpreter();
+     *      // no unreachable return statement required.
+     *   }
+     * }
+     * 
+     * 
+ */ public static final class PrimitiveFailed extends AbstractPrimitiveFailed { private static final long serialVersionUID = 1L; - public static void andTransferToInterpreter() { + public static PrimitiveFailed andTransferToInterpreter() { CompilerDirectives.transferToInterpreter(); throw new PrimitiveFailed(); } - public static void andTransferToInterpreter(final long reason) { + public static PrimitiveFailed andTransferToInterpreter(final long reason) { CompilerDirectives.transferToInterpreter(); throw new PrimitiveFailed(reason); } diff --git a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SocketPlugin.java b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SocketPlugin.java index bbb25169b..740f6eb2b 100644 --- a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SocketPlugin.java +++ b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SocketPlugin.java @@ -68,7 +68,7 @@ protected static AbstractSqueakObject doWork(final AbstractSqueakObject receiver private static SqueakSocket getSocketOrPrimFail(final long socketHandle) { final SqueakSocket socket = SOCKETS.get(socketHandle); if (socket == null) { - throw new PrimitiveFailed(); + throw PrimitiveFailed.andTransferToInterpreter(); } return socket; } @@ -196,7 +196,7 @@ protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObje return getSocketOrPrimFail(socketID).getLocalPort(); } catch (final IOException e) { LOG.log(Level.FINE, "Retrieving local port failed", e); - throw new PrimitiveFailed(); + throw PrimitiveFailed.andTransferToInterpreter(); } } } @@ -223,7 +223,7 @@ protected final AbstractSqueakObject doWork(final AbstractSqueakObject receiver, return receiver; } catch (final IOException e) { LOG.log(Level.FINE, "Listen failed", e); - throw new PrimitiveFailed(); + throw PrimitiveFailed.andTransferToInterpreter(); } } @@ -242,7 +242,7 @@ protected final AbstractSqueakObject doWork(final AbstractSqueakObject receiver, return receiver; } catch (final IOException e) { LOG.log(Level.FINE, "Listen failed", e); - throw new PrimitiveFailed(); + throw PrimitiveFailed.andTransferToInterpreter(); } } } @@ -270,7 +270,7 @@ protected final AbstractSqueakObject doWork(final AbstractSqueakObject receiver, return receiver; } catch (final IOException e) { LOG.log(Level.FINE, "Listen failed", e); - throw new PrimitiveFailed(); + throw PrimitiveFailed.andTransferToInterpreter(); } } } @@ -290,7 +290,7 @@ protected final ArrayObject doWork(@SuppressWarnings("unused") final AbstractSqu return setSocketOption(socket, option.asString(), value.asString()); } catch (final IOException e) { LOG.log(Level.FINE, "Set socket option failed", e); - throw new PrimitiveFailed(); + throw PrimitiveFailed.andTransferToInterpreter(); } } @@ -320,7 +320,7 @@ protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObje socket.connectTo(host, (int) port); } catch (final IOException e) { LOG.log(Level.FINE, "Socket connect failed", e); - throw new PrimitiveFailed(); + throw PrimitiveFailed.andTransferToInterpreter(); } return 0L; } @@ -345,7 +345,7 @@ protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObje return socket.getStatus().id(); } catch (final IOException e) { LOG.log(Level.FINE, "Retrieving socket status failed", e); - throw new PrimitiveFailed(); + throw PrimitiveFailed.andTransferToInterpreter(); } } } @@ -364,7 +364,7 @@ protected final AbstractSqueakObject doWork(@SuppressWarnings("unused") final Ab return code.image.wrap(getSocketOrPrimFail(socketID).getRemoteAddress()); } catch (final IOException e) { LOG.log(Level.FINE, "Retrieving remote address failed", e); - throw new PrimitiveFailed(); + throw PrimitiveFailed.andTransferToInterpreter(); } } } @@ -383,7 +383,7 @@ protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObje return getSocketOrPrimFail(socketID).getRemotePort(); } catch (final IOException e) { LOG.log(Level.FINE, "Retrieving remote port failed", e); - throw new PrimitiveFailed(); + throw PrimitiveFailed.andTransferToInterpreter(); } } } @@ -410,7 +410,7 @@ protected final Object doWork(@SuppressWarnings("unused") final AbstractSqueakOb return code.image.wrap(0, value); } catch (final IOException e) { LOG.log(Level.FINE, "Retrieving socket option failed", e); - throw new PrimitiveFailed(); + throw PrimitiveFailed.andTransferToInterpreter(); } } } @@ -464,7 +464,7 @@ protected final AbstractSqueakObject doWork(@SuppressWarnings("unused") final Ab return code.image.wrap(socket.getLocalAddress()); } catch (final IOException e) { LOG.log(Level.FINE, "Retrieving local address failed", e); - throw new PrimitiveFailed(); + throw PrimitiveFailed.andTransferToInterpreter(); } } } @@ -497,7 +497,7 @@ protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObje return socket.sendData(ByteBuffer.wrap(buffer.getByteStorage(), (int) startIndex - 1, (int) count)); } catch (final IOException e) { LOG.log(Level.FINE, "Sending data failed", e); - throw new PrimitiveFailed(); + throw PrimitiveFailed.andTransferToInterpreter(); } } } @@ -517,7 +517,7 @@ protected final AbstractSqueakObject doWork(final AbstractSqueakObject receiver, return receiver; } catch (final IOException e) { LOG.log(Level.FINE, "Closing socket failed", e); - throw new PrimitiveFailed(); + throw PrimitiveFailed.andTransferToInterpreter(); } } } @@ -537,7 +537,7 @@ protected final AbstractSqueakObject doWork(final AbstractSqueakObject receiver, return receiver; } catch (final IOException e) { LOG.log(Level.FINE, "Closing socket failed", e); - throw new PrimitiveFailed(); + throw PrimitiveFailed.andTransferToInterpreter(); } } } @@ -556,7 +556,7 @@ protected final Object doWork(@SuppressWarnings("unused") final AbstractSqueakOb return code.image.wrap(getSocketOrPrimFail(socketID).isSendDone()); } catch (final IOException e) { LOG.log(Level.FINE, "Checking completed send failed", e); - throw new PrimitiveFailed(); + throw PrimitiveFailed.andTransferToInterpreter(); } } } @@ -580,7 +580,7 @@ protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObje return socket.receiveData(ByteBuffer.wrap(buffer.getByteStorage(), (int) startIndex - 1, (int) count)); } catch (final IOException e) { LOG.log(Level.FINE, "Receiving data failed", e); - throw new PrimitiveFailed(); + throw PrimitiveFailed.andTransferToInterpreter(); } } } @@ -603,7 +603,7 @@ protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObje return 0L; } catch (final IOException e) { LOG.log(Level.FINE, "Destroying socket failed", e); - throw new PrimitiveFailed(); + throw PrimitiveFailed.andTransferToInterpreter(); } } } @@ -632,7 +632,7 @@ protected final long doWork(final PointersObject receiver, SOCKETS.put(socket.handle(), socket); return socket.handle(); } catch (final IOException e) { - throw new PrimitiveFailed(); + throw PrimitiveFailed.andTransferToInterpreter(); } } } @@ -661,7 +661,7 @@ protected final long doWork(final AbstractSqueakObject receiver, return accepted.handle(); } catch (final IOException e) { LOG.log(Level.FINE, "Accepting socket failed", e); - throw new PrimitiveFailed(); + throw PrimitiveFailed.andTransferToInterpreter(); } } } @@ -683,7 +683,7 @@ protected final long doWork(final PointersObject receiver, final long semaphoreIndex) { LOG.warning("TODO: primitiveSocketCreate"); - throw new PrimitiveFailed(); + throw PrimitiveFailed.andTransferToInterpreter(); } } From a19b50dee478ba62c5a5a0192e2908182c2a2950 Mon Sep 17 00:00:00 2001 From: Falco Duersch Date: Mon, 28 Jan 2019 14:53:48 +0100 Subject: [PATCH 8/9] fixup! Refactor socket plugin to NIO codacy --- .../squeak/nodes/plugins/network/Resolver.java | 14 +++++++------- .../squeak/nodes/plugins/network/SqueakSocket.java | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/Resolver.java b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/Resolver.java index 8458fad9a..65df817a9 100644 --- a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/Resolver.java +++ b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/Resolver.java @@ -32,15 +32,15 @@ long id() { private Resolver() { } - static byte[] getAnyLocalAddress() { + protected static byte[] getAnyLocalAddress() { return anyLocalAddress.getAddress(); } - static byte[] getLoopbackAddress() { + protected static byte[] getLoopbackAddress() { return loopbackAddress.getAddress(); } - static void startHostNameLookUp(final String hostName) throws UnknownHostException { + protected static void startHostNameLookUp(final String hostName) throws UnknownHostException { try { if ("localhost".equals(hostName)) { lastNameLookup = Resolver.getLoopbackAddress(); @@ -55,11 +55,11 @@ static void startHostNameLookUp(final String hostName) throws UnknownHostExcepti } } - static byte[] lastHostNameLookupResult() { + protected static byte[] lastHostNameLookupResult() { return lastNameLookup; } - static void startAddressLookUp(final byte[] address) throws UnknownHostException { + protected static void startAddressLookUp(final byte[] address) throws UnknownHostException { try { lastAddressLookup = InetAddress.getByAddress(address).getHostName(); } catch (final UnknownHostException e) { @@ -68,11 +68,11 @@ static void startAddressLookUp(final byte[] address) throws UnknownHostException } } - static String lastAddressLookUpResult() { + protected static String lastAddressLookUpResult() { return lastAddressLookup; } - static String addressBytesToString(final byte[] address) { + protected static String addressBytesToString(final byte[] address) { try { return InetAddress.getByAddress(address).getHostAddress(); } catch (final UnknownHostException e) { diff --git a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SqueakSocket.java b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SqueakSocket.java index 55d78dc85..9edfb223a 100644 --- a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SqueakSocket.java +++ b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SqueakSocket.java @@ -156,7 +156,7 @@ protected final String getOption(final String name) throws IOException { } protected final void setOption(final String name, final String value) throws IOException { - final Boolean enabled = value.equals("1"); + final Boolean enabled = "1".equals(value); final SocketOption option = socketOptionFromString(name); sneakySetOption(option, enabled); } From 042209a94f5103cdcf7bb4a0fea2e3651433439d Mon Sep 17 00:00:00 2001 From: Falco Duersch Date: Mon, 28 Jan 2019 14:56:08 +0100 Subject: [PATCH 9/9] fixup! Refactor socket plugin to NIO format --- .../exceptions/PrimitiveExceptions.java | 5 ++- .../nodes/plugins/network/SocketPlugin.java | 45 ++++++++++++------- 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/exceptions/PrimitiveExceptions.java b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/exceptions/PrimitiveExceptions.java index f8d8225fd..8b506a501 100644 --- a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/exceptions/PrimitiveExceptions.java +++ b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/exceptions/PrimitiveExceptions.java @@ -23,7 +23,10 @@ public final long getReasonCode() { /** * Primitive failed. * - *

Below factory methods return {@code PrimitiveFailed}, such that it is possible to substitue a return clause. Example:

+ *

+ * Below factory methods return {@code PrimitiveFailed}, such that it is possible to substitue a + * return clause. Example: + *

* *
      * long getStatus() {
diff --git a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SocketPlugin.java b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SocketPlugin.java
index 740f6eb2b..85df28a7c 100644
--- a/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SocketPlugin.java
+++ b/src/de.hpi.swa.graal.squeak/src/de/hpi/swa/graal/squeak/nodes/plugins/network/SocketPlugin.java
@@ -87,7 +87,7 @@ protected PrimResolverStartNameLookupNode(final CompiledMethodObject method) {
          */
         @Specialization(guards = "hostName.isByteType()")
         @TruffleBoundary
-        protected final Object doWork(final Object receiver, final NativeObject hostName) {
+        protected static Object doWork(final Object receiver, final NativeObject hostName) {
             try {
                 LOG.finer(() -> "Starting lookup for host name " + hostName);
                 Resolver.startHostNameLookUp(hostName.asString());
@@ -113,7 +113,7 @@ protected PrimResolverStartAddressLookupNode(final CompiledMethodObject method)
          */
         @Specialization(guards = "address.isByteType()")
         @TruffleBoundary
-        protected final Object doWork(final Object receiver, final NativeObject address) {
+        protected static Object doWork(final Object receiver, final NativeObject address) {
             try {
                 LOG.finer(() -> "Starting lookup for address " + address);
                 Resolver.startAddressLookUp(address.getByteStorage());
@@ -191,7 +191,8 @@ protected PrimSocketLocalPortNode(final CompiledMethodObject method) {
         /** Return the local port for this socket, or zero if no port has yet been assigned. */
         @Specialization
         @TruffleBoundary
-        protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObject receiver, final long socketID) {
+        protected static long doWork(
+                        @SuppressWarnings("unused") final AbstractSqueakObject receiver, final long socketID) {
             try {
                 return getSocketOrPrimFail(socketID).getLocalPort();
             } catch (final IOException e) {
@@ -214,7 +215,7 @@ protected PrimSocketListenWithOrWithoutBacklogNode(final CompiledMethodObject me
          */
         @Specialization
         @TruffleBoundary
-        protected final AbstractSqueakObject doWork(final AbstractSqueakObject receiver,
+        protected static AbstractSqueakObject doWork(final AbstractSqueakObject receiver,
                         final long socketID,
                         final long port,
                         @SuppressWarnings("unused") final NotProvided backlogSize) {
@@ -233,7 +234,7 @@ protected final AbstractSqueakObject doWork(final AbstractSqueakObject receiver,
          */
         @Specialization
         @TruffleBoundary
-        protected final AbstractSqueakObject doWork(final AbstractSqueakObject receiver,
+        protected static AbstractSqueakObject doWork(final AbstractSqueakObject receiver,
                         final long socketID,
                         final long port,
                         @SuppressWarnings("unused") final long backlogSize) {
@@ -260,7 +261,7 @@ protected PrimSocketListenOnPortBacklogInterfaceNode(final CompiledMethodObject
          */
         @Specialization(guards = "interfaceAddress.isByteType()")
         @TruffleBoundary
-        protected final AbstractSqueakObject doWork(final AbstractSqueakObject receiver,
+        protected static AbstractSqueakObject doWork(final AbstractSqueakObject receiver,
                         final long socketID,
                         final long port,
                         @SuppressWarnings("unused") final long backlogSize,
@@ -313,7 +314,9 @@ protected PrimSocketConnectToPortNode(final CompiledMethodObject method) {
 
         @Specialization(guards = "hostAddress.isByteType()")
         @TruffleBoundary
-        protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObject receiver, final long socketID, final NativeObject hostAddress, final long port) {
+        protected static long doWork(
+                        @SuppressWarnings("unused") final AbstractSqueakObject receiver, final long socketID,
+                        final NativeObject hostAddress, final long port) {
             try {
                 final SqueakSocket socket = getSocketOrPrimFail(socketID);
                 final String host = Resolver.addressBytesToString(hostAddress.getByteStorage());
@@ -335,7 +338,8 @@ protected PrimSocketConnectionStatusNode(final CompiledMethodObject method) {
 
         @Specialization
         @TruffleBoundary
-        protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObject receiver, final long socketID) {
+        protected static long doWork(
+                        @SuppressWarnings("unused") final AbstractSqueakObject receiver, final long socketID) {
             if (!SOCKETS.containsKey(socketID)) {
                 return SqueakSocket.Status.Unconnected.id();
             }
@@ -378,7 +382,8 @@ protected PrimSocketRemotePortNode(final CompiledMethodObject method) {
 
         @Specialization
         @TruffleBoundary
-        protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObject receiver, final long socketID) {
+        protected static long doWork(
+                        @SuppressWarnings("unused") final AbstractSqueakObject receiver, final long socketID) {
             try {
                 return getSocketOrPrimFail(socketID).getRemotePort();
             } catch (final IOException e) {
@@ -486,7 +491,8 @@ protected PrimSocketSendDataBufCountNode(final CompiledMethodObject method) {
          */
         @Specialization(guards = "buffer.isByteType()")
         @TruffleBoundary
-        protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObject receiver,
+        protected static long doWork(
+                        @SuppressWarnings("unused") final AbstractSqueakObject receiver,
                         final long socketID,
                         final NativeObject buffer,
                         final long startIndex,
@@ -511,7 +517,8 @@ protected PrimSocketCloseConnectionNode(final CompiledMethodObject method) {
 
         @Specialization
         @TruffleBoundary
-        protected final AbstractSqueakObject doWork(final AbstractSqueakObject receiver, final long socketID) {
+        protected static AbstractSqueakObject doWork(final AbstractSqueakObject receiver,
+                        final long socketID) {
             try {
                 getSocketOrPrimFail(socketID).close();
                 return receiver;
@@ -531,7 +538,8 @@ protected PrimSocketAbortConnectionNode(final CompiledMethodObject method) {
 
         @Specialization
         @TruffleBoundary
-        protected final AbstractSqueakObject doWork(final AbstractSqueakObject receiver, final long socketID) {
+        protected static AbstractSqueakObject doWork(final AbstractSqueakObject receiver,
+                        final long socketID) {
             try {
                 getSocketOrPrimFail(socketID).close();
                 return receiver;
@@ -574,7 +582,9 @@ protected PrimSocketReceiveDataBufCountNode(final CompiledMethodObject method) {
          */
         @Specialization(guards = "buffer.isByteType()")
         @TruffleBoundary
-        protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObject receiver, final long socketID, final NativeObject buffer, final long startIndex, final long count) {
+        protected static long doWork(
+                        @SuppressWarnings("unused") final AbstractSqueakObject receiver, final long socketID,
+                        final NativeObject buffer, final long startIndex, final long count) {
             try {
                 final SqueakSocket socket = getSocketOrPrimFail(socketID);
                 return socket.receiveData(ByteBuffer.wrap(buffer.getByteStorage(), (int) startIndex - 1, (int) count));
@@ -594,7 +604,8 @@ protected PrimSocketDestroyNode(final CompiledMethodObject method) {
 
         @Specialization
         @TruffleBoundary
-        protected final long doWork(@SuppressWarnings("unused") final AbstractSqueakObject receiver, final long socketID) {
+        protected static long doWork(
+                        @SuppressWarnings("unused") final AbstractSqueakObject receiver, final long socketID) {
             try {
                 final SqueakSocket socket = SOCKETS.removeKey(socketID);
                 if (socket != null) {
@@ -618,7 +629,7 @@ protected PrimSocketCreate3SemaphoresNode(final CompiledMethodObject method) {
         @SuppressWarnings("unused")
         @TruffleBoundary
         @Specialization
-        protected final long doWork(final PointersObject receiver,
+        protected static long doWork(final PointersObject receiver,
                         final long netType,
                         final long socketType,
                         final long rcvBufSize,
@@ -647,7 +658,7 @@ protected PrimSocketAccept3SemaphoresNode(final CompiledMethodObject method) {
         @SuppressWarnings("unused")
         @TruffleBoundary
         @Specialization
-        protected final long doWork(final AbstractSqueakObject receiver,
+        protected static long doWork(final AbstractSqueakObject receiver,
                         final long socketID,
                         final long receiveBufferSize,
                         final long sendBufSize,
@@ -675,7 +686,7 @@ protected PrimSocketCreateNode(final CompiledMethodObject method) {
 
         @SuppressWarnings("unused")
         @Specialization
-        protected final long doWork(final PointersObject receiver,
+        protected static long doWork(final PointersObject receiver,
                         final long netType,
                         final long socketType,
                         final long rcvBufSize,