void start(const QVariant &vrequest, Mode mode) { outSeq = 0; outCredits = 0; quiet = false; ZhttpRequestPacket request; if(!request.fromVariant(vrequest)) { log_warning("failed to parse zurl request"); QVariantHash vhash = vrequest.toHash(); rid = vhash.value("id").toByteArray(); toAddress = vhash.value("from").toByteArray(); QByteArray type = vhash.value("type").toByteArray(); if(!toAddress.isEmpty() && type != "error" && type != "cancel") { QMetaObject::invokeMethod(this, "respondError", Qt::QueuedConnection, Q_ARG(QByteArray, "bad-request")); } else { cleanup(); QMetaObject::invokeMethod(q, "finished", Qt::QueuedConnection); } return; } rid = request.id; toAddress = request.from; userData = request.userData; sentHeader = false; stuffToRead = false; bytesReceived = 0; ignorePolicies = request.ignorePolicies; if(request.uri.isEmpty()) { log_warning("missing request uri"); QMetaObject::invokeMethod(this, "respondError", Qt::QueuedConnection, Q_ARG(QByteArray, "bad-request")); return; } QString scheme = request.uri.scheme(); if(scheme == "https" || scheme == "http") { transport = HttpTransport; } else if(scheme == "wss" || scheme == "ws") { transport = WebSocketTransport; } else { log_warning("unsupported scheme"); QMetaObject::invokeMethod(this, "respondError", Qt::QueuedConnection, Q_ARG(QByteArray, "bad-request")); return; } if(transport == WebSocketTransport && mode != Worker::Stream) { log_warning("websocket must be used from stream interface"); QMetaObject::invokeMethod(this, "respondError", Qt::QueuedConnection, Q_ARG(QByteArray, "bad-request")); return; } int defaultPort; if(scheme == "https" || scheme == "wss") defaultPort = 443; else // http || wss defaultPort = 80; HttpHeaders headers = request.headers; if(transport == HttpTransport) { // fire and forget if(mode == Worker::Stream && (rid.isEmpty() || toAddress.isEmpty())) quiet = true; // streaming only allowed on streaming interface if(mode == Worker::Stream) outStream = request.stream; else outStream = false; if(request.method.isEmpty()) { log_warning("missing request method"); QMetaObject::invokeMethod(this, "respondError", Qt::QueuedConnection, Q_ARG(QByteArray, "bad-request")); return; } log_info("IN id=%s, %s %s", request.id.data(), qPrintable(request.method), request.uri.toEncoded().data()); // inbound streaming must start with sequence number of 0 if(mode == Worker::Stream && request.more && request.seq != 0) { log_warning("streamed input must start with seq 0"); QMetaObject::invokeMethod(this, "respondError", Qt::QueuedConnection, Q_ARG(QByteArray, "bad-request")); return; } // can't use these two together if(mode == Worker::Single && request.more) { log_warning("cannot use streamed input on router interface"); QMetaObject::invokeMethod(this, "respondError", Qt::QueuedConnection, Q_ARG(QByteArray, "bad-request")); return; } bodySent = false; inSeq = request.seq; if(!isAllowed(request.uri.host()) || (!request.connectHost.isEmpty() && !isAllowed(request.connectHost))) { QMetaObject::invokeMethod(this, "respondError", Qt::QueuedConnection, Q_ARG(QByteArray, "policy-violation")); return; } QByteArray hostHeader = request.uri.host().toUtf8(); // only tack on the port if it isn't being overridden int port = request.uri.port(defaultPort); if(request.connectPort == -1 && port != defaultPort) hostHeader += ":" + QByteArray::number(port); headers.removeAll("Host"); headers += HttpHeader("Host", hostHeader); hreq = new HttpRequest(dns, this); connect(hreq, SIGNAL(nextAddress(const QHostAddress &)), SLOT(req_nextAddress(const QHostAddress &))); connect(hreq, SIGNAL(readyRead()), SLOT(req_readyRead())); connect(hreq, SIGNAL(bytesWritten(int)), SLOT(req_bytesWritten(int))); connect(hreq, SIGNAL(error()), SLOT(req_error())); maxResponseSize = request.maxSize; sessionTimeout = request.timeout; if(!request.connectHost.isEmpty()) hreq->setConnectHost(request.connectHost); if(request.connectPort != -1) request.uri.setPort(request.connectPort); hreq->setIgnoreTlsErrors(request.ignoreTlsErrors); if(request.followRedirects) hreq->setFollowRedirects(8); if(request.credits != -1) outCredits += request.credits; } else // WebSocketTransport { log_info("IN id=%s, %s", request.id.data(), request.uri.toEncoded().data()); // inbound streaming must start with sequence number of 0 if(request.seq != 0) { log_warning("websocket input must start with seq 0"); QMetaObject::invokeMethod(this, "respondError", Qt::QueuedConnection, Q_ARG(QByteArray, "bad-request")); return; } if(toAddress.isEmpty()) { log_warning("websocket input must provide from address"); QMetaObject::invokeMethod(this, "respondError", Qt::QueuedConnection, Q_ARG(QByteArray, "bad-request")); return; } inSeq = request.seq; if(!isAllowed(request.uri.host()) || (!request.connectHost.isEmpty() && !isAllowed(request.connectHost))) { QMetaObject::invokeMethod(this, "respondError", Qt::QueuedConnection, Q_ARG(QByteArray, "policy-violation")); return; } QByteArray hostHeader = request.uri.host().toUtf8(); // only tack on the port if it isn't being overridden int port = request.uri.port(defaultPort); if(request.connectPort == -1 && port != defaultPort) hostHeader += ":" + QByteArray::number(port); headers.removeAll("Host"); headers += HttpHeader("Host", hostHeader); ws = new WebSocket(dns, this); connect(ws, SIGNAL(nextAddress(const QHostAddress &)), SLOT(req_nextAddress(const QHostAddress &))); connect(ws, SIGNAL(connected()), SLOT(ws_connected())); connect(ws, SIGNAL(readyRead()), SLOT(ws_readyRead())); connect(ws, SIGNAL(framesWritten(int)), SLOT(ws_framesWritten(int))); connect(ws, SIGNAL(peerClosing()), SLOT(ws_peerClosing())); connect(ws, SIGNAL(closed()), SLOT(ws_closed())); connect(ws, SIGNAL(error()), SLOT(ws_error())); if(!request.connectHost.isEmpty()) ws->setConnectHost(request.connectHost); if(request.connectPort != -1) request.uri.setPort(request.connectPort); ws->setIgnoreTlsErrors(request.ignoreTlsErrors); ws->setMaxFrameSize(config->sessionBufferSize); if(request.credits != -1) outCredits += request.credits; } httpActivityTimer = new QTimer(this); connect(httpActivityTimer, SIGNAL(timeout()), SLOT(httpActivity_timeout())); httpActivityTimer->setSingleShot(true); httpActivityTimer->start(config->activityTimeout * 1000); if(sessionTimeout != -1) { httpSessionTimer = new QTimer(this); connect(httpSessionTimer, SIGNAL(timeout()), SLOT(httpSession_timeout())); httpSessionTimer->setSingleShot(true); httpSessionTimer->start(sessionTimeout); } if(transport == WebSocketTransport || (transport == HttpTransport && mode == Worker::Stream)) { expireTimer = new QTimer(this); connect(expireTimer, SIGNAL(timeout()), SLOT(expire_timeout())); expireTimer->setSingleShot(true); expireTimer->start(SESSION_EXPIRE); keepAliveTimer = new QTimer(this); connect(keepAliveTimer, SIGNAL(timeout()), SLOT(keepAlive_timeout())); keepAliveTimer->start(SESSION_EXPIRE / 2); } if(transport == HttpTransport) { if(!request.body.isEmpty() && !request.more && !headers.contains("Content-Length")) headers += HttpHeader("Content-Length", QByteArray::number(request.body.size())); bool hasOrMightHaveBody = (!request.body.isEmpty() || request.more); hreq->start(request.method, request.uri, headers, hasOrMightHaveBody); if(hasOrMightHaveBody) { if(!request.body.isEmpty()) hreq->writeBody(request.body); if(!request.more) { bodySent = true; hreq->endBody(); } } else bodySent = true; if(mode == Stream) { if(request.more) { // send cts ZhttpResponsePacket resp; resp.type = ZhttpResponsePacket::Credit; resp.credits = config->sessionBufferSize; writeResponse(resp); } else { // send ack ZhttpResponsePacket resp; resp.type = ZhttpResponsePacket::KeepAlive; writeResponse(resp); } } } else // WebSocketTransport { ws->start(request.uri, headers); } }
/*======================================================================== Routine Description: wifi state machine -- management the entry for each of wifi state because wifi_rx_proc() maybe no need to be called in some state or substate a bool param "b_doRx" is be used to declare it Arguments: Return Value: Note: ========================================================================*/ void wifi_state_machine(void) { #ifdef CONFIG_STATION bool b_doRx = FALSE; /*not use and move wifi_rx_proc() before wifi_state_machine() to fix Dequeue fail*/ switch (pIoTMlme->CurrentWifiState) { case WIFI_STATE_INIT: ws_init(&b_doRx); break; /*Smart Connection SM*/ case WIFI_STATE_SMTCNT: ws_smt_conn(&b_doRx); break; /*Scan SM*/ case WIFI_STATE_SCAN: /*send Probe req frame at first , then listen Probe response in each channel*/ ws_scan(&b_doRx); break; /*Auth SM*/ case WIFI_STATE_AUTH: ws_auth(&b_doRx); break; /*Assoc SM*/ case WIFI_STATE_ASSOC: ws_assoc(&b_doRx); break; /*4 Way handshake SM*/ case WIFI_STATE_4WAY: ws_4way(&b_doRx); break; /*Connected SM*/ case WIFI_STATE_CONNED: ws_connected(&b_doRx); #if CFG_SUPPORT_TCPIP if (pIoTMlme->TcpInit == FALSE) { /*pIoTMlme->TcpInit shall be set FALSE, once call wifi_state_chg(WIFI_STATE_INIT, 0) or iot_linkdown()*/ tcpip_init(); /*if user add their own tcp/udp connection in other place, but not in tcpip_init() it need to initial such connection here*/ } tcpip_periodic_timer(); #endif break; default: b_doRx = TRUE; break; } #endif #ifdef CONFIG_SOFTAP #if CFG_SUPPORT_TCPIP if (pIoTMlme->TcpInit == FALSE) { tcpip_init(); /*if user add their own tcp/udp connection in other place, but not in tcpip_init() it need to initial such connection here*/ } tcpip_periodic_timer(); #endif #endif return; }