Skip to content

Commit 48b36eb

Browse files
Add initial implementation
1 parent d379946 commit 48b36eb

File tree

10 files changed

+1003
-0
lines changed

10 files changed

+1003
-0
lines changed

.classpath

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<classpath>
3+
<classpathentry kind="src" path="src"/>
4+
<classpathentry kind="src" path="test"/>
5+
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
6+
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
7+
<classpathentry kind="output" path="bin"/>
8+
</classpath>

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
bin
2+

.project

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<projectDescription>
3+
<name>java-websocket-client</name>
4+
<comment></comment>
5+
<projects>
6+
</projects>
7+
<buildSpec>
8+
<buildCommand>
9+
<name>org.eclipse.jdt.core.javabuilder</name>
10+
<arguments>
11+
</arguments>
12+
</buildCommand>
13+
</buildSpec>
14+
<natures>
15+
<nature>org.eclipse.jdt.core.javanature</nature>
16+
</natures>
17+
</projectDescription>

src/net/rcode/wsclient/Framing.java

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package net.rcode.wsclient;
2+
3+
import java.io.DataInputStream;
4+
import java.io.DataOutputStream;
5+
6+
/**
7+
* Base class for supporting different framing types on a websocket
8+
* @author stella
9+
*
10+
*/
11+
public class Framing {
12+
public Message readMessage(DataInputStream input) throws Exception {
13+
throw new UnsupportedOperationException();
14+
}
15+
16+
public void sendMessage(DataOutputStream output, Message message) throws Exception {
17+
throw new UnsupportedOperationException();
18+
}
19+
}
+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package net.rcode.wsclient;
2+
3+
import java.io.DataInputStream;
4+
import java.io.DataOutputStream;
5+
import java.util.Arrays;
6+
7+
public class FramingDraft03 extends Framing {
8+
@Override
9+
public Message readMessage(DataInputStream input) throws Exception {
10+
// TODO Auto-generated method stub
11+
return super.readMessage(input);
12+
}
13+
14+
@Override
15+
public void sendMessage(DataOutputStream out, Message message) throws Exception {
16+
byte[] data=message.getMessageData();
17+
if (data==null) return;
18+
19+
int length=data.length;
20+
int header1=message.getOpcode()&0xf;
21+
int header2;
22+
23+
// Different paths based on length
24+
if (length<=125) {
25+
// All fits in one word
26+
header2=length;
27+
out.write(header1);
28+
out.write(header2);
29+
} else if (length<=32767) {
30+
// 2 byte length
31+
header2=126;
32+
out.write(header1);
33+
out.write(header2);
34+
out.writeShort(length);
35+
} else {
36+
// 8 byte length
37+
header2=127;
38+
out.write(header1);
39+
out.write(header2);
40+
out.writeLong(length);
41+
}
42+
43+
System.out.println("Wrote header for message length " + length + ": " + Integer.toHexString(header1) + " " + Integer.toHexString(header2));
44+
System.out.println("Write data: " + Arrays.toString(data));
45+
46+
out.write(data);
47+
out.flush();
48+
System.out.println("Message sent");
49+
}
50+
51+
}
+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package net.rcode.wsclient;
2+
3+
import java.io.ByteArrayOutputStream;
4+
import java.io.DataInputStream;
5+
import java.io.DataOutputStream;
6+
7+
public class FramingDraft76 extends Framing {
8+
@Override
9+
public Message readMessage(DataInputStream input) throws Exception {
10+
for (;;) {
11+
int frameType=input.readUnsignedByte();
12+
if ((frameType&0x80)==0x80) {
13+
int length=0;
14+
for (;;) {
15+
int b=input.readUnsignedByte(),
16+
bv=b&0x7f;
17+
length=length*128 + bv;
18+
if ((b&0x80)!=0x80) break;
19+
}
20+
21+
byte[] data=new byte[length];
22+
input.readFully(data);
23+
24+
if (frameType==0xff && length==0) {
25+
// Close
26+
// TODO: Graceful close
27+
return null;
28+
} else {
29+
return new Message(Message.OPCODE_BINARY, data);
30+
}
31+
} else {
32+
ByteArrayOutputStream accum=new ByteArrayOutputStream();
33+
for (;;) {
34+
int b=input.read();
35+
if (b==0xff) break;
36+
accum.write(b);
37+
}
38+
39+
if (frameType==0) {
40+
Message message=new Message(Message.OPCODE_TEXT, accum.toByteArray());
41+
return message;
42+
}
43+
}
44+
}
45+
}
46+
47+
@Override
48+
public void sendMessage(DataOutputStream output, Message message) throws Exception {
49+
int opcode=message.getOpcode();
50+
if (opcode==Message.OPCODE_PING) return; // Just ignore
51+
52+
if (opcode!=Message.OPCODE_TEXT) {
53+
throw new IllegalArgumentException("Draft76 only supports text messages");
54+
}
55+
56+
output.write(0);
57+
output.write(message.getMessageData());
58+
output.write(0xff);
59+
output.flush();
60+
}
61+
62+
}

