Skip to content

Commit

Permalink
Add initial implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
stellaraccident committed Feb 24, 2011
1 parent d379946 commit 48b36eb
Show file tree
Hide file tree
Showing 10 changed files with 1,003 additions and 0 deletions.
8 changes: 8 additions & 0 deletions .classpath
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="test"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
<classpathentry kind="output" path="bin"/>
</classpath>
2 changes: 2 additions & 0 deletions .gitignore
@@ -0,0 +1,2 @@
bin

17 changes: 17 additions & 0 deletions .project
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>java-websocket-client</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>
19 changes: 19 additions & 0 deletions src/net/rcode/wsclient/Framing.java
@@ -0,0 +1,19 @@
package net.rcode.wsclient;

import java.io.DataInputStream;
import java.io.DataOutputStream;

/**
* Base class for supporting different framing types on a websocket
* @author stella
*
*/
public class Framing {
public Message readMessage(DataInputStream input) throws Exception {
throw new UnsupportedOperationException();
}

public void sendMessage(DataOutputStream output, Message message) throws Exception {
throw new UnsupportedOperationException();
}
}
51 changes: 51 additions & 0 deletions src/net/rcode/wsclient/FramingDraft03.java
@@ -0,0 +1,51 @@
package net.rcode.wsclient;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.util.Arrays;

public class FramingDraft03 extends Framing {
@Override
public Message readMessage(DataInputStream input) throws Exception {
// TODO Auto-generated method stub
return super.readMessage(input);
}

@Override
public void sendMessage(DataOutputStream out, Message message) throws Exception {
byte[] data=message.getMessageData();
if (data==null) return;

int length=data.length;
int header1=message.getOpcode()&0xf;
int header2;

// Different paths based on length
if (length<=125) {
// All fits in one word
header2=length;
out.write(header1);
out.write(header2);
} else if (length<=32767) {
// 2 byte length
header2=126;
out.write(header1);
out.write(header2);
out.writeShort(length);
} else {
// 8 byte length
header2=127;
out.write(header1);
out.write(header2);
out.writeLong(length);
}

System.out.println("Wrote header for message length " + length + ": " + Integer.toHexString(header1) + " " + Integer.toHexString(header2));
System.out.println("Write data: " + Arrays.toString(data));

out.write(data);
out.flush();
System.out.println("Message sent");
}

}
62 changes: 62 additions & 0 deletions src/net/rcode/wsclient/FramingDraft76.java
@@ -0,0 +1,62 @@
package net.rcode.wsclient;

import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;

public class FramingDraft76 extends Framing {
@Override
public Message readMessage(DataInputStream input) throws Exception {
for (;;) {
int frameType=input.readUnsignedByte();
if ((frameType&0x80)==0x80) {
int length=0;
for (;;) {
int b=input.readUnsignedByte(),
bv=b&0x7f;
length=length*128 + bv;
if ((b&0x80)!=0x80) break;
}

byte[] data=new byte[length];
input.readFully(data);

if (frameType==0xff && length==0) {
// Close
// TODO: Graceful close
return null;
} else {
return new Message(Message.OPCODE_BINARY, data);
}
} else {
ByteArrayOutputStream accum=new ByteArrayOutputStream();
for (;;) {
int b=input.read();
if (b==0xff) break;
accum.write(b);
}

if (frameType==0) {
Message message=new Message(Message.OPCODE_TEXT, accum.toByteArray());
return message;
}
}
}
}

@Override
public void sendMessage(DataOutputStream output, Message message) throws Exception {
int opcode=message.getOpcode();
if (opcode==Message.OPCODE_PING) return; // Just ignore

if (opcode!=Message.OPCODE_TEXT) {
throw new IllegalArgumentException("Draft76 only supports text messages");
}

output.write(0);
output.write(message.getMessageData());
output.write(0xff);
output.flush();
}

}
53 changes: 53 additions & 0 deletions src/net/rcode/wsclient/Message.java
@@ -0,0 +1,53 @@
package net.rcode.wsclient;

import java.nio.charset.Charset;

public class Message {
private static final Charset UTF8=Charset.forName("UTF8");

// -- message opcodes
public static final int OPCODE_CONTINUATION=0;
public static final int OPCODE_CLOSE=1;
public static final int OPCODE_PING=2;
public static final int OPCODE_PONG=3;
public static final int OPCODE_TEXT=4;
public static final int OPCODE_BINARY=5;


private int opcode;
private byte[] messageData;

public Message(int opcode, byte[] messageData) {
this.opcode=opcode;
this.messageData=messageData;
}

public boolean isText() {
return opcode==OPCODE_TEXT;
}

public String getMessageText() {
if (isText()) return new String(messageData, UTF8);
else throw new IllegalStateException("Not text based message");
}

public int getOpcode() {
return opcode;
}

public byte[] getMessageData() {
return messageData;
}

@Override
public String toString() {
if (opcode==OPCODE_TEXT) return getMessageText();
else if (messageData!=null ){
StringBuilder ret=new StringBuilder();
for (byte b: messageData) {
ret.append(Integer.toHexString(b)).append(" ");
}
return ret.toString();
} else return "";
}
}
36 changes: 36 additions & 0 deletions src/net/rcode/wsclient/NetConfig.java
@@ -0,0 +1,36 @@
package net.rcode.wsclient;

import javax.net.SocketFactory;
import javax.net.ssl.SSLSocketFactory;

/**
* Class holding various network configurations
* @author stella
*
*/
public class NetConfig {
private SocketFactory plainSocketFactory;
private SocketFactory secureSocketFactory;

public void setPlainSocketFactory(SocketFactory plainSocketFactory) {
this.plainSocketFactory = plainSocketFactory;
}
public void setSecureSocketFactory(SocketFactory secureSocketFactory) {
this.secureSocketFactory = secureSocketFactory;
}

/**
* @return a value previously specified or system default
*/
public SocketFactory getPlainSocketFactory() {
if (plainSocketFactory==null) return SocketFactory.getDefault();
return plainSocketFactory;
}
/**
* @return a value previously specified or system default
*/
public SocketFactory getSecureSocketFactory() {
if (secureSocketFactory==null) return SSLSocketFactory.getDefault();
return secureSocketFactory;
}
}

0 comments on commit 48b36eb

Please sign in to comment.