diff --git a/com/etsy/net/JUDS.java b/com/etsy/net/JUDS.java index 1a8f1e6..2063e4c 100644 --- a/com/etsy/net/JUDS.java +++ b/com/etsy/net/JUDS.java @@ -13,14 +13,14 @@ public class JUDS { /** * A constant for the datagram socket type (connectionless). */ - public static final int SOCK_DGRAM = 0; + public static final int SOCK_DGRAM; /** * A constant for the stream oriented stream socket type (connection-based) */ - public static final int SOCK_STREAM = 1; + public static final int SOCK_STREAM; + public static final int SOCK_SEQPACKET; - public static final int SERVER = 0; public static final int CLIENT = 1; @@ -60,6 +60,11 @@ public class JUDS { } jarURL = prepared; } + + UnixDomainSocket.staticInit(); + SOCK_DGRAM = UnixDomainSocket.nativeGetSocketType("SOCK_DGRAM"); + SOCK_STREAM = UnixDomainSocket.nativeGetSocketType("SOCK_STREAM"); + SOCK_SEQPACKET = UnixDomainSocket.nativeGetSocketType("SOCK_SEQPACKET"); } private static ClassLoader judsCl = new URLClassLoader( diff --git a/com/etsy/net/UnixDomainSocket.c b/com/etsy/net/UnixDomainSocket.c index ac0bf28..20a0a19 100644 --- a/com/etsy/net/UnixDomainSocket.c +++ b/com/etsy/net/UnixDomainSocket.c @@ -18,10 +18,6 @@ #define ASSERTNOERR(cond, msg) do { \ if (cond) { fprintf(stderr, "[%d] ", errno); perror(msg); return -1; }} while(0) -/* In the class UnixDomainSocket SOCK_DGRAM and SOCK_STREAM correspond to the - * constant values 0 and 1; SOCK_TYPE replaces them with the respective macro */ -#define SOCK_TYPE(type) ((type) == 0 ? SOCK_DGRAM : SOCK_STREAM) - #ifndef SUN_LEN #define SUN_LEN(su) \ @@ -56,13 +52,13 @@ Java_com_etsy_net_UnixDomainSocket_nativeCreate(JNIEnv * jEnv, socklen_t salen = sockaddr_init(socketFile, &sa); /* create the socket */ - s = socket(PF_UNIX, SOCK_TYPE(jSocketType), 0); + s = socket(PF_UNIX, jSocketType, 0); ASSERTNOERR(s == -1, "nativeCreate: socket"); /* bind to the socket; here the socket file is created */ ASSERTNOERR(bind(s, (struct sockaddr *)&sa, salen) == -1, "nativeCreate: bind"); - if (SOCK_TYPE(jSocketType) == SOCK_STREAM) { + if (jSocketType == SOCK_STREAM || jSocketType == SOCK_SEQPACKET) { ASSERTNOERR(listen(s, 0) == -1, "nativeCreate: listen"); s = accept(s, (struct sockaddr *)&sa, &salen); ASSERTNOERR(s == -1, "nativeCreate: accept"); @@ -88,13 +84,13 @@ Java_com_etsy_net_UnixDomainSocket_nativeListen(JNIEnv * jEnv, socklen_t salen = sockaddr_init(socketFile, &sa); /* create the socket */ - s = socket(PF_UNIX, SOCK_TYPE(jSocketType), 0); + s = socket(PF_UNIX, jSocketType, 0); ASSERTNOERR(s == -1, "nativeListen: socket"); /* bind to the socket; here the socket file is created */ ASSERTNOERR(bind(s, (struct sockaddr *)&sa, salen) == -1, "nativeListen: bind"); - if (SOCK_TYPE(jSocketType) == SOCK_STREAM) { + if (jSocketType == SOCK_STREAM) { ASSERTNOERR(listen(s, jBacklog) == -1, "nativeListen: listen"); } @@ -113,7 +109,7 @@ Java_com_etsy_net_UnixDomainSocket_nativeAccept(JNIEnv * jEnv, int s = -1; /* socket file handle */ ASSERTNOERR(jSocketFileHandle == -1, "nativeAccept: socket"); - if (SOCK_TYPE(jSocketType) == SOCK_STREAM) { + if (jSocketType == SOCK_STREAM) { s = accept(jSocketFileHandle, NULL, 0); ASSERTNOERR(s == -1, "nativeAccept: accept"); } @@ -135,7 +131,7 @@ Java_com_etsy_net_UnixDomainSocket_nativeOpen(JNIEnv * jEnv, (*jEnv)->GetStringUTFChars(jEnv, jSocketFile, NULL); socklen_t salen = sockaddr_init(socketFile, &sa); - s = socket(PF_UNIX, SOCK_TYPE(jSocketType), 0); + s = socket(PF_UNIX, jSocketType, 0); ASSERTNOERR(s == -1, "nativeOpen: socket"); if (connect(s, (struct sockaddr *)&sa, salen) == -1) { perror("nativeOpen: connect"); @@ -249,3 +245,38 @@ Java_com_etsy_net_UnixDomainSocket_nativeUnlink(JNIEnv * jEnv, return ret; } + + +#define CMP_ASN(ret,sock,sockStr) (-1!=(ret=(0==strcmp(#sock,sockStr))?sock:-1)) + +JNIEXPORT jint JNICALL Java_com_etsy_net_UnixDomainSocket_nativeGetSocketType + (JNIEnv * jEnv, jclass cls, jstring jSocketType){ + int ret=-1; + const char *socketType=(*jEnv)->GetStringUTFChars(jEnv, jSocketType, NULL); + do{ + #ifdef SOCK_STREAM + if(CMP_ASN(ret,SOCK_STREAM,socketType)) break; + #endif + #ifdef SOCK_DGRAM + if(CMP_ASN(ret,SOCK_DGRAM,socketType)) break; + #endif + #ifdef SOCK_RAW + if(CMP_ASN(ret,SOCK_RAW,socketType)) break; + #endif + #ifdef SOCK_RDM + if(CMP_ASN(ret,SOCK_RDM,socketType)) break; + #endif + #ifdef SOCK_SEQPACKET + if(CMP_ASN(ret,SOCK_SEQPACKET,socketType)) break; + #endif + #ifdef SOCK_DCCP + if(CMP_ASN(ret,SOCK_DCCP,socketType)) break; + #endif + #ifdef SOCK_PACKET + if(CMP_ASN(ret,SOCK_PACKET,socketType)) break; + #endif + }while(0); + + (*jEnv)->ReleaseStringUTFChars(jEnv, jSocketType, socketType); + return ret; +} diff --git a/com/etsy/net/UnixDomainSocket.java b/com/etsy/net/UnixDomainSocket.java index 332ccd9..820e519 100644 --- a/com/etsy/net/UnixDomainSocket.java +++ b/com/etsy/net/UnixDomainSocket.java @@ -30,6 +30,10 @@ public abstract class UnixDomainSocket { private static File jarFile; static { + staticInit(); + } + + static void staticInit(){ // Load the Unix domain socket C library getJarPath(); try { @@ -209,6 +213,8 @@ protected native static int nativeWrite(int nativeSocketFileHandle, protected native static int nativeUnlink(String socketFile); + protected native static int nativeGetSocketType(String socketType); + protected UnixDomainSocket() { // default constructor diff --git a/test/TestUnixDomainSocket.java b/test/TestUnixDomainSocket.java index c6ee388..6e1b365 100644 --- a/test/TestUnixDomainSocket.java +++ b/test/TestUnixDomainSocket.java @@ -46,6 +46,25 @@ public static void main(String[] args) throws IOException, InterruptedException System.out.println("Text sent: \"" + text + "\""); socket.close(); + Thread.sleep(2000); + + // Testcase 1.3: Test UnixDomainSocketClient with a SEQPACKET socket + socket = new UnixDomainSocketClient(socketFile,JUDS.SOCK_SEQPACKET); + System.out.println("Provoke and catch an " + + "UnsupportedOperationException:"); + try { + in = socket.getInputStream(); + } catch (UnsupportedOperationException e) { + System.out.println("UnsupportedOperationException has been " + + "thrown as expected."); + } + out = socket.getOutputStream(); + text = "[3] Hello! I'm the client!"; + out.write(text.getBytes()); + System.out.println("Text sent: \"" + text + "\""); + socket.close(); + + Thread.sleep(10); // Testcase 2.1: Test UnixDomainSocketServer with a stream socket System.out.println("\nTest #2: Test UnixDomainSocketServer\nTestcase " @@ -80,5 +99,24 @@ public static void main(String[] args) throws IOException, InterruptedException System.out.println("Text received: \"" + new String(b) + "\""); ssocket.close(); ssocket.unlink(); + + // Testcase 2.3: Test UnixDomainSocketServer with a datagram socket + System.out.println("Testcase 2.3: Test UnixDomainSocketServer with " + + "a seqpacket socket..."); + ssocket = new UnixDomainSocketServer(socketFile, + JUDS.SOCK_SEQPACKET); + System.out.println("Provoke and catch an " + + "UnsupportedOperationException:"); + in = ssocket.getInputStream(); + try { + out = ssocket.getOutputStream(); + } catch (UnsupportedOperationException e) { + System.out.println("UnsupportedOperationException has been " + + "thrown as expected."); + } + in.read(b); + System.out.println("Text received: \"" + new String(b) + "\""); + ssocket.close(); + ssocket.unlink(); } } diff --git a/test/TestUnixDomainSocket.py b/test/TestUnixDomainSocket.py index 4c469b6..28494f2 100755 --- a/test/TestUnixDomainSocket.py +++ b/test/TestUnixDomainSocket.py @@ -9,6 +9,10 @@ def main(): print ("usage: %s socketfilename" % sys.argv[0]) sys.exit(1) socket_file = sys.argv[1] + try: + os.unlink(socket_file) + except OSError: + pass # Testcase 1.1: Test UnixDomainSocketClient with a stream socket print ("Test #1: Test UnixDomainSocketClient\n" @@ -36,6 +40,18 @@ def main(): time.sleep(1) # wait for the server + # Testcase 1.3: Test UnixDomainSocketClient with a seqpacket socket + print ("Testcase 1.3: Test UnixDomainSocketClient with a seqpacket socket...") + s = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) + s.bind(socket_file) + s.listen(0) + client, client_address = s.accept() + text = client.recv(BUFSIZE) + print ("Text received: \"%s\"" % text) + s.close() + os.unlink(socket_file) + + time.sleep(1) # wait for the server # Testcase 2.1: Test UnixDomainSocketServer with a stream socket s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) s.connect(socket_file) @@ -56,6 +72,16 @@ def main(): print ("Text sent: \"%s\"" % text) s.close() + time.sleep(1) # wait for the server + + # Testcase 2.3: Test UnixDomainSocketServer with a seqpacket socket + s = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) + s.connect(socket_file) + text = "[6] Hello I'm the client!" + s.send(text) + print ("Text sent: \"%s\"" % text) + s.close() + if __name__ == "__main__": main()