src/net/rcode/wsclient/Message.java

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package net.rcode.wsclient;
2+
3+
import java.nio.charset.Charset;
4+
5+
public class Message {
6+
private static final Charset UTF8=Charset.forName("UTF8");
7+
8+
// -- message opcodes
9+
public static final int OPCODE_CONTINUATION=0;
10+
public static final int OPCODE_CLOSE=1;
11+
public static final int OPCODE_PING=2;
12+
public static final int OPCODE_PONG=3;
13+
public static final int OPCODE_TEXT=4;
14+
public static final int OPCODE_BINARY=5;
15+
16+
17+
private int opcode;
18+
private byte[] messageData;
19+
20+
public Message(int opcode, byte[] messageData) {
21+
this.opcode=opcode;
22+
this.messageData=messageData;
23+
}
24+
25+
public boolean isText() {
26+
return opcode==OPCODE_TEXT;
27+
}
28+
29+
public String getMessageText() {
30+
if (isText()) return new String(messageData, UTF8);
31+
else throw new IllegalStateException("Not text based message");
32+
}
33+
34+
public int getOpcode() {
35+
return opcode;
36+
}
37+
38+
public byte[] getMessageData() {
39+
return messageData;
40+
}
41+
42+
@Override
43+
public String toString() {
44+
if (opcode==OPCODE_TEXT) return getMessageText();
45+
else if (messageData!=null ){
46+
StringBuilder ret=new StringBuilder();
47+
for (byte b: messageData) {
48+
ret.append(Integer.toHexString(b)).append(" ");
49+
}
50+
return ret.toString();
51+
} else return "";
52+
}
53+
}

src/net/rcode/wsclient/NetConfig.java

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package net.rcode.wsclient;
2+
3+
import javax.net.SocketFactory;
4+
import javax.net.ssl.SSLSocketFactory;
5+
6+
/**
7+
* Class holding various network configurations
8+
* @author stella
9+
*
10+
*/
11+
public class NetConfig {
12+
private SocketFactory plainSocketFactory;
13+
private SocketFactory secureSocketFactory;
14+
15+
public void setPlainSocketFactory(SocketFactory plainSocketFactory) {
16+
this.plainSocketFactory = plainSocketFactory;
17+
}
18+
public void setSecureSocketFactory(SocketFactory secureSocketFactory) {
19+
this.secureSocketFactory = secureSocketFactory;
20+
}
21+
22+
/**
23+
* @return a value previously specified or system default
24+
*/
25+
public SocketFactory getPlainSocketFactory() {
26+
if (plainSocketFactory==null) return SocketFactory.getDefault();
27+
return plainSocketFactory;
28+
}
29+
/**
30+
* @return a value previously specified or system default
31+
*/
32+
public SocketFactory getSecureSocketFactory() {
33+
if (secureSocketFactory==null) return SSLSocketFactory.getDefault();
34+
return secureSocketFactory;
35+
}
36+
}

0 commit comments

Comments
 (0)