void startClient() { state = ClientStarting; refreshTimeout(); update(); }
void UserDesktopWidget::timerEvent(QTimerEvent* e) { if(e->timerId() == m_refresh_timerid) refreshTimeout(); else if(e->timerId() == m_sendinput_timerid) sendDesktopInputTimeout(); }
void HTTPTransaction::processIngressBody(unique_ptr<IOBuf> chain, size_t len) { DestructorGuard g(this); if (aborted_) { return; } refreshTimeout(); transport_.notifyIngressBodyProcessed(len); if (handler_) { if (!isIngressComplete()) { handler_->onBody(std::move(chain)); } if (useFlowControl_ && !isIngressEOMSeen()) { recvToAck_ += len; if (recvToAck_ > 0) { uint32_t divisor = 2; if (transport_.isDraining()) { // only send window updates for draining transports when window is // closed divisor = 1; } if (uint32_t(recvToAck_) >= (recvWindow_.getCapacity() / divisor)) { flushWindowUpdate(); } } } // else don't care about window updates } }
void HTTPTransaction::updateReadTimeout() { if (isExpectingIngress()) { refreshTimeout(); } else { cancelTimeout(); } }
void startServer() { state = ServerStarting; startKeepAlive(); refreshTimeout(); update(); }
void HTTPTransaction::setIdleTimeout( std::chrono::milliseconds transactionTimeout) { transactionTimeout_ = transactionTimeout; VLOG(4) << "HTTPTransaction: transaction timeout is set to " << std::chrono::duration_cast<std::chrono::milliseconds>( transactionTimeout) .count(); refreshTimeout(); }
void HTTPTransaction::processIngressTrailers(unique_ptr<HTTPHeaders> trailers) { DestructorGuard g(this); if (aborted_) { return; } refreshTimeout(); if (handler_ && !isIngressComplete()) { handler_->onTrailers(std::move(trailers)); } }
void HTTPTransaction::processIngressChunkComplete() { DestructorGuard g(this); if (aborted_) { return; } refreshTimeout(); if (handler_ && !isIngressComplete()) { handler_->onChunkComplete(); } }
// Set a new weight for this node void HTTP2PriorityQueue::Node::updateWeight(uint8_t weight) { int16_t delta = weight - weight_ + 1; weight_ = weight + 1; parent_->totalChildWeight_ += delta; if (isEnqueued()) { parent_->totalEnqueuedWeight_ += delta; } refreshTimeout(); }
void HTTPTransaction::processIngressHeadersComplete( std::unique_ptr<HTTPMessage> msg) { DestructorGuard g(this); if (aborted_) { return; } refreshTimeout(); if (handler_ && !isIngressComplete()) { handler_->onHeadersComplete(std::move(msg)); } }
StreamOutputWidget::StreamOutputWidget(QWidget *parent) : QWidget(parent), m_mutex(QMutex::Recursive), m_audioOutput(NULL), m_IODevice(NULL), m_enabled(false) { //Create GUI components m_ui.setupUi(this); m_timer =new QTimer(this); //Connect signals connect(m_ui.m_startButton,SIGNAL(clicked()),this,SLOT(startButtonClicked())); connect(m_ui.m_stopButton,SIGNAL(clicked()),this,SLOT(stopButtonClicked())); connect(m_ui.m_clearButton,SIGNAL(clicked()),this,SLOT(clearButtonClicked())); connect(m_timer,SIGNAL(timeout()),this,SLOT(refreshTimeout())); connect(m_ui.m_enabledCheckbox,SIGNAL(toggled(bool)),this,SLOT(enabledButtonClicked(bool))); //Scan audio output devices scanOutputDevice(); m_timer->start(100); //100ms timer }
bool CloudAuthenticator::startAuthentication() { qCDebug(dcCloud()) << "Authenticator: Start authenticating" << m_username; // Check if we have username and password if(!m_username.isEmpty() && !m_password.isEmpty()) { m_refreshToken.clear(); stopAuthentication(); QUrlQuery query; query.addQueryItem("grant_type", "password"); query.addQueryItem("username", m_username); query.addQueryItem("password", m_password); setQuery(query); QNetworkRequest request(m_url); QByteArray data = QString(m_clientId + ":" + m_clientSecret).toUtf8().toBase64(); QString header = "Basic " + data; request.setRawHeader("Authorization", header.toLocal8Bit()); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); QNetworkReply *reply = m_networkManager->post(request, m_query.toString().toUtf8()); m_tokenRequests.append(reply); return true; } else if (!m_refreshToken.isEmpty()) { // Use the refreshtoken if there is one refreshTimeout(); return true; } qCWarning(dcCloud()) << "Authenticator: Cannot start authentication. There is no refresh token, username or password around."; stopAuthentication(); m_error = Cloud::CloudErrorLoginCredentialsMissing; return false; }
void handle(const ZhttpResponsePacket &packet) { if(state == ClientRequestStartWait) { if(packet.from.isEmpty()) { state = Stopped; errored = true; errorCondition = ErrorGeneric; cleanup(); log_warning("zhttp client: error id=%s initial ack for streamed input request did not contain from field", packet.id.data()); emit q->error(); return; } toAddress = packet.from; state = ClientRequesting; startKeepAlive(); } else if(state == ClientRequestFinishWait) { toAddress = packet.from; state = ClientReceiving; if(!doReq) startKeepAlive(); } if(packet.type == ZhttpResponsePacket::Error) { errored = true; errorCondition = convertError(packet.condition); log_debug("zhttp client: error id=%s cond=%s", packet.id.data(), packet.condition.data()); state = Stopped; cleanup(); emit q->error(); return; } else if(packet.type == ZhttpResponsePacket::Cancel) { log_debug("zhttp client: received cancel id=%s", packet.id.data()); errored = true; errorCondition = ErrorGeneric; state = Stopped; cleanup(); emit q->error(); return; } // if non-req mode, check sequencing if(!doReq && packet.seq != inSeq) { log_warning("zhttp client: error id=%s received message out of sequence, canceling", packet.id.data()); // if this was not an error packet, send cancel if(packet.type != ZhttpResponsePacket::Error && packet.type != ZhttpResponsePacket::Cancel) { ZhttpRequestPacket p; p.type = ZhttpRequestPacket::Cancel; writePacket(p); } state = Stopped; errored = true; errorCondition = ErrorGeneric; cleanup(); emit q->error(); return; } ++inSeq; refreshTimeout(); if(doReq && (packet.type != ZhttpResponsePacket::Data || packet.more)) { log_warning("zhttp/zws client req: received invalid req response"); state = Stopped; errored = true; errorCondition = ErrorGeneric; cleanup(); emit q->error(); return; } if(packet.type == ZhttpResponsePacket::Data) { if(!haveResponseValues) { haveResponseValues = true; responseCode = packet.code; responseReason = packet.reason; responseHeaders = packet.headers; } if(doReq) { if(responseBodyBuf.size() + packet.body.size() > REQ_BUF_MAX) log_warning("zhttp client req: id=%s server response too large", packet.id.data()); } else { if(responseBodyBuf.size() + packet.body.size() > IDEAL_CREDITS) log_warning("zhttp client: id=%s server is sending too fast", packet.id.data()); } responseBodyBuf += packet.body; if(!doReq && packet.credits > 0) { outCredits += packet.credits; if(outCredits > 0) { // try to write anything that was waiting on credits QPointer<QObject> self = this; tryWrite(); if(!self) return; } } if(packet.more) { if(!packet.body.isEmpty()) emit q->readyRead(); } else { // always emit readyRead here even if body is empty, for EOF state = Stopped; cleanup(); emit q->readyRead(); } } else if(packet.type == ZhttpResponsePacket::Credit) { if(packet.credits > 0) { outCredits += packet.credits; if(outCredits > 0) tryWrite(); } } else if(packet.type == ZhttpResponsePacket::KeepAlive) { // nothing to do } else { log_debug("zhttp client: unsupported packet type id=%s type=%d", packet.id.data(), (int)packet.type); } }
HTTPTransaction::HTTPTransaction(TransportDirection direction, HTTPCodec::StreamID id, uint32_t seqNo, Transport& transport, HTTP2PriorityQueue& egressQueue, const WheelTimerInstance& timeout, HTTPSessionStats* stats, bool useFlowControl, uint32_t receiveInitialWindowSize, uint32_t sendInitialWindowSize, http2::PriorityUpdate priority, HTTPCodec::StreamID assocId): deferredEgressBody_(folly::IOBufQueue::cacheChainLength()), direction_(direction), id_(id), seqNo_(seqNo), transport_(transport), timeout_(timeout), stats_(stats), recvWindow_(receiveInitialWindowSize), sendWindow_(sendInitialWindowSize), egressQueue_(egressQueue), assocStreamId_(assocId), priority_(priority), ingressPaused_(false), egressPaused_(false), flowControlPaused_(false), handlerEgressPaused_(false), egressRateLimited_(false), useFlowControl_(useFlowControl), aborted_(false), deleting_(false), firstByteSent_(false), firstHeaderByteSent_(false), inResume_(false), inActiveSet_(true), ingressErrorSeen_(false), priorityFallback_(false), headRequest_(false) { if (assocStreamId_) { if (isUpstream()) { egressState_ = HTTPTransactionEgressSM::State::SendingDone; } else { ingressState_ = HTTPTransactionIngressSM::State::ReceivingDone; } } refreshTimeout(); if (stats_) { stats_->recordTransactionOpened(); } queueHandle_ = egressQueue_.addTransaction(id_, priority, this, false, &insertDepth_); if(priority.streamDependency != 0 && insertDepth_ == 1) { priorityFallback_ = true; } currentDepth_ = insertDepth_; }
void handle(const ZhttpResponsePacket &packet) { if(packet.type == ZhttpResponsePacket::Error) { errorCondition = convertError(packet.condition); log_debug("zws client: error id=%s cond=%s", packet.id.data(), packet.condition.data()); responseCode = packet.code; responseReason = packet.reason; responseHeaders = packet.headers; responseBody = packet.body; state = Idle; cleanup(); emit q->error(); return; } else if(packet.type == ZhttpResponsePacket::Cancel) { log_debug("zws client: received cancel id=%s", packet.id.data()); errorCondition = ErrorGeneric; state = Idle; cleanup(); emit q->error(); return; } if(!packet.from.isEmpty()) toAddress = packet.from; if(packet.seq != inSeq) { log_warning("zws client: error id=%s received message out of sequence, canceling", packet.id.data()); tryRespondCancel(packet); state = Idle; errorCondition = ErrorGeneric; cleanup(); emit q->error(); return; } if(!toAddress.isEmpty() && !keepAliveTimer->isActive()) startKeepAlive(); ++inSeq; refreshTimeout(); if(state == Connecting) { if(packet.type != ZhttpResponsePacket::Data && packet.type != ZhttpResponsePacket::Credit && packet.type != ZhttpResponsePacket::KeepAlive) { state = Idle; errorCondition = ErrorGeneric; cleanup(); log_warning("zws client: error id=%s initial response wrong type", packet.id.data()); emit q->error(); return; } if(packet.from.isEmpty()) { state = Idle; errorCondition = ErrorGeneric; cleanup(); log_warning("zws client: error id=%s initial ack did not contain from field", packet.id.data()); emit q->error(); return; } } if(packet.type == ZhttpResponsePacket::Data || packet.type == ZhttpResponsePacket::Ping || packet.type == ZhttpResponsePacket::Pong) { if(state == Connecting) { // this is assured earlier assert(packet.type == ZhttpResponsePacket::Data); responseCode = packet.code; responseReason = packet.reason; responseHeaders = packet.headers; if(packet.credits > 0) outCredits += packet.credits; state = Connected; update(); emit q->connected(); } else { if(inSize + packet.body.size() > IDEAL_CREDITS) log_warning("zws client: id=%s server is sending too fast", packet.id.data()); if(packet.type == ZhttpResponsePacket::Data) { handleIncomingDataPacket(packet.contentType, packet.body, packet.more); } else if(packet.type == ZhttpResponsePacket::Ping) { inFrames += Frame(Frame::Ping, packet.body, false); inSize += packet.body.size(); } else if(packet.type == ZhttpResponsePacket::Pong) { inFrames += Frame(Frame::Pong, packet.body, false); inSize += packet.body.size(); } if(packet.credits > 0) { outCredits += packet.credits; if(outCredits > 0) { // try to write anything that was waiting on credits QPointer<QObject> self = this; tryWrite(); if(!self) return; } } emit q->readyRead(); } } else if(packet.type == ZhttpResponsePacket::Close) { handlePeerClose(packet.code); } else if(packet.type == ZhttpResponsePacket::Credit) { if(packet.credits > 0) { outCredits += packet.credits; if(outCredits > 0) tryWrite(); } } else if(packet.type == ZhttpResponsePacket::KeepAlive) { // nothing to do } else { log_debug("zws client: unsupported packet type id=%s type=%d", packet.id.data(), (int)packet.type); } }
void handle(const ZhttpRequestPacket &packet) { if(packet.type == ZhttpRequestPacket::Error) { errorCondition = convertError(packet.condition); log_debug("zws server: error id=%s cond=%s", packet.id.data(), packet.condition.data()); state = Idle; cleanup(); emit q->error(); return; } else if(packet.type == ZhttpRequestPacket::Cancel) { log_debug("zws server: received cancel id=%s", packet.id.data()); errorCondition = ErrorGeneric; state = Idle; cleanup(); emit q->error(); return; } if(packet.seq != inSeq) { log_warning("zws server: error id=%s received message out of sequence, canceling", packet.id.data()); tryRespondCancel(packet); state = Idle; errorCondition = ErrorGeneric; cleanup(); emit q->error(); return; } ++inSeq; refreshTimeout(); if(packet.type == ZhttpRequestPacket::Data || packet.type == ZhttpRequestPacket::Ping || packet.type == ZhttpRequestPacket::Pong) { if(inSize + packet.body.size() > IDEAL_CREDITS) log_warning("zws client: id=%s server is sending too fast", packet.id.data()); if(packet.type == ZhttpRequestPacket::Data) { handleIncomingDataPacket(packet.contentType, packet.body, packet.more); } else if(packet.type == ZhttpRequestPacket::Ping) { inFrames += Frame(Frame::Ping, packet.body, false); inSize += packet.body.size(); } else if(packet.type == ZhttpRequestPacket::Pong) { inFrames += Frame(Frame::Pong, packet.body, false); inSize += packet.body.size(); } if(packet.credits > 0) { outCredits += packet.credits; if(outCredits > 0) { // try to write anything that was waiting on credits QPointer<QObject> self = this; tryWrite(); if(!self) return; } } emit q->readyRead(); } else if(packet.type == ZhttpRequestPacket::Close) { handlePeerClose(packet.code); } else if(packet.type == ZhttpRequestPacket::Credit) { if(packet.credits > 0) { outCredits += packet.credits; tryWrite(); } } else if(packet.type == ZhttpRequestPacket::KeepAlive) { // nothing to do } else { log_debug("zws server: unsupported packet type id=%s type=%d", packet.id.data(), (int)packet.type); } }
void handle(const ZhttpRequestPacket &packet) { if(paused) return; if(packet.type == ZhttpRequestPacket::Error) { errored = true; errorCondition = convertError(packet.condition); log_debug("zhttp server: error id=%s cond=%s", packet.id.data(), packet.condition.data()); state = Stopped; cleanup(); emit q->error(); return; } else if(packet.type == ZhttpRequestPacket::Cancel) { log_debug("zhttp server: received cancel id=%s", packet.id.data()); errored = true; errorCondition = ErrorGeneric; state = Stopped; cleanup(); emit q->error(); return; } if(packet.seq != inSeq) { log_warning("zhttp server: error id=%s received message out of sequence, canceling", packet.id.data()); // if this was not an error packet, send cancel if(packet.type != ZhttpRequestPacket::Error && packet.type != ZhttpRequestPacket::Cancel) { ZhttpResponsePacket p; p.type = ZhttpResponsePacket::Cancel; writePacket(p); } state = Stopped; errored = true; errorCondition = ErrorGeneric; cleanup(); emit q->error(); return; } ++inSeq; refreshTimeout(); if(packet.type == ZhttpRequestPacket::Data) { requestBodyBuf += packet.body; bool done = haveRequestBody; if(!packet.more) { haveRequestBody = true; state = ServerResponseWait; } if(packet.credits > 0) outCredits += packet.credits; if(!packet.body.isEmpty() || (!done && haveRequestBody)) emit q->readyRead(); } else if(packet.type == ZhttpRequestPacket::Credit) { if(packet.credits > 0) { outCredits += packet.credits; tryWrite(); } } else if(packet.type == ZhttpRequestPacket::KeepAlive) { // nothing to do } else if(packet.type == ZhttpRequestPacket::HandoffProceed) { if(pausing) { pausing = false; paused = true; emit q->paused(); } } else { log_debug("zhttp server: unsupported packet type id=%s type=%d", packet.id.data(), (int)packet.type); } }
void tryWrite() { if(state == Requesting) { // if all we have to send is EOF, we don't need credits for that if(out.isEmpty() && outFinished) { ZurlRequestPacket p; p.id = rid.second; p.seq = outSeq++; p.body = QByteArray(""); // need to set body to count as content packet state = Receiving; manager->write(p, replyAddress); refreshTimeout(); return; } if(!out.isEmpty() && outCredits > 0) { // if we have data to send, and the credits to do so, then send data. // also send credits if we need to. int size = qMin(outCredits, out.size()); QByteArray buf = out.mid(0, size); out = out.mid(size); outCredits -= size; ZurlRequestPacket p; p.id = rid.second; p.seq = outSeq++; p.body = buf; if(!out.isEmpty() || !outFinished) p.more = true; if(pendingInCredits > 0) { p.credits = pendingInCredits; pendingInCredits = 0; } if(!p.more) state = Receiving; manager->write(p, replyAddress); refreshTimeout(); emit q->bytesWritten(size); } } else if(state == Receiving) { if(pendingInCredits > 0) { // if we have no data to send but we need to send credits, do at least that ZurlRequestPacket p; p.id = rid.second; p.seq = outSeq++; p.credits = pendingInCredits; pendingInCredits = 0; manager->write(p, replyAddress); refreshTimeout(); } } }
void handle(const ZurlResponsePacket &packet) { if(state == RequestStartWait) { if(packet.replyAddress.isEmpty()) { state = Private::Stopped; errorCondition = ErrorGeneric; cleanup(); log_warning("initial ack for streamed input request did not contain reply-address"); emit q->error(); return; } replyAddress = packet.replyAddress; state = Requesting; } else if(state == RequestFinishWait) { replyAddress = packet.replyAddress; state = Receiving; } if(packet.isError) { // zurl conditions: // remote-connection-failed // connection-timeout // tls-error // bad-request // policy-violation // max-size-exceeded // cancel QByteArray cond = packet.condition; if(cond == "policy-violation") errorCondition = ErrorPolicy; else if(cond == "remote-connection-failed") errorCondition = ErrorConnect; else if(cond == "tls-error") errorCondition = ErrorTls; else if(cond == "length-required") errorCondition = ErrorLengthRequired; else if(cond == "connection-timeout") errorCondition = ErrorTimeout; else // bad-request, max-size-exceeded, cancel errorCondition = ErrorGeneric; state = Private::Stopped; cleanup(); emit q->error(); return; } if(packet.seq != inSeq) { log_warning("received message out of sequence, canceling"); // if this was not an error packet, send cancel if(packet.condition.isEmpty()) { ZurlRequestPacket p; p.id = rid.second; p.seq = outSeq++; p.cancel = true; manager->write(p, replyAddress); } state = Private::Stopped; errorCondition = ErrorGeneric; cleanup(); emit q->error(); return; } ++inSeq; refreshTimeout(); bool doReadyRead = false; if(!packet.body.isNull()) { if(!haveResponseValues) { haveResponseValues = true; responseCode = packet.code; responseStatus = packet.reason; responseHeaders = packet.headers; } if(in.size() + packet.body.size() > IDEAL_CREDITS) log_warning("zurl is sending too fast"); in += packet.body; if(packet.more) { if(!packet.body.isEmpty()) doReadyRead = true; } else { // always emit readyRead here even if body is empty, for EOF state = Private::Stopped; cleanup(); emit q->readyRead(); return; } } if(packet.credits > 0) outCredits += packet.credits; // the only reason we should need to write as a result of a read // is if we were given credits or we have credits to give if(packet.credits > 0 || pendingInCredits > 0) { QPointer<QObject> self = this; tryWrite(); if(!self) return; } if(doReadyRead) emit q->readyRead(); }
void write(const QVariant &vrequest) { ZurlRequestPacket request; if(!request.fromVariant(vrequest)) { QVariantHash vhash = vrequest.toHash(); if(!vhash["cancel"].toBool()) { QMetaObject::invokeMethod(this, "respondError", Qt::QueuedConnection, Q_ARG(QByteArray, "bad-request")); } else { cleanup(); QMetaObject::invokeMethod(q, "finished", Qt::QueuedConnection); } return; } // cancel session if a wrong sequenced packet is received if(inSeq == -1 || request.seq == -1 || request.seq != inSeq + 1) { if(!request.cancel) { QMetaObject::invokeMethod(this, "respondError", Qt::QueuedConnection, Q_ARG(QByteArray, "cancel")); } else { cleanup(); QMetaObject::invokeMethod(q, "finished", Qt::QueuedConnection); } return; } if(request.cancel) { cleanup(); QMetaObject::invokeMethod(q, "finished", Qt::QueuedConnection); return; } refreshTimeout(); inSeq = request.seq; // all we care about from follow-up writes are body and credits if(request.credits != -1) outCredits += request.credits; if(!request.body.isNull()) { if(bodySent) { QMetaObject::invokeMethod(this, "respondError", Qt::QueuedConnection, Q_ARG(QByteArray, "bad-request")); return; } if(!request.body.isEmpty()) hreq->writeBody(request.body); // the 'more' flag only has significance if body field present if(!request.more) { bodySent = true; hreq->endBody(); } } // if we needed credits to send something, take care of that now if(request.credits != -1 && stuffToRead) trySend(); }
inline ClientHandler(PacketHandler<ClientHandler>& mPacketHandler) : packetHandler(mPacketHandler) { onPacketReceived += [this](sf::Packet mPacket){ packetHandler.handle(*this, mPacket); refreshTimeout(); }; timeoutFuture = std::async(std::launch::async, [this] { while(running) { std::this_thread::sleep_for(800ms); if(!isBusy() || --untilTimeout > 0) continue; HG_LO_VERBOSE("ClientHandler") << "Client (" << uid << ") timed out\n"; onDisconnect(); disconnect(); } }); }
void write(const QVariant &vrequest) { ZhttpRequestPacket request; if(!request.fromVariant(vrequest)) { QVariantHash vhash = vrequest.toHash(); if(vhash["type"].toByteArray() != "cancel") { QMetaObject::invokeMethod(this, "respondError", Qt::QueuedConnection, Q_ARG(QByteArray, "bad-request")); } else { cleanup(); QMetaObject::invokeMethod(q, "finished", Qt::QueuedConnection); } return; } // cancel session if a wrong sequenced packet is received if(inSeq == -1 || request.seq == -1 || request.seq != inSeq + 1) { if(request.type != ZhttpRequestPacket::Cancel) { QMetaObject::invokeMethod(this, "respondCancel", Qt::QueuedConnection); } else { cleanup(); QMetaObject::invokeMethod(q, "finished", Qt::QueuedConnection); } return; } if(request.type == ZhttpRequestPacket::Cancel) { cleanup(); QMetaObject::invokeMethod(q, "finished", Qt::QueuedConnection); return; } inSeq = request.seq; refreshTimeout(); // all we care about from follow-up writes are body and credits if(request.credits != -1) outCredits += request.credits; if(transport == HttpTransport) { if(request.type == ZhttpRequestPacket::Data) { if(bodySent) { QMetaObject::invokeMethod(this, "respondError", Qt::QueuedConnection, Q_ARG(QByteArray, "bad-request")); return; } refreshActivityTimeout(); if(!request.body.isEmpty()) hreq->writeBody(request.body); // the 'more' flag only has significance if body field present if(!request.more) { bodySent = true; hreq->endBody(); } } } else // WebSocketTransport { if(request.type == ZhttpRequestPacket::Data || request.type == ZhttpRequestPacket::Close || request.type == ZhttpRequestPacket::Ping || request.type == ZhttpRequestPacket::Pong) { refreshActivityTimeout(); if(request.type == ZhttpRequestPacket::Data) { WebSocket::Frame::Type ftype; if(wsSendingMessage) ftype = WebSocket::Frame::Continuation; else if(request.contentType == "binary") ftype = WebSocket::Frame::Binary; else ftype = WebSocket::Frame::Text; wsSendingMessage = request.more; wsPendingWrites += request.body.size(); ws->writeFrame(WebSocket::Frame(ftype, request.body, request.more)); } else if(request.type == ZhttpRequestPacket::Ping) { wsPendingWrites += 0; ws->writeFrame(WebSocket::Frame(WebSocket::Frame::Ping, QByteArray(), false)); } else if(request.type == ZhttpRequestPacket::Pong) { wsPendingWrites += 0; ws->writeFrame(WebSocket::Frame(WebSocket::Frame::Pong, QByteArray(), false)); } else if(request.type == ZhttpRequestPacket::Close) ws->close(request.code); } } // if we needed credits to send something, take care of that now if(request.credits != -1 && stuffToRead) trySend(); }