Android Open Source - android_lucidchat Web Socket Client






From Project

Back to project page android_lucidchat.

License

The source code is released under:

Apache License

If you think the Android project android_lucidchat listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package fi.harism.lucidchat.websocket;
/*ww  w. ja  v a  2  s. c  o  m*/
import java.io.EOFException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.URI;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.List;

import javax.net.SocketFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;

import org.apache.http.Header;
import org.apache.http.HttpException;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpResponseException;
import org.apache.http.message.BasicLineParser;
import org.apache.http.message.BasicNameValuePair;

import android.os.Handler;
import android.os.HandlerThread;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;

public class WebSocketClient {
  private static TrustManager[] sTrustManagers;

  private static final String TAG = "WebSocketClient";

  public static void setTrustManagers(TrustManager[] tm) {
    sTrustManagers = tm;
  }

  private List<BasicNameValuePair> mExtraHeaders;
  private Handler mHandler;
  private HandlerThread mHandlerThread;
  private Listener mListener;
  private HybiParser mParser;
  private final Object mSendLock = new Object();

  private Socket mSocket;

  private Thread mThread;

  private URI mURI;

  public WebSocketClient(URI uri, Listener listener,
      List<BasicNameValuePair> extraHeaders) {
    mURI = uri;
    mListener = listener;
    mExtraHeaders = extraHeaders;
    mParser = new HybiParser(this);

    mHandlerThread = new HandlerThread("websocket-thread");
    mHandlerThread.start();
    mHandler = new Handler(mHandlerThread.getLooper());
  }

  public void connect() {
    if (mThread != null && mThread.isAlive()) {
      return;
    }

    mThread = new Thread(new Runnable() {
      @Override
      public void run() {
        try {
          int port = (mURI.getPort() != -1) ? mURI.getPort() : ((mURI
              .getScheme().equals("wss") || mURI.getScheme()
              .equals("https")) ? 443 : 80);

          String path = TextUtils.isEmpty(mURI.getPath()) ? "/"
              : mURI.getPath();
          if (!TextUtils.isEmpty(mURI.getQuery())) {
            path += "?" + mURI.getQuery();
          }

          String originScheme = mURI.getScheme().equals("wss") ? "https"
              : "http";
          URI origin = new URI(originScheme, "//" + mURI.getHost(),
              null);

          SocketFactory factory = (mURI.getScheme().equals("wss") || mURI
              .getScheme().equals("https")) ? getSSLSocketFactory()
              : SocketFactory.getDefault();
          mSocket = factory.createSocket(mURI.getHost(), port);

          PrintWriter out = new PrintWriter(mSocket.getOutputStream());
          out.print("GET " + path + " HTTP/1.1\r\n");
          out.print("Upgrade: websocket\r\n");
          out.print("Connection: Upgrade\r\n");
          out.print("Host: " + mURI.getHost() + "\r\n");
          out.print("Origin: " + origin.toString() + "\r\n");
          out.print("Sec-WebSocket-Key: " + createSecret() + "\r\n");
          out.print("Sec-WebSocket-Version: 13\r\n");
          if (mExtraHeaders != null) {
            for (NameValuePair pair : mExtraHeaders) {
              out.print(String.format("%s: %s\r\n",
                  pair.getName(), pair.getValue()));
            }
          }
          out.print("\r\n");
          out.flush();

          HybiParser.HappyDataInputStream stream = new HybiParser.HappyDataInputStream(
              mSocket.getInputStream());

          // Read HTTP response status line.
          StatusLine statusLine = parseStatusLine(readLine(stream));
          if (statusLine == null) {
            throw new HttpException(
                "Received no reply from server.");
          } else if (statusLine.getStatusCode() != HttpStatus.SC_SWITCHING_PROTOCOLS) {
            throw new HttpResponseException(statusLine
                .getStatusCode(), statusLine.getReasonPhrase());
          }

          // Read HTTP response headers.
          String line;
          while (!TextUtils.isEmpty(line = readLine(stream))) {
            Header header = parseHeader(line);
            if (header.getName().equals("Sec-WebSocket-Accept")) {
              // FIXME: Verify the response...
            }
          }

          mListener.onConnect();

          // Now decode websocket frames.
          mParser.start(stream);

        } catch (EOFException ex) {
          Log.d(TAG, "WebSocket EOF!", ex);
          mListener.onDisconnect(0, "EOF");

        } catch (SSLException ex) {
          // Connection reset by peer
          Log.d(TAG, "Websocket SSL error!", ex);
          mListener.onDisconnect(0, "SSL");

        } catch (Exception ex) {
          mListener.onError(ex);
        }
      }
    });
    mThread.start();
  }

