You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

303 lines
11 KiB

import jdk.nashorn.internal.parser.JSONParser;
import javax.xml.bind.DatatypeConverter;
import java.io.*;
import java.net.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.NoSuchElementException;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Created by itsmy on 08.08.2016.
*/
public class client extends Thread {
private Socket socket;
private BufferedReader reader;
private OutputStreamWriter writer;
private OutputStream out;
private InputStream in;
public Boolean httpAuthed = false;
public Boolean socketAuthed = false;
public int socketID;
public void openSocket(Socket s) throws IOException {
socket = s;
out = socket.getOutputStream();
in = socket.getInputStream();
start();
}
public void run() {
socketID = ctServer.socketID;
ctServer.sockets.add(socketID, this);
console.socket(socketID,"New connection");
wsControl();
}
public void close(){
try{
if(socket.isClosed()){
return;
}
socket.close();
}
catch(IOException e){
}
if(socketAuthed){
ctServer.clientInfoList.remove(socketID);
}
ctServer.sessions[socketID] = false;
httpAuthed = false;
socketAuthed = false;
console.socket(socketID,"Disconnected");
this.interrupt();
}
public void wsControl(){
try{
handshake();
while (httpAuthed) {
String msg = readSocket();
sendSocket(msg);
//TODO: сделать проверку протокола
}
} finally {
close();
}
}
private String bytesToStringUTFCustom(int[] ints) {
char[] buffer = new char[ints.length];
for(int i = 0; i < buffer.length; i++) {
char c = (char) ints[i];
buffer[i] = c;
}
return new String(buffer);
}
private void handshake(){
try{
if(!httpAuthed) {
socket.setSoTimeout(2000);
String data = new Scanner(in, "UTF-8").useDelimiter("\\r\\n\\r\\n").next();
Matcher get = Pattern.compile("^GET").matcher(data);
if (get.find()) {
Matcher match = Pattern.compile("Sec-WebSocket-Key: (.*)").matcher(data);
match.find();
try {
byte[] response = ("HTTP/1.1 101 Switching Protocols\r\n"
+ "Connection: Upgrade\r\n"
+ "Upgrade: websocket\r\n"
+ "Sec-WebSocket-Accept: "
+ DatatypeConverter
.printBase64Binary(
MessageDigest
.getInstance("SHA-1")
.digest((match.group(1) + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
.getBytes("UTF-8")))
+ "\r\n\r\n")
.getBytes("UTF-8");
out.write(response, 0, response.length);
} catch (IOException e) {
console.out("Server Error:", e.toString());
} catch (NoSuchAlgorithmException e) {
console.out("Server Error:", e.toString());
}
socket.setSoTimeout(0);
httpAuthed = true;
console.socket(socketID,"Handshake accepted!");
}
}
}catch (SocketException e){
console.debug("исключение 22");
//TODO: написать исключение если сокет закрыт
}catch (NoSuchElementException e){
console.socket(socketID,"Handshake Timeout (2000ms)");
httpAuthed = false;
}
}
public Boolean sendSocket(String message){
byte[] response;
byte[] r;
try{
response = message.getBytes("UTF-8");
}catch (UnsupportedEncodingException e){
console.socket(socketID, "Unsupported encoding!");
return false;
}
catch (NullPointerException e){
return false;
}
if (message.length() < 126) {
r = new byte[response.length+2];
System.arraycopy(response,0,r,2,response.length);
r[0] = (byte) 129;
r[1] = (byte) (response.length);
}
else{
if (message.length() < 65535) {
r = new byte[response.length+4];
System.arraycopy(response,0,r,4,response.length);
r[0] = (byte) 129;
r[1] = (byte) 126;
r[2] = (byte) (response.length >>> 8);
r[3] = (byte) (response.length);
}
else{
if(response.length > Long.MAX_VALUE){
console.out("Socket Exception", "Too long message for sending! (>64bit)");
return false;
}
r = new byte[response.length+8];
System.arraycopy(response,0,r,8,response.length);
r[0] = (byte) 129;
r[1] = (byte) 127;
r[2] = (byte) (response.length >>> 56);
r[3] = (byte) (response.length >>> 48);
r[4] = (byte) (response.length >>> 40);
r[5] = (byte) (response.length >>> 32);
r[6] = (byte) (response.length >>> 24);
r[7] = (byte) (response.length >>> 16);
r[8] = (byte) (response.length >>> 8);
r[9] = (byte) (response.length);
}
}
try{
out.write(r, 0, r.length);
return true;
}catch(IOException e){
console.out("Socket Exeption", "Client socket is closed?! Closing socket connection!");
close();
return false;
}
}
public String readSocket(){
String out = "";
try
{
int[] MSG = new int[0];
int OPCOUNT = 1;
int LENGTH;
int KEYFRAME = 0;
int[] KEY = new int[4];
int OPCODE = in.read(); //читаем OPCODE byte
switch(OPCODE){
case -1: close(); //закрываем чтение потока при -1
return null;
case 136: close();
return null;
case 129:
LENGTH = in.read(); //читаем второй бит с данными о размере сообщения
//TODO: which и switch OPCOUNT - необходимо убрать
while(OPCOUNT < 4) {
switch (OPCOUNT){
case 1: switch (LENGTH){ //узнаем длину сообщения
default: KEYFRAME = 2;
break;
case 254: KEYFRAME = 4; //126-65535
break;
case 255: KEYFRAME = 10; //65535-...
break;
}
break;
case 2:
switch (KEYFRAME) {
case 2:
MSG = new int[LENGTH - 128];
break;
case 4:
LENGTH = (in.read() << 8) + (in.read());
MSG = new int[LENGTH];
break;
case 10:
LENGTH = (in.read() << 56)
+ (in.read() << 48)
+ (in.read() << 40)
+ (in.read() << 32)
+ (in.read() << 24)
+ (in.read() << 16)
+ (in.read() << 8)
+ (in.read());
MSG = new int[LENGTH];
break;
}
for (int i = 0; i < 4; i++) {
KEY[i] = in.read();
}
for (int j = 0; j < (MSG.length); j++) {
int enc = in.read();
MSG[j] = (byte) (enc ^ KEY[j & 0x3]);
}
break;
case 3:
if(MSG.length>0){
out = bytesToStringUTFCustom(MSG);
}
else{
return null;
}
}
OPCOUNT++;
}
}
}catch(IOException e){
console.out("Socket Exception", "Client socket is closed?! Closing socket connection!");
close();
}
console.socket(socketID, "Message: "+out);
return out;
}
//
// public Socket getSocketbyId(socketID){
// if(socket.closed)
// return this.socket;
// }
// public void sControl(){
// try{
// while (true) {
// String input = reader.readLine();
// if(input == null){break;}
// Pattern main = Pattern.compile(";");
// if(!httpAuthed) {
// if (!ctServer.checkClient(this, main.split(input))) {
// writer.println("CONNECT_DENIED");
// break;
// }
// }
// switch (input) {
// case "EXIT":
// socket.close();
// break;
// default:
// writer.println("Client info - " + socket.getRemoteSocketAddress().toString());
// console.out("Socket "+socketID+" Message",input);
// }
// }
// } catch (IOException e) {
// console.out("Server Error:", e.toString());
// } finally {
// close();
// try {
// socket.close();
// console.out("Server", "Socket "+socketID+" disconnected!");
// } catch (IOException e) {
// console.out("Server","System socket closing error!");
// }catch (NullPointerException e){
//
// }
//
// }
// }
}