Okundu Omeni
/
wifi-https-ble-sm-uart-atcmd-5-13-1
this is using the mbed os version 5-13-1
Diff: source/WiFiManager.cpp
- Branch:
- PassingRegression
- Revision:
- 129:590bdc2dcf5b
- Parent:
- 127:a21788227ca6
--- a/source/WiFiManager.cpp Mon Jul 15 21:37:22 2019 +0000 +++ b/source/WiFiManager.cpp Fri Jul 19 16:49:26 2019 +0000 @@ -51,7 +51,8 @@ //_event_queue.call_every(10000, this, &WiFiManager::callWifiWatchDog); //keep_alive_id = _event_queue.call_every(CLOUD_KEEP_ALIVE_INTERVAL, this, &WiFiManager::callInternetKeepAlive); keep_alive_id = 0; - https_request_succeeded = false; + https_token_valid = false; + token_refresh_count = 0; //watchDogTick.attach(callback(this, &WiFiManager::callWifiWatchDogIsr), 10.0); // call flip function every 10 seconds } @@ -121,7 +122,12 @@ nsapi_size_or_error_t error; //serr = socket->send("GET /nudgebox/v1 HTTP/1.0\r\nHost: https://dev2.dnanudge.io\r\n\r\n", 18); dbg_printf(LOG, "\n[WIFI MAN] KEEP ALIVE SERVER REQUEST\r\n"); - error = socket->send(HELLO_MSG, sizeof(HELLO_MSG)); + char *httpsReq = new char[KEEPALIVE_MSG_SIZE]; + sprintf(httpsReq,"%s\r\nAuthorization: %s\r\n\r\n", KEEPALIVE_MSG_HDR, aws_id_token); + int hdrlen= strlen(httpsReq); + dbg_printf(LOG, "\n[WIFI MAN] KEEP ALIVE MSG [len = %d]\r\n%s", hdrlen, httpsReq); + memcpy(&httpsReq[hdrlen], KEEPALIVE_MSG_BDY,sizeof(KEEPALIVE_MSG_BDY)); + error = socket->send(httpsReq, (hdrlen+sizeof(KEEPALIVE_MSG_BDY))); if(error < 0) { @@ -146,37 +152,48 @@ { queueATresponse(AT_SOCKET_KEEP_ALIVE_FAILED); https_connection_active = false; + socket->close(); + delete socket; + socket = NULL; } + delete httpsReq; } void WiFiManager::CreateTokenHttpsRequest(char * httpsReq) { - - sprintf(httpsReq, "%s\r\n\r\n{\r\n\"AuthParameters\" : {\r\n" + char *httpsBody = new char[200]; + sprintf(httpsBody,"{\r\n\"AuthParameters\" : {\r\n" "\"USERNAME\" : \"%s\",\r\n\"PASSWORD\" : \"%s\"\r\n},\r\n" "\"AuthFlow\" : \"%s\",\r\n" - "\"ClientId\" : \"%s\"\r\n}", TOKEN_REQ_HDR, UserName, Password, AuthFlow, ClientId); + "\"ClientId\" : \"%s\"\r\n}", UserName, Password, AuthFlow, ClientId); + int bodyLen = strlen(httpsBody); + sprintf(httpsReq,"%s\r\ncontent-length: %d" + "\r\n\r\n%s", TOKEN_REQ_HDR, bodyLen, httpsBody); dbg_printf(LOG, "\n[WIFI MAN] Cloud Access Token REQUEST:\r\n%s\r\n", httpsReq); + delete httpsBody; } void WiFiManager::GetCloudAccessToken() { + int start = Kernel::get_ms_count(); // Send data nsapi_size_or_error_t error; dbg_printf(LOG, "\n[WIFI MAN] Get Cloud Access Token REQUEST\r\n"); + // first free up access token memory to avoid leak + freeAccessTokenMemory(); char *httpsReq = new char[500]; httpsReq[0] = NULL; CreateTokenHttpsRequest(httpsReq); if(strlen(httpsReq) == 0) { - queueATresponse(AT_SOCKET_KEEP_ALIVE_FAILED); + queueATresponse(AT_ACCESS_TOKEN_FAILED); return; } error = socket->send(httpsReq, strlen(httpsReq)+1); - + delete httpsReq; if(error < 0) { - queueATresponse(AT_SOCKET_KEEP_ALIVE_FAILED); + queueATresponse(AT_ACCESS_TOKEN_FAILED); return; } @@ -187,33 +204,59 @@ if(error >= 0 && strstr(respBuf, "HTTP/1.1 200")!= NULL) // received HTTP 200 OK status { dbg_printf(LOG, "\n[WIFI MAN] ACCESS TOKEN RESPONSE: \r\n %s\r\n", respBuf); - // reserve memomry on the heap for tokens - aws_id_token = new char[ID_TOKEN_SIZE]; - aws_refresh_token = new char[REFRESH_TOKEN_SIZE]; // extract ID TOKEN char *sp1 = strstr(respBuf,ID_TOKEN_STR_START); - char *sp2 = strstr(respBuf,ACCESS_TOKEN_STR_END); - int tokenLen = sp2-sp1; - strncpy(aws_id_token, sp1, tokenLen); - dbg_printf(LOG, "\n[WIFI MAN] IdToken: \r\n %s\r\n", aws_id_token); + char *sp2 = strstr(sp1+strlen(ID_TOKEN_STR_START),ACCESS_TOKEN_STR_END); + int tokenLen = sp2-sp1-(strlen(ID_TOKEN_STR_START)); + // reserve memomry on the heap for id token + aws_id_token = new char[tokenLen+1]; + strncpy(aws_id_token, sp1+(strlen(ID_TOKEN_STR_START)), tokenLen); + dbg_printf(LOG, "\n[WIFI MAN] Token Length: %d \r\n IdToken: \r\n %s\r\n", tokenLen, aws_id_token); +#ifdef EXTRACT_REFRESH_TOKEN // extract Refresh TOKEN sp1 = strstr(respBuf,REFRESH_TOKEN_STR_START); - sp2 = strstr(respBuf,ACCESS_TOKEN_STR_END); - tokenLen = sp2-sp1; - strncpy(aws_refresh_token, sp1, tokenLen); - dbg_printf(LOG, "\n[WIFI MAN] RefreshToken: \r\n %s\r\n", aws_refresh_token); - queueATresponse(AT_SOCKET_KEEP_ALIVE_OK); - https_connection_active = true; + sp2 = strstr(sp1+strlen(REFRESH_TOKEN_STR_START),ACCESS_TOKEN_STR_END); + tokenLen = sp2-sp1-(strlen(REFRESH_TOKEN_STR_START)); + // reserve memomry on the heap for refresh token + aws_refresh_token = new char[tokenLen+1]; + strncpy(aws_refresh_token, sp1+(strlen(REFRESH_TOKEN_STR_START)), tokenLen); + dbg_printf(LOG, "\n[WIFI MAN] Token Length: %d \r\nRefreshToken: \r\n %s\r\n", tokenLen, aws_refresh_token); +#endif + queueATresponse(AT_ACCESS_TOKEN_SUCCESS); + token_refresh_count++; + //https_connection_active = true; + https_token_valid = true; + // schedule the invalidation of the token for 59 minutes time + _event_queue.call_in(TOKEN_VALID_PERIOD_MS, this, &WiFiManager::invalidateAccessToken); } else { - queueATresponse(AT_SOCKET_KEEP_ALIVE_FAILED); - https_connection_active = false; + dbg_printf(LOG, "\n[WIFI MAN] Failure Response: \r\n %s\r\n", respBuf); + queueATresponse(AT_ACCESS_TOKEN_FAILED); + //https_connection_active = false; } delete respBuf; + int elapsed_ms = Kernel::get_ms_count() - start; + dbg_printf(LOG, "\n[WIFI MAN] Access token Acquisition::\r\n Time Elapsed : %ld ms\r\n", elapsed_ms); + socket->close(); + delete socket; + socket = NULL; } +void WiFiManager::invalidateAccessToken() +{ + https_token_valid = false; +} +void WiFiManager::freeAccessTokenMemory() +{ + free(aws_id_token); + aws_id_token = NULL; +#ifdef EXTRACT_REFRESH_TOKEN + free(aws_refresh_token); + aws_refresh_token = NULL; +#endif +} void WiFiManager::sendThreadATresponseString(const char * buf, at_cmd_resp_t at_cmd) { if(at_data_resp != NULL) return; @@ -426,6 +469,7 @@ } backgroundTaskCompleted = false; wifiCmd = WIFI_CMD_NONE; + //wifiCmd = WIFI_CMD_GET_TOKEN; break; } case WIFI_CMD_NETWORK_STATUS: @@ -450,12 +494,20 @@ break; case WIFI_CMD_SEND_HTTPS_REQ: { + wifiBusy = 1; + if(!https_token_valid) // if this is the first time get token + { + wifiCmd = WIFI_CMD_NONE; + fromWiFiCmd = WIFI_CMD_TLS_CONNECT; + nextWiFiCmd = WIFI_CMD_SEND_HTTPS_REQ; + setNextCommand(WIFI_CMD_GET_TOKEN); + break; + } // cancel keep alive event as not needed since new request has come in. if(keep_alive_id != 0) // only cancel if it has been activated { _event_queue.cancel(keep_alive_id); } - wifiBusy = 1; #ifdef SEND_DEBUG_MESSAGES if(outputBuffersAvailable()) { @@ -467,25 +519,27 @@ dbg_printf(LOG, "before call to send http request \n"); dbg_printf(LOG, "\r\n[WIFI-MAN] Received HTTPS request...\r\n"); print_memory_info(); - //network->attach(NULL); + // disable network interrupts during https request + network->attach(NULL); #ifdef USE_EVENTS_FOR_HTTPS_REQUESTS // Events can be cancelled as long as they have not been dispatched. If the // event has already expired, cancel has no side-effects. int event_id = _event_queue.call(this, &WiFiManager::createSendHttpsRequest); - backgroundTaskCompleted = false; - int msecCount = 0; - int oldChunkNum = chunkNum; - while(!backgroundTaskCompleted && msecCount < 6000) - { - msecCount+=10; - wait_ms(10); - if(oldChunkNum != chunkNum) // new payload received - { - oldChunkNum = chunkNum; - msecCount = 0; - } - } + waitForBackgroundTask(6000, 10); // six second timeout +// backgroundTaskCompleted = false; +// int msecCount = 0; +// int oldChunkNum = chunkNum; +// while(!backgroundTaskCompleted && msecCount < 6000) +// { +// msecCount+=10; +// wait_ms(10); +// if(oldChunkNum != chunkNum) // new payload received +// { +// oldChunkNum = chunkNum; +// msecCount = 0; +// } +// } if(backgroundTaskCompleted) { //queueATresponse(AT_INTERNET_CONFIG_RESP); @@ -513,46 +567,93 @@ } sendATresponseString(AT_COMMAND_FAILED); } - if(https_request_succeeded == false) - { - https_request_succeeded = result; - } - dbg_printf(LOG, "after call to send http request \n"); print_memory_info(); wifiCmd = WIFI_CMD_NONE; wifiBusy = 0; // enable keep alive after https request completes keep_alive_id = _event_queue.call_every(CLOUD_KEEP_ALIVE_INTERVAL, this, &WiFiManager::callInternetKeepAlive); - //network->attach(callback(this, &WiFiManager::status_callback)); + // re-enable network interrupts after https request. + network->attach(callback(this, &WiFiManager::status_callback)); break; } case WIFI_CMD_TLS_CONNECT: { + dbg_printf(LOG, "\r\n[WIFI-MAN] ATTEMPTING TLS CONNECTION\r\n"); char* hostName = strstr(internet_config->url,"//"); wifiBusy = 1; if(hostName != NULL) { hostName += 2; - https_connection_active = createTLSconnection(hostName); - if(https_connection_active == false) + //https_connection_active = createTLSconnection(hostName); + _event_queue.call(this, &WiFiManager::createTLSconnThreadCall, (const char*)hostName); + waitForBackgroundTask(6000, 10); // six second timeout + if(backgroundTaskCompleted == false) { + https_connection_active = false; queueATresponse(AT_SOCKET_KEEP_ALIVE_FAILED); delete socket; socket = NULL; } + else + { + https_connection_active = true; + } } - wifiCmd = WIFI_CMD_NONE; + if(fromWiFiCmd == WIFI_CMD_TLS_CONNECT) + { + wifiCmd = nextWiFiCmd; + fromWiFiCmd = WIFI_CMD_NONE; + nextWiFiCmd = WIFI_CMD_NONE; + } + else + { + wifiCmd = WIFI_CMD_NONE; + } wifiBusy = 0; break; } case WIFI_CMD_INTERNET_KEEP_ALIVE: + { wifiBusy = 1; + if(!https_token_valid) // if this is the first time get token + { + wifiCmd = WIFI_CMD_NONE; + fromWiFiCmd = WIFI_CMD_TLS_CONNECT; + nextWiFiCmd = WIFI_CMD_INTERNET_KEEP_ALIVE; + setNextCommand(WIFI_CMD_GET_TOKEN); + break; + } keepSocketAlive(); wifiCmd = WIFI_CMD_NONE; wifiBusy = 0; break; + } + case WIFI_CMD_GET_TOKEN: + { + wifiBusy = 1; + _event_queue.call(this, &WiFiManager::createTLSconnThreadCall, AWS_HOST_NAME); + waitForBackgroundTask(6000, 10); // six second timeout + if(backgroundTaskCompleted == false) + { + queueATresponse(AT_SOCKET_KEEP_ALIVE_FAILED); + delete socket; + socket = NULL; + } + else + { + https_connection_active = false; + GetCloudAccessToken(); + wifiCmd = WIFI_CMD_NONE; + setNextCommand(WIFI_CMD_TLS_CONNECT); + //_event_queue.call_in(ONE_SECOND,this, &WiFiManager::setNextCommand, WIFI_CMD_TLS_CONNECT); + //wifiCmd = WIFI_CMD_TLS_CONNECT; + } + //wifiBusy = 0; + break; + } case WIFI_CMD_WIFI_MAC_ADDR: + { wifiBusy = 1; if(outputBuffersAvailable()) { @@ -562,6 +663,7 @@ wifiCmd = WIFI_CMD_NONE; wifiBusy = 0; break; + } case WIFI_CMD_SEND_HTTP_REQ: break; default: @@ -577,6 +679,38 @@ backgroundTaskCompleted = createHttpsRequest(); } + +void WiFiManager::createTLSconnThreadCall(const char * hostName) +{ + bool result; + backgroundTaskCompleted = false; + result = createTLSconnection(hostName); + if(result) + { + // update remote peer details after socket connection + updateRemotePeerDetails(); + // send socket connection event before proceeding to send https request + // give about 2 ms + sendSocketConnectionEvent(); + backgroundTaskCompleted = true; + } +} +void WiFiManager::waitForBackgroundTask(int timeout_ms, int inc_ms) +{ + backgroundTaskCompleted = false; + int msecCount = 0; + int oldChunkNum = chunkNum; + while(!backgroundTaskCompleted && msecCount < timeout_ms) + { + msecCount+=inc_ms; + wait_ms(inc_ms); + if(oldChunkNum != chunkNum) // new payload received + { + oldChunkNum = chunkNum; + msecCount = 0; + } + } +} void WiFiManager::sendATresponseString(at_cmd_resp_t at_cmd) { int strLen = strlen(responseString) + 1; @@ -701,7 +835,7 @@ dbg_printf(LOG, "\n [WIFI-MAN] Error instantiating WiFi!! \n"); return 0; } - nsapi_error_t error; + //nsapi_error_t error; dbg_printf(LOG, "\n [WIFI-MAN] About to start scan for WiFi networks\n"); lastScanCount = network->scan(NULL, 0); dbg_printf(LOG, "\n [WIFI-MAN] Scan for WiFi networks completed - \n"); @@ -1314,7 +1448,7 @@ if(responseString == NULL && chunkNum==1) { responseString = (char *) malloc(100); - sprintf(responseString, "\r\nHTTPS BODY CALLBACK RECEIVED\r\n"); + sprintf(responseString, "\r\nHTTPS BODY CALLBACK RECEIVED:: length= %d\r\n", length); sendATresponseString(AT_EVENT); } #endif @@ -1346,17 +1480,23 @@ return false; } dbg_printf(LOG, "TLS set_root_ca_cert passed!!\n"); - r = socket->connect(hostName, 443); - if(r != NSAPI_ERROR_OK) - { - char errstr[100]; - mbedtls_strerror(r, errstr, 100); - dbg_printf(LOG, "TLS connect failed (err = %d) for hostname '%s' -- ERROR = %s !!\n", r, hostName, errstr); - socket->close(); - return false; - } - dbg_printf(LOG, "TLS connection successful for https site : %s\n", hostName); - return true; + int start_ms = _event_queue.tick(); + int elapsed_ms; + do{ + r = socket->connect(hostName, 443); + elapsed_ms = _event_queue.tick() - start_ms; + if(r == NSAPI_ERROR_OK) + { + dbg_printf(LOG, "TLS connection successful for https site : %s" + " \r\n[TLS conn elapsed_ms = %d]\n", hostName, elapsed_ms); + return true; + } + }while(elapsed_ms < TLS_RETRY_TIMEOUT_MS); + char errstr[100]; + mbedtls_strerror(r, errstr, 100); + dbg_printf(LOG, "TLS connect failed (err = %d) for hostname '%s' -- ERROR = %s !!\n", r, hostName, errstr); + socket->close(); + return false; } @@ -1409,9 +1549,20 @@ char full_url[100]; char host[60] ; strncpy(full_url,internet_config->url, strlen(internet_config->url)+1); - strncpy(host,http_req_cfg->hostName, strlen(http_req_cfg->hostName)+1); + //strncpy(host,http_req_cfg->hostName, strlen(http_req_cfg->hostName)+1); + char *eu = strstr(internet_config->url,HTTPS_URL_PREFIX); + if(eu == NULL) + eu = internet_config->url; + else + eu += strlen(HTTPS_URL_PREFIX); + char *eu2 = strstr(eu, "/"); // find the api path + int hLen = eu2 != NULL ? eu2-eu-1: strlen(eu); + + + strncpy(host,eu, hLen+1); strncat(full_url, http_req_cfg->request_URI, strlen(http_req_cfg->request_URI)+1); #ifdef FULL_DEBUG_ENABLED + dbg_printf(LOG, "\n[WIFI MAN] server host name = %s\n", host); dbg_printf(LOG, "\n[WIFI MAN] server url+uri = %s\n", full_url); dbg_printf(LOG, "\n[WIFI MAN] Host = %s\n", http_req_cfg->hostName); dbg_printf(LOG, "\n[WIFI MAN] Accept = %s\n", http_req_cfg->AcceptVal); @@ -1509,27 +1660,38 @@ dbg_printf(LOG, "http_req_cfg->method = %d\n", http_req_cfg->method); if(http_req_cfg->method == HTTP_GET){ dbg_printf(LOG, "HTTP_GET -- ignoring body\n"); - setHttpsHeader("Host", http_req_cfg->hostName); + setHttpsHeader("Host", host); setHttpsHeader("Accept", http_req_cfg->AcceptVal); http_response = https_request->send(NULL, 0); } else{ - setHttpsHeader("Host", http_req_cfg->hostName); + setHttpsHeader("Host", host); + setHttpsHeader("Authorization", aws_id_token); setHttpsHeader("Accept", http_req_cfg->AcceptVal); setHttpsHeader("Content-Type", http_req_cfg->contentType); setHttpsHeader("Content-Length", http_req_cfg->contentLen); dbg_printf(LOG, "https headers setup - about to send request\r\n"); // Grab the heap statistics dbg_printf(LOG, "Heap size: %lu / %lu bytes\r\n", heap_stats.current_size, heap_stats.reserved_size); + dbg_printf(LOG, "\n[WIFI MAN] Token Length: %d \r\n IdToken: \r\n %s\r\n", strlen(aws_id_token), aws_id_token); + +#ifdef PRINT_REQUEST_LOGS + uint8_t *http_req_log_buf = (uint8_t*)calloc(2048, 1); + https_request->set_request_log_buffer(http_req_log_buf, 2048); +#endif http_response = https_request->send(http_req_cfg->body, bodyLen); } #else - setHttpsHeader("Host", http_req_cfg->hostName); + setHttpsHeader("Host", host); + setHttpsHeader("Authorization", aws_id_token); setHttpsHeader("Accept", http_req_cfg->AcceptVal); setHttpsHeader("Content-Type", http_req_cfg->contentType); setHttpsHeader("Content-Length", http_req_cfg->contentLen); http_response = https_request->send(http_req_cfg->body, bodyLen); -#endif +#endif +#ifdef PRINT_REQUEST_LOGS + printHttpRequestLogBuffer(); +#endif nsapi_error_t error = https_request->get_error(); if(error < 0) { @@ -1589,6 +1751,22 @@ https_request->set_header(key, value); } +void WiFiManager::printHttpRequestLogBuffer() +{ + + // after the request is done: +#ifdef PRINT_BUFFER_IN_HEX + dbg_printf(LOG, "\n----- Request buffer Hex-----\n"); + for (size_t ix = 0; ix < https_request->get_request_log_buffer_length(); ix++) { + if(ix%16 == 0)dbg_printf(LOG, "\n[%04x] ", ix); + dbg_printf(LOG, "%02x ", http_req_log_buf[ix]); + } +#endif + dbg_printf(LOG, "\n[ request size = %d bytes]\r\n", https_request->get_request_log_buffer_length()); + dbg_printf(LOG, "----- Request buffer string -----\r\n%s ", (char *)http_req_log_buf); + //wait_ms(100); + free(http_req_log_buf); +} void WiFiManager::sendHttpsRequest(const char * body, int bodyLen) { }