  private String createSecret() {
    byte[] nonce = new byte[16];
    for (int i = 0; i < 16; i++) {
      nonce[i] = (byte) (Math.random() * 256);
    }
    return Base64.encodeToString(nonce, Base64.DEFAULT).trim();
  }

  public void disconnect() {
    if (mSocket != null) {
      mHandler.post(new Runnable() {
        @Override
        public void run() {
          try {
            mSocket.close();
            mSocket = null;
          } catch (IOException ex) {
            Log.d(TAG, "Error while disconnecting", ex);
            mListener.onError(ex);
          }
        }
      });
    }
  }

  public Listener getListener() {
    return mListener;
  }

  private SSLSocketFactory getSSLSocketFactory()
      throws NoSuchAlgorithmException, KeyManagementException {
    SSLContext context = SSLContext.getInstance("TLS");
    context.init(null, sTrustManagers, null);
    return context.getSocketFactory();
  }

  private Header parseHeader(String line) {
    return BasicLineParser.parseHeader(line, new BasicLineParser());
  }

  private StatusLine parseStatusLine(String line) {
    if (TextUtils.isEmpty(line)) {
      return null;
    }
    return BasicLineParser.parseStatusLine(line, new BasicLineParser());
  }

  // Can't use BufferedReader because it buffers past the HTTP data.
  private String readLine(HybiParser.HappyDataInputStream reader)
      throws IOException {
    int readChar = reader.read();
    if (readChar == -1) {
      return null;
    }
    StringBuilder string = new StringBuilder("");
    while (readChar != '\n') {
      if (readChar != '\r') {
        string.append((char) readChar);
      }

      readChar = reader.read();
      if (readChar == -1) {
        return null;
      }
    }
    return string.toString();
  }

  public void send(byte[] data) {
    sendFrame(mParser.frame(data));
  }

  public void send(String data) {
    sendFrame(mParser.frame(data));
  }

  void sendFrame(final byte[] frame) {
    mHandler.post(new Runnable() {
      @Override
      public void run() {
        try {
          synchronized (mSendLock) {
            OutputStream outputStream = mSocket.getOutputStream();
            outputStream.write(frame);
            outputStream.flush();
          }
        } catch (IOException e) {
          mListener.onError(e);
        }
      }
    });
  }

  public interface Listener {
    public void onConnect();

    public void onDisconnect(int code, String reason);

    public void onError(Exception error);

    public void onMessage(byte[] data);

    public void onMessage(String message);
  }
}




Java Source Code List

fi.harism.lucidchat.ContainerCenter.java
fi.harism.lucidchat.ContainerMenu.java
fi.harism.lucidchat.ConversationScrollView.java
fi.harism.lucidchat.DialogConnect.java
fi.harism.lucidchat.MainActivity.java
fi.harism.lucidchat.PreferencesHandler.java
fi.harism.lucidchat.SplashActivity.java
fi.harism.lucidchat.api.Channel.java
fi.harism.lucidchat.api.ChatConnection.java
fi.harism.lucidchat.api.ChatHandler.java
fi.harism.lucidchat.api.Conversation.java
fi.harism.lucidchat.api.Message.java
fi.harism.lucidchat.api.User.java
fi.harism.lucidchat.quickaction.ActionItem.java
fi.harism.lucidchat.quickaction.PopupWindows.java
fi.harism.lucidchat.quickaction.QuickAction.java
fi.harism.lucidchat.websocket.HybiParser.java
fi.harism.lucidchat.websocket.WebSocketClient.java