defuze.me
Client
|
00001 /************************************************************************** 00002 ** defuze.me Epitech Innovative Project 00003 ** 00004 ** Copyright 2010-2011 00005 ** Athena Calmettes - Jocelyn De La Rosa - Francois Gaillard 00006 ** Adrien Jarthon - Alexandre Moore - Luc Peres - Arnaud Sellier 00007 ** 00008 ** All rights reserved. 00009 **************************************************************************/ 00010 00011 #include "websocket.hpp" 00012 #include "logger.hpp" 00013 #include <QHttpResponseHeader> 00014 #include <QCryptographicHash> 00015 #include <QApplication> 00016 00017 using namespace Network; 00018 00019 WebSocket::WebSocket(const QString& uri) : uri(uri), frame(0) 00020 { 00021 handshaking = false; 00022 QObject::connect(this, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(errorSlot(QAbstractSocket::SocketError))); 00023 QObject::connect(this, SIGNAL(connected()), SLOT(handshake())); 00024 QObject::connect(this, SIGNAL(readyRead()), SLOT(receive())); 00025 } 00026 00027 WebSocket::~WebSocket() 00028 { 00029 } 00030 00031 void WebSocket::generateToken() 00032 { 00033 token.resize(16); 00034 for(int i = 0; i < 16; i++) 00035 token[i] = qrand() % 0xFF; 00036 } 00037 00038 bool WebSocket::validToken(const QByteArray& accept) 00039 { 00040 QByteArray hash = QCryptographicHash::hash(token.toBase64() + WebSocketSecret, QCryptographicHash::Sha1); 00041 return (accept == hash.toBase64()); 00042 } 00043 00044 void WebSocket::connect() 00045 { 00046 generateToken(); 00047 if (isOpen()) 00048 { 00049 disconnectFromHost(); 00050 readAll(); 00051 } 00052 buffer.clear(); 00053 connectToHost(uri.host(), uri.port()); 00054 Logger::log(QString("WebSocket: connecting to %1:%2").arg(uri.host()).arg(uri.port())); 00055 } 00056 00057 void WebSocket::send(WebFrame& frame) 00058 { 00059 while (frame.remainingFrames() > 0) 00060 { 00061 QByteArray data = frame.encoded(); 00062 write(data); 00063 qApp->processEvents(); 00064 } 00065 } 00066 00067 void WebSocket::onMessage(const QObject* receiver, const char* method) 00068 { 00069 QObject::connect(this, SIGNAL(messageSignal(QByteArray)), receiver, method); 00070 } 00071 00072 void WebSocket::onOpen(const QObject* receiver, const char* method) 00073 { 00074 QObject::connect(this, SIGNAL(openSignal()), receiver, method); 00075 } 00076 00077 void WebSocket::onClose(const QObject* receiver, const char* method) 00078 { 00079 QObject::connect(this, SIGNAL(closeSignal(QString)), receiver, method); 00080 } 00081 00082 void WebSocket::errorSlot(QAbstractSocket::SocketError error) 00083 { 00084 Q_UNUSED(error); 00085 Logger::log(QString("WebSocket: %1").arg(errorString())); 00086 emit closeSignal(errorString()); 00087 } 00088 00089 void WebSocket::handshake() 00090 { 00091 handshaking = true; 00092 QString path = uri.path(); 00093 if (uri.encodedQuery().size() > 0) 00094 path += "?" + QString::fromUtf8(uri.encodedQuery()); 00095 write(QString("GET %1 HTTP/1.1\r\n").arg(path).toUtf8()); 00096 write(QString("Host: %1\r\n").arg(uri.host()).toUtf8()); 00097 write("Upgrade: websocket\r\n"); 00098 write("Connection: Upgrade\r\n"); 00099 write(QString("Sec-WebSocket-Key: %1\r\n").arg(QString::fromUtf8(token.toBase64())).toUtf8()); 00100 write("Sec-WebSocket-Protocol: chat\r\n"); 00101 write("Sec-WebSocket-Version: 8\r\n"); 00102 write("\r\n"); 00103 } 00104 00105 bool WebSocket::parseHandshake() 00106 { 00107 if (!canReadLine()) 00108 return false; 00109 00110 QByteArray data = readLine(); 00111 if (data == "\r\n") // Header end 00112 { 00113 QHttpResponseHeader header(QString::fromUtf8(buffer)); 00114 if (header.statusCode() == 101 && 00115 header.value("Upgrade") == "websocket" && 00116 validToken(header.value("Sec-WebSocket-Accept").toUtf8())) 00117 { 00118 handshaking = false; 00119 Logger::log("WebSocket: connection ok"); 00120 buffer.clear(); 00121 emit openSignal(); 00122 } 00123 else 00124 { 00125 Logger::log(QString("WebSocket: invalid handshake")); 00126 emit closeSignal(tr("Invalid handshake")); 00127 disconnectFromHost(); 00128 return false; 00129 } 00130 } 00131 else 00132 buffer += data; 00133 return true; 00134 } 00135 00136 bool WebSocket::parseFrame() 00137 { 00138 if (frame) 00139 frame->append(this); 00140 else 00141 { 00142 frame = WebFrame::fromStream(this); 00143 if (!frame) 00144 { 00145 Logger::log("WebSocket: invalid framing data"); 00146 emit closeSignal(tr("Invalid framing data")); 00147 disconnectFromHost(); 00148 return false; 00149 } 00150 } 00151 if (frame && frame->complete()) 00152 { 00153 emit messageSignal(frame->content()); 00154 delete frame; 00155 frame = 0; 00156 } 00157 return true; 00158 } 00159 00160 void WebSocket::receive() 00161 { 00162 while (bytesAvailable()) 00163 { 00164 if (handshaking) 00165 { 00166 if (!parseHandshake()) 00167 return; 00168 } 00169 else 00170 { 00171 if (!parseFrame()) 00172 return; 00173 } 00174 } 00175 }