com.googlecode.lineblog.websocket.TokenThread.java Source code

Java tutorial

Introduction

Here is the source code for com.googlecode.lineblog.websocket.TokenThread.java

Source

/**
 * License
 * 
 * Licensed under the GNU GPL v3
 * http://www.gnu.org/licenses/gpl.html
 * 
 */
package com.googlecode.lineblog.websocket;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.security.MessageDigest;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * 
 * @author lichangshu E-mail:lchshu001@gmail.com
 * @version 2011-9-30 ?03:30:17
 */
public class TokenThread extends Thread {

    public static final String GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
    public static final String HEADER_CODE = "iso-8859-1";
    public static final String PROTOCOL = "chat";
    public static final int SPLITVERSION = 6;

    private int webSocketVersion = 0;
    private String token;
    private OutputStream out;
    private InputStream in;
    private Socket socket;
    private static Log log = LogFactory.getLog(TokenThread.class);

    public TokenThread(Socket socket) throws IOException {
        if (socket == null)
            throw new RuntimeException("socket is not null!");
        this.socket = socket;
        this.in = new BufferedInputStream(this.socket.getInputStream());
        this.out = new BufferedOutputStream(this.socket.getOutputStream());
        this.accept();//?
    }

    public synchronized void sendMessage(String message) throws IOException {
        if (webSocketVersion < 1)
            HelpUtil.writeFrame(out, message);
        else
            WebSocketFram.writeWebSocketV6Fram(out, message);
        out.flush();
    }

    public boolean socketIsClosed() {
        return this.socket.isClosed();
    }

    public void logOut() {
        if (socketIsClosed())
            return;
        try {
            if (webSocketVersion <= 0)
                out.write(WebSocketFram.getCloseV1To6());
            if (webSocketVersion < 6)
                out.write(WebSocketFram.getCloseV1To6());
            else
                out.write(WebSocketFram.getCloseV7UP());
            out.flush();
            this.in.close();
            this.socket.close();
            TokenManage.getTokenManage().removeTokenThread(this.token);
            log.info("[" + this.token + "] has logout!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        try {
            while (true) {
                byte[] bts;
                if (webSocketVersion < SPLITVERSION)
                    bts = HelpUtil.readFrame(in);
                else {
                    WebSocketFram ws = WebSocketFram.parseWebSocketV6Fram(in);
                    bts = WebSocketFram.readWebSocketV6(in, ws);
                }
                if (bts == null || bts.length <= 0)
                    return;
                String message = new String(bts, HelpUtil.WEB_SOCKET_CHARSET);
                log.debug(token + ":" + new String(bts, HelpUtil.WEB_SOCKET_CHARSET));
                //??
                try {
                    TokenManage.getTokenManage().executCommond(this.getToken(), message);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            this.logOut();
        }
    }

    public String getToken() {
        return token;
    }

    /**
     * ?
     */
    private void accept() {
        log.info("Start : " + socket.getRemoteSocketAddress().toString());
        try {
            String reqestLine = new String(HelpUtil.readLine(in));
            // headers : HTTP request header!
            Map<String, String> requestHeaders = new HashMap<String, String>();
            while (true) {
                byte[] bts = HelpUtil.readLine(in);
                if (bts[0] == '\r' && bts[1] == '\n') {
                    break;
                }
                String line = new String(bts);
                int mh = line.indexOf(':');
                requestHeaders.put(line.substring(0, mh), line.substring(mh + 1).trim());
            }
            //HTTP request headers!
            if (log.isDebugEnabled()) {
                log.debug("-- request : headers --");
                log.debug(reqestLine);
                for (String key : requestHeaders.keySet()) {
                    log.debug(key + ": " + requestHeaders.get(key));
                }
            }

            // HTTP response header!
            Map<String, String> resMap = new HashMap<String, String>();
            String responsLine = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n";
            resMap.put("Upgrade", "WebSocket");
            resMap.put("Connection", "Upgrade");
            if (requestHeaders.get("Origin") != null)
                resMap.put("Sec-WebSocket-Origin", requestHeaders.get("Origin"));
            resMap.put("Sec-WebSocket-Location", "ws://" + requestHeaders.get("Host").trim() + "/");

            String token = null;
            byte[] content = null;
            //Sec-WebSocket-Version: 6  ? 
            String version = requestHeaders.get("Sec-WebSocket-Version");
            if (version != null) {
                webSocketVersion = new Integer(version);
            }
            if (webSocketVersion >= 4) {
                String code = requestHeaders.get("Sec-WebSocket-Key") + GUID;
                byte[] bts = MessageDigest.getInstance("SHA1").digest(code.getBytes(HEADER_CODE));
                code = HelpUtil.getBASE64(bts);
                resMap.put("Sec-WebSocket-Accept", code);
                //Sec-WebSocket-Protocol: chat
                resMap.put("Sec-WebSocket-Protocol", PROTOCOL);
                if (requestHeaders.get("Sec-WebSocket-Version") != null)
                    resMap.put("Sec-WebSocket-Version", requestHeaders.get("Sec-WebSocket-Version"));
                if (requestHeaders.get("Sec-WebSocket-Origin") != null)
                    resMap.put("Sec-WebSocket-Origin", requestHeaders.get("Sec-WebSocket-Origin"));
                token = HelpUtil.md5(code);
            } else {// 0 -- 3
                    // the end 8 Byte!
                int len = 8; // in.available();
                byte[] key3 = new byte[len];
                if (in.read(key3) != len)
                    throw new RuntimeException();
                log.debug(HelpUtil.formatBytes(key3));
                String key1 = requestHeaders.get("Sec-WebSocket-Key1");
                String key2 = requestHeaders.get("Sec-WebSocket-Key2");
                int k1 = HelpUtil.parseWebsokcetKey(key1);
                int k2 = HelpUtil.parseWebsokcetKey(key2);

                byte[] sixteenByte = new byte[16];
                System.arraycopy(HelpUtil.intTo4Byte(k1), 0, sixteenByte, 0, 4);
                System.arraycopy(HelpUtil.intTo4Byte(k2), 0, sixteenByte, 4, 4);
                System.arraycopy(key3, 0, sixteenByte, 8, 8);
                byte[] md5 = MessageDigest.getInstance("MD5").digest(sixteenByte);
                content = md5;
                log.debug("response content : " + HelpUtil.formatBytes(md5));
                token = HelpUtil.md5(md5);
            }
            log.info("START , token [" + token + "]");

            //return user message
            out.write(responsLine.getBytes(HEADER_CODE));
            log.debug(responsLine);
            for (String key : resMap.keySet()) {
                out.write((key + ": " + resMap.get(key) + "\r\n").getBytes(HEADER_CODE));
                if (log.isDebugEnabled())
                    log.debug(key + ": " + resMap.get(key));
            }
            out.write("\r\n".getBytes());

            if (content != null)
                out.write(content);

            // return user the token!
            this.sendMessage(token);//HelpUtil.writeFrame(out, token);
            out.flush();

            this.token = token;
            TokenManage.getTokenManage().putTokenThread(token, this);

        } catch (Exception e) {
            e.printStackTrace();
            if (socket != null)
                try {
                    socket.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
        }
    }

    public int getWebSocketVersion() {
        return webSocketVersion;
    }
}