Ejemplo n.º 1
0
void receiveRequests()
{
	// service ready
	klog("spawner server ready");

	// defining size for messages
	const size_t requestLenMax = sizeof(MessageHeader) + sizeof(SpawnCommandSpawnRequest) + 1024;

	while (true)
	{
		// creating buffer for message
		uint8_t requestBuffer[requestLenMax];

		// receive incoming request
		MessageReceiveStatus stat = ReceiveMessage(requestBuffer, requestLenMax);

		if (stat != MESSAGE_RECEIVE_STATUS_SUCCESSFUL) protocolError("receiving command failed with code %i", stat);

		MessageHeader *header = (MessageHeader*) requestBuffer;
		SpawnCommandHeader *commandHeader = (SpawnCommandHeader*) MESSAGE_CONTENT(header);

		if (commandHeader->command == SPAWN_COMMAND_SPAWN_REQUEST) processSpawnRequest((SpawnCommandSpawnRequest*) commandHeader, header->sender, header->transaction);
		else if (commandHeader->command == SPAWN_COMMAND_SHUTDOWN_MACHINE || commandHeader->command == SPAWN_COMMAND_REBOOT_MACHINE) processHealtMachine(commandHeader->command);
		else protocolError("received unknown command: code %i, task %i", commandHeader->command, header->sender);
	}
}
Ejemplo n.º 2
0
 void Protocol::handleSocketError(){
     switch (error()){
     case QAbstractSocket::RemoteHostClosedError:
         emit closed();
         break;
     case QAbstractSocket::HostNotFoundError:
         protocolError(tr("The host was not found. Please check the "
                  "host name and port settings."));
         break;
     case QAbstractSocket::ConnectionRefusedError:
         protocolError(tr("The connection was refused by the server. "
                  "Check that the host name and port "
                  "settings are correct."
                  ));
         break;
     default:
         emit protocolError(errorString());
     }
 }
Ejemplo n.º 3
0
void ExistenceChecker::onError(const std::string &address, Kullo::Api::NetworkError error)
{
    setLocked(false);

    switch (error) {
    case Kullo::Api::NetworkError::Server:
        Log.e() << "Server error.";
        emit serverError(QString::fromStdString(address));
        break;
    case Kullo::Api::NetworkError::Protocol:
        Log.e() << "Protocol error.";
        emit protocolError(QString::fromStdString(address));
        break;
    case Kullo::Api::NetworkError::Connection:
        Log.e() << "Connection error.";
        emit networkError(QString::fromStdString(address));
        break;
    default:
        kulloAssert(false);
    }
}
void EnginioBackendConnection::onSocketReadyRead()
{
    //     WebSocket Protocol (RFC6455)
    //     Base Framing Protocol
    //     http://tools.ietf.org/html/rfc6455#section-5.2
    //
    //      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    //     +-+-+-+-+-------+-+-------------+-------------------------------+
    //     |F|R|R|R| opcode|M| Payload len |    Extended payload length    |
    //     |I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
    //     |N|V|V|V|       |S|             |   (if payload len==126/127)   |
    //     | |1|2|3|       |K|             |                               |
    //     +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
    //     |     Extended payload length continued, if payload len == 127  |
    //     + - - - - - - - - - - - - - - - +-------------------------------+
    //     |                               |Masking-key, if MASK set to 1  |
    //     +-------------------------------+-------------------------------+
    //     | Masking-key (continued)       |          Payload Data         |
    //     +-------------------------------- - - - - - - - - - - - - - - - +
    //     :                     Payload Data continued ...                :
    //     + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
    //     |                     Payload Data continued ...                |
    //     +---------------------------------------------------------------+

    while (_tcpSocket->bytesAvailable()) {
        switch (_protocolDecodeState) {
        case HandshakePending: {
            // The response is closed by a CRLF line on its own (e.g. ends with two newlines).
            while (_handshakeReply.isEmpty()
                   || (!_handshakeReply.endsWith(QString(CRLF % CRLF).toUtf8())
                   // According to documentation QIODevice::readLine replaces newline characters on
                   // Windows with '\n', so just to be on the safe side:
                   && !_handshakeReply.endsWith(QByteArrayLiteral("\n\n")))) {

                if (!_tcpSocket->bytesAvailable())
                    return;

                _handshakeReply.append(_tcpSocket->readLine());
            }

            QString response = QString::fromUtf8(_handshakeReply);
            _handshakeReply.clear();

            int statusCode = extractResponseStatus(response);
            QString secWebSocketAccept = extractResponseHeader(SecWebSocketAcceptHeader, response, /* ignoreCase */ false);
            bool hasValidKey = secWebSocketAccept == gBase64EncodedSha1VerificationKey;

            if (statusCode != 101 || !hasValidKey
                    || extractResponseHeader(UpgradeHeader, response) != QStringLiteral("websocket")
                    || extractResponseHeader(ConnectionHeader, response) != QStringLiteral("upgrade")
                    )
                return protocolError("Handshake failed!");

            _keepAliveTimer.start(TwoMinutes, this);
            _protocolDecodeState = FrameHeaderPending;
            emit stateChanged(ConnectedState);
        } // Fall-through.

        case FrameHeaderPending: {
            if (quint64(_tcpSocket->bytesAvailable()) < DefaultHeaderLength)
                return;

            // Large payload.
            if (_payloadLength == LargePayloadMarker) {
                if (quint64(_tcpSocket->bytesAvailable()) < LargePayloadHeaderLength)
                    return;

                char data[LargePayloadHeaderLength];
                if (quint64(_tcpSocket->read(data, LargePayloadHeaderLength)) != LargePayloadHeaderLength)
                    return protocolError("Reading large payload length failed!");

                if (data[0] & MSB)
                    return protocolError("The most significant bit of a large payload length must be 0!", MessageTooBigCloseStatus);

                // 8 bytes interpreted as a 64-bit unsigned integer
                _payloadLength = qFromBigEndian<quint64>(reinterpret_cast<uchar*>(data));
                _protocolDecodeState = PayloadDataPending;

                break;
            }

            char data[DefaultHeaderLength];
            if (quint64(_tcpSocket->read(data, DefaultHeaderLength)) != DefaultHeaderLength)
                return protocolError("Reading header failed!");

            if (!_payloadLength) {
                // This is the initial frame header data.
                _isFinalFragment = (data[0] & FIN);
                _protocolOpcode = static_cast<WebSocketOpcode>(data[0] & OPC);
                _isPayloadMasked = (data[1] & MSK);
                _payloadLength = (data[1] & LEN);

                if (_isPayloadMasked)
                    return protocolError("Invalid masked frame received from server.");

                // For data length 0-125 LEN is the payload length.
                if (_payloadLength < NormalPayloadMarker)
                    _protocolDecodeState = PayloadDataPending;

            } else {
                Q_ASSERT(_payloadLength == NormalPayloadMarker);
                // Normal sized payload: 2 bytes interpreted as the payload
                // length expressed in network byte order (e.g. big endian).
                _payloadLength = qFromBigEndian<quint16>(reinterpret_cast<uchar*>(data));
                _protocolDecodeState = PayloadDataPending;
            }

            break;
        }

        case PayloadDataPending: {
            if (static_cast<quint64>(_tcpSocket->bytesAvailable()) < _payloadLength)
                return;

            if (_protocolOpcode == ConnectionCloseOp) {
                WebSocketCloseStatus closeStatus = UnknownCloseStatus;
                if (_payloadLength >= DefaultHeaderLength) {
                    char data[DefaultHeaderLength];
                    if (quint64(_tcpSocket->read(data, DefaultHeaderLength)) != DefaultHeaderLength)
                        return protocolError("Reading connection close status failed!");

                     closeStatus = static_cast<WebSocketCloseStatus>(qFromBigEndian<quint16>(reinterpret_cast<uchar*>(data)));

                     // The body may contain UTF-8-encoded data with value /reason/,
                     // the interpretation of this data is however not defined by the
                     // specification. Further more the data is not guaranteed to be
                     // human readable, thus it is safe for us to just discard the rest
                     // of the message at this point.
                }

                qDebug() << "Connection closed by the server with status:" << closeStatus;

                QJsonObject data;
                data[EnginioString::messageType] = QStringLiteral("close");
                data[EnginioString::status] = closeStatus;
                emit dataReceived(data);

                close(closeStatus);

                _tcpSocket->close();
                return;
            }

            // We received data from the server so restart the timer.
            _keepAliveTimer.start(TwoMinutes, this);

            _applicationData.append(_tcpSocket->read(_payloadLength));
            _protocolDecodeState = FrameHeaderPending;
            _payloadLength = 0;

            if (!_isFinalFragment)
                break;

            switch (_protocolOpcode) {
            case TextFrameOp: {
                QJsonObject data = QJsonDocument::fromJson(_applicationData).object();
                data[EnginioString::messageType] = QStringLiteral("data");
                emit dataReceived(data);
                break;
            }
            case PingOp:{
                // We must send back identical application data as found in the message.
                QByteArray payload = _applicationData;
                QByteArray maskingKey = generateMaskingKey();
                QByteArray message = constructFrameHeader(/*isFinalFragment*/ true, PongOp, payload.size(), maskingKey);
                Q_ASSERT(!message.isEmpty());
                maskData(payload, maskingKey);
                message.append(payload);
                _tcpSocket->write(message);
                break;
            }
            case PongOp:
                _pingTimeoutTimer.stop();
                emit pong();
                break;
            default:
                protocolError("WebSocketOpcode not yet supported.", UnsupportedDataTypeCloseStatus);
                qWarning() << "\t\t->" << _protocolOpcode;
            }

            _applicationData.clear();

            break;
        }
        }
    }
}
void EnginioBackendConnection::onSocketConnectionError(QAbstractSocket::SocketError error)
{
    protocolError("Socket connection error.");
    qWarning() << "\t\t->" << error;
}
Ejemplo n.º 6
0
        void Protocol::prepareStateMachine(){
            qDebug() << "Protocol: Initialising Protocol State";
            QStateMachine *machine = new QStateMachine(this);

            /**
             *  Main states are connected, disconnected and done, we start disconnected
             *  and turn to connected when the socket is operational.
             *  All the other states are part of the connected state
             */
            QState *disconnected = new QState();
            QState *connected = new QState();
            QFinalState *done = new QFinalState();

            /**
             *  When first connected, we need to know the protocol version,
             *  then request authentication. We then either turn to the authenticated
             *  state or flee to *done
             */
            QState *waitingproto = new QState(connected);
            QState *waitingauthrequest = new QState(connected);
            QState *waitingauthstatus = new QState(connected);
            QState *authenticated = new QState(connected);
            connected->setInitialState(waitingproto);

            /**
             * When authenticated, the user must provide some information about himself
             * (nickname, status, planet picture, user picture, attack picture)
             * Then the user can request to join the chat room, get the list of games and users
             * join a game or create a game
             * In the chat room, the user sends and receives messages, and can eventually exit
             */
            QState *waitinguserdetails = new QState(authenticated);
            QState *waitingcommand = new QState(authenticated);
            QState *inchat = new QState(authenticated);
            QState *waitinggamecreation = new QState(authenticated);
            QState *waitinggamelist = new QState(authenticated);
            QState *waitinguserlist = new QState(authenticated);
            QState *joinedgame = new QState(authenticated);
            authenticated->setInitialState(waitinguserdetails);

            /**
             * When entering the game, we wait for the users to show up
             * then receive the game map
             * we then wait for the game to unpause, and the game progresses till
             * there's a winner or cancellation
             */
            QState *waitinguser = new QState(joinedgame);
            QState *waitingmap = new QState(joinedgame);
            QState *paused = new QState(joinedgame);
            QState *ingame = new QState(joinedgame);
            joinedgame->setInitialState(waitinguser);

            qDebug() << "Protocol: Connecting Protocol Signals";
            disconnected->addTransition(this, SIGNAL(connected()), connected);
            connected->addTransition(this, SIGNAL(closed()), done);
            waitingproto->addTransition(this, SIGNAL(protocol(QString)), waitingauthrequest);
            waitingauthrequest->addTransition(this, SIGNAL(authrequest(QString,QString)), waitingauthstatus);
            waitingauthstatus->addTransition(this, SIGNAL(authenticated()), authenticated);
            waitingauthstatus->addTransition(this, SIGNAL(protocolError(QString)), done);

            machine->addState(disconnected);
            machine->addState(connected);
            machine->setInitialState(disconnected);

            qDebug() << "Protocol: Starting State Machine";
            machine->start();
        }