changeset 0:5a50d4b48bf9

init
author kazz <kazz@cr.ie.u-ryukyu.ac.jp>
date Wed, 19 Jan 2011 00:16:26 +0900
parents
children 4c2ddaa9b998
files .classpath .project src/AcceptHandler.java src/Handler.java src/IOHandler.java src/MatcherTest.java src/WebSocketServer.java
diffstat 7 files changed, 219 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.classpath	Wed Jan 19 00:16:26 2011 +0900
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.project	Wed Jan 19 00:16:26 2011 +0900
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>WebSocket</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>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/AcceptHandler.java	Wed Jan 19 00:16:26 2011 +0900
@@ -0,0 +1,24 @@
+import java.io.IOException;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+
+
+public class AcceptHandler implements Handler {
+
+	@Override
+	public void handle(SelectionKey key) {
+		ServerSocketChannel ssChannel = (ServerSocketChannel)key.channel();
+		try {
+			SocketChannel sChannel = ssChannel.accept();
+			if (sChannel == null)
+				return;
+			sChannel.configureBlocking(false);
+			sChannel.register(key.selector(), SelectionKey.OP_READ, new IOHandler());
+			
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Handler.java	Wed Jan 19 00:16:26 2011 +0900
@@ -0,0 +1,6 @@
+import java.nio.channels.SelectionKey;
+
+
+public interface Handler {
+	public void handle(SelectionKey key);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/IOHandler.java	Wed Jan 19 00:16:26 2011 +0900
@@ -0,0 +1,113 @@
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.SocketChannel;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.HashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+
+public class IOHandler implements Handler {
+	public static int BUFFERSIZE = 8192;
+	public HashMap<String, String> map = new HashMap<String, String>();
+	
+	@Override
+	public void handle(SelectionKey key) {
+		if (!key.isReadable())
+			return;
+		SocketChannel sChannel = (SocketChannel)key.channel();
+		ByteBuffer buffer = ByteBuffer.allocate(BUFFERSIZE);
+		try {
+			int num;
+			if ((num = sChannel.read(buffer)) > 0) {
+				String str = new String(buffer.array());
+				Pattern pat = Pattern.compile("((([^\n\r]+): ([^\n\r]+))|(^GET ([/A-Za-z]+) HTTP/1.1))");
+				Matcher mat = pat.matcher(str);
+				while (mat.find()) {
+					if (mat.group(6) != null) {
+						map.put("path", mat.group(6));
+					}
+					if (mat.group(3) != null && mat.group(4) != null) {
+						map.put(mat.group(3), mat.group(4));
+					}
+				}
+				buffer.position(num - 8);
+				byte[] key3 = new byte[8];
+				buffer.get(key3);
+				byte[] resCode = generateResponseCode(key3);
+				ByteBuffer response = generateResponse(resCode);
+				sChannel.write(response);
+				System.out.println("sent response");
+			}
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+	}
+	
+	private ByteBuffer generateResponse(byte[] resCode) {
+		ByteBuffer response = ByteBuffer.allocate(BUFFERSIZE);
+		response.put("HTTP/1.1 101 WebSocket Protocol Handshake\r\n".getBytes());
+		response.put("Upgrade: WebSocket\r\n".getBytes());
+		response.put("Connection: ".getBytes());
+		response.put(map.get("Connection").getBytes());
+		response.put("\r\n".getBytes());
+		response.put("Sec-WebSocket-Origin: ".getBytes());
+		response.put(map.get("Origin").getBytes());
+		response.put("\r\n".getBytes());
+		response.put("Sec-WebSocket-Location: ".getBytes());
+		response.put(generateWebSocketAddress(map.get("Origin"), map.get("path")).getBytes());
+		response.put("\r\n".getBytes());
+		String s;
+		if ((s = map.get("Sec-WebSocket-Protocol")) != null) {
+			response.put("Sec-WebSocket-Protocol: ".getBytes());
+			response.put(s.getBytes());
+			response.put("\r\n".getBytes());
+		}		
+		response.put("\r\n".getBytes());
+		response.put(resCode);
+		//response.put("\r\n".getBytes());
+		response.limit(response.position());
+		response.rewind();
+		return response;
+	}
+	
+	private String generateWebSocketAddress(String origin, String path) {
+		return origin.replaceAll("https*", "ws") + ":" + WebSocketServer.port + path;
+	}
+
+	private byte[] generateResponseCode(byte[] key3) {
+		int val1 = generateResponseCodeValue(map.get("Sec-WebSocket-Key1"));
+		int val2 = generateResponseCodeValue(map.get("Sec-WebSocket-Key2"));
+		ByteBuffer buf = ByteBuffer.allocate(16);
+		buf.order(ByteOrder.BIG_ENDIAN);
+		buf.putInt(val1);
+		buf.putInt(val2);
+		buf.put(key3);
+		byte[] code = null;
+		try {
+			MessageDigest digest = MessageDigest.getInstance("MD5");
+			code = digest.digest(buf.array());
+		} catch (NoSuchAlgorithmException e) {
+			e.printStackTrace();
+		}
+		return code;
+	} 
+	
+	private int generateResponseCodeValue(String str) {
+		char[] ch = str.toCharArray();
+		int val = 0;
+		int spNum = 0;
+		for (char c : ch) {
+			if (c == ' ') {
+				spNum++;
+			} else if ('0' <= c && c <= '9') {
+				val *= 10;
+				val += c - '0';
+			}
+		}
+		return val / spNum;
+	}
+}
Binary file src/MatcherTest.java has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/WebSocketServer.java	Wed Jan 19 00:16:26 2011 +0900
@@ -0,0 +1,53 @@
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.ServerSocketChannel;
+
+public class WebSocketServer {
+	public static int port;
+	private ServerSocketChannel ssChannel;
+	private Selector selector;
+	private boolean running = true;
+	
+	public WebSocketServer(int port) {
+		this.port = port;
+		try {
+			ssChannel = ServerSocketChannel.open();
+			ssChannel.socket().bind(new InetSocketAddress(port));
+			ssChannel.configureBlocking(false);
+			selector = Selector.open();
+			ssChannel.register(selector, SelectionKey.OP_ACCEPT, new AcceptHandler());
+		} catch (IOException e) {
+			System.out.println("Can't open ServerSocketChannel.");
+			e.printStackTrace();
+		}
+	}
+	
+	public void mainLoop() {
+		
+		while (running) {
+			try {
+				int keyCount = selector.select(0);
+				for (SelectionKey key : selector.selectedKeys()) {
+					Handler handler = (Handler) key.attachment();
+					handler.handle(key);
+					selector.selectedKeys().remove(key);
+				}
+				
+			} catch (IOException e) {
+				e.printStackTrace();
+			}
+		} 
+		
+	}
+	
+	/**
+	 * @param args
+	 */
+	public static void main(String[] args) {
+		WebSocketServer wsServer = new WebSocketServer(11000);
+		wsServer.mainLoop();
+	}
+
+}