Created
July 7, 2017 08:42
-
-
Save eckucukoglu/f394e6dc0a71324667fb809f097c8059 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "OnboardingServer.h" | |
#include "HttpConnectionInfo.h" | |
#include "PropAP.h" | |
#include <thread> | |
#include <mutex> | |
#include <condition_variable> | |
#include <iostream> | |
#include <fstream> | |
#include <string.h> | |
#include <curl/curl.h> | |
#include <json-c/json.h> | |
#include <sys/types.h> | |
#include <sys/select.h> | |
#include <sys/socket.h> | |
#include <microhttpd.h> | |
#include <functional> | |
#include <map> | |
#include <vector> | |
#include <json-c/json.h> | |
using namespace std; | |
#define PORT 8888 | |
#define TMS_REQUEST_TIMEOUT 10 | |
#define CONTENT_TYPE "Content-Type" | |
#define APPLICATION_JSON "application/json" | |
#define GET_METHOD "GET" | |
#define POST_METHOD "POST" | |
#define ORIGIN_HEADER "Origin" | |
#define CORS_HEADER "Access-Control-Allow-Origin" | |
string ARCELIK_TMS_ENDPOINT = "http://tms.sihirbaz.arcelikcloud.com/manager/device_checkin"; | |
// string ARCELIK_TMS_ENDPOINT = "http://127.0.0.1:8000/manager/device_checkin"; | |
int OnboardingServer::isServerUp = 0; | |
CURL* OnboardingServer::curl; | |
string OnboardingServer::macAddress = ""; | |
string OnboardingServer::tmsData = ""; | |
mutex OnboardingServer::isServerUpMutex; | |
mutex OnboardingServer::serverMutex; | |
condition_variable OnboardingServer::serverCv; | |
function<void (std::vector<PropAP>*)> OnboardingServer::listCallback; | |
function<bool (const char*, const char*)> OnboardingServer::connectCallback; | |
string EMPTY_STRING = ""; | |
const char* OnboardingServer::createJsonResponse(const char* message, bool success, const char* error) { | |
json_object * jobj = json_object_new_object(); | |
const char* jsonMessage; | |
if(message != NULL) { | |
json_object_object_add(jobj, "data", json_object_new_string(message)); | |
} | |
json_object_object_add(jobj, "success", json_object_new_boolean(success)); | |
if(error != NULL) { | |
json_object_object_add(jobj, "error", json_object_new_string(error)); | |
} | |
jsonMessage = json_object_to_json_string(jobj); | |
return jsonMessage; | |
} | |
const char* OnboardingServer::createJsonListResponse(vector<PropAP>* availableAPs, bool success, const char* error) { | |
json_object * jobj = json_object_new_object(); | |
const char* jsonMessage; | |
if(availableAPs != NULL) { | |
json_object * jarr = json_object_new_array(); | |
for(unsigned int i=0; i<availableAPs->size(); i++) { | |
PropAP tmp = (*availableAPs)[i]; | |
json_object * jprop = json_object_new_object(); | |
json_object_object_add(jprop, "ssid", json_object_new_string(tmp.name.c_str())); | |
json_object_object_add(jprop, "level", json_object_new_int(tmp.signalLevel)); | |
json_object_array_add(jarr, jprop); | |
} | |
json_object_object_add(jobj, "ssids", jarr); | |
} | |
json_object_object_add(jobj, "success", json_object_new_boolean(success)); | |
if(error != NULL) { | |
json_object_object_add(jobj, "error", json_object_new_string(error)); | |
} | |
jsonMessage = json_object_to_json_string(jobj); | |
return jsonMessage; | |
} | |
const char* OnboardingServer::handleGet(HttpConnectionInfo *con_info) { | |
const char* responseChar; | |
if(0 == strcmp (con_info->url, "/getaccesspoints")) { | |
vector<PropAP> availableAPs; | |
availableAPs.clear(); | |
listCallback(&availableAPs); | |
if(availableAPs.size() > 0) { | |
responseChar = createJsonListResponse(&availableAPs, true, NULL); | |
} else { | |
responseChar = createJsonResponse(NULL, false, "no_available_access_points"); | |
} | |
} else if(0 == strcmp (con_info->url, "/test")) { | |
responseChar = createJsonResponse(NULL, true, NULL); | |
} else if(0 == strcmp (con_info->url, "/hellomac")) { | |
// TODO MAC_ADDRESS get? | |
ifstream mac_address_file("/persist/wlan_mac"); | |
getline(mac_address_file, macAddress); | |
responseChar = createJsonResponse(macAddress.c_str(), true, NULL); | |
} else { | |
responseChar = createJsonResponse(NULL, false, "invalid_url"); | |
} | |
return responseChar; | |
} | |
const char* OnboardingServer::handlePost(HttpConnectionInfo *con_info) { | |
const char* responseChar; | |
if(0 == strcmp (con_info->url, "/setaccesspoint")) { | |
string ssid = (con_info->postData)["ssid"]; | |
string psk = (con_info->postData)["psk"]; | |
tmsData = (con_info->postData)["data"]; | |
if(!EMPTY_STRING.compare(ssid) || !EMPTY_STRING.compare(psk) || !EMPTY_STRING.compare(tmsData)) { | |
responseChar = createJsonResponse(NULL, false, "invalid_data"); | |
} else { | |
if(connectCallback(ssid.c_str(), psk.c_str())) { | |
// Connection to AP is successfull | |
responseChar = createJsonResponse(NULL, true, NULL); | |
} else { | |
// Connection to AP failure | |
responseChar = createJsonResponse(NULL, false, "could_not_connect"); | |
} | |
} | |
} else { | |
responseChar = createJsonResponse(NULL, false, "invalid_url"); | |
} | |
return responseChar; | |
} | |
int OnboardingServer::postProcessor(void* cls, MHD_ValueKind kind, const char* key, const char* filename, const char* content_type, | |
const char* transfer_encoding, const char* data, uint64_t off, size_t size) { | |
HttpConnectionInfo* con_info = (HttpConnectionInfo*) cls; | |
if (con_info->postData.find(key) == con_info->postData.end()) { | |
if (!data) | |
(con_info->postData)[key] = ""; | |
else | |
(con_info->postData)[key] = data; | |
} | |
return MHD_YES; | |
} | |
int OnboardingServer::headerProcessor(void *cls, enum MHD_ValueKind kind, const char *key, const char *value) { | |
HttpConnectionInfo* con_info = (HttpConnectionInfo*) cls; | |
if(0 == strcmp (key, CONTENT_TYPE)) { | |
con_info->contentType = value; | |
} else if(0 == strcmp (key, ORIGIN_HEADER)) { | |
cout << "Origin: " << value << endl; | |
con_info->origin = value;json_object * jobj = json_object_new_object(); | |
const char* tmsBody; | |
json_object_object_add(jobj, "mac_address", json_object_new_string(macAddress.c_str())); | |
json_object_object_add(jobj, "data", json_object_new_string(tmsData.c_str())); | |
tmsBody = json_object_to_json_string(jobj); | |
cout << "####TMSBODY: "<< tmsBody << endl; | |
curl_easy_setopt(curl, CURLOPT_URL, ARCELIK_TMS_ENDPOINT.c_str()); | |
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, tmsBody); | |
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)strlen(tmsBody)); | |
// Timeout stayla | |
curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, requestTimeoutCheckerFunction); | |
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); | |
cout << "Pushing data to TMS..." << endl; | |
res = curl_easy_perform(curl); | |
if(res != CURLE_OK) { | |
cout << "TMS fail" << endl; | |
return false; | |
} else { | |
cout << "TMS success" << endl; | |
return true; | |
} | |
curl | |
} | |
return MHD_YES; | |
} | |
int OnboardingServer::httpRequestHandler(void *cls, struct MHD_Connection *connection, const char *url, const char *method, | |
const char *version, const char *upload_data, size_t *upload_data_size, void **con_cls) { | |
struct MHD_Response *response; | |
int ret; | |
if (NULL == *con_cls) { | |
HttpConnectionInfo *con_info = new HttpConnectionInfo; | |
if (NULL == con_info) | |
return MHD_NO; | |
if (0 == strcmp (method, POST_METHOD)) { | |
con_info->postProcessorCallback = MHD_create_post_processor(connection, 2048, &postProcessor, (void *) con_info); | |
MHD_get_connection_values(connection, MHD_HEADER_KIND, &headerProcessor, (void *) con_info); | |
if (NULL == con_info->postProcessorCallback) { | |
delete con_info; | |
return MHD_NO; | |
} | |
con_info->connectionMethod = POST_METHOD; | |
} else { | |
MHD_get_connection_values(connection, MHD_HEADER_KIND, &headerProcessor, (void *) con_info); | |
con_info->connectionMethod = GET_METHOD; | |
} | |
*con_cls = (void *) con_info; | |
return MHD_YES; | |
} | |
HttpConnectionInfo *con_info = (HttpConnectionInfo*) *con_cls; | |
con_info->url = url; | |
if (0 == strcmp (method, GET_METHOD)) { | |
// GET | |
const char* responseChar = handleGet(con_info); | |
response = MHD_create_response_from_buffer (strlen(responseChar), (void*) responseChar, MHD_RESPMEM_PERSISTENT); | |
MHD_add_response_header(response, CONTENT_TYPE, APPLICATION_JSON); | |
if(con_info->origin != NULL) { | |
MHD_add_response_header(response, CORS_HEADER, con_info->origin); | |
} | |
ret = MHD_queue_response (connection, MHD_HTTP_OK, response); | |
MHD_destroy_response (response); | |
return ret; | |
} else if (0 == strcmp (method, POST_METHOD)) { | |
// POST | |
if (*upload_data_size != 0) { | |
// POST data is coming... | |
MHD_post_process (con_info->postProcessorCallback, upload_data, *upload_data_size); | |
*upload_data_size = 0; | |
return MHD_YES; | |
} else { | |
// POST data is over | |
const char* responseChar = handlePost(con_info); | |
response = MHD_create_response_from_buffer (strlen(responseChar), (void*) responseChar, MHD_RESPMEM_PERSISTENT); | |
MHD_add_response_header(response, CONTENT_TYPE, APPLICATION_JSON); | |
if(con_info->origin != NULL) { | |
MHD_add_response_header(response, CORS_HEADER, con_info->origin); | |
} | |
ret = MHD_queue_response (connection, MHD_HTTP_OK, response); | |
MHD_destroy_response (response); | |
return ret; | |
} | |
} | |
return MHD_YES; | |
} | |
void request_completed(void* cls, MHD_Connection* connection, void** con_cls, MHD_RequestTerminationCode toe) { | |
cout << "Destroying http connection" << endl; | |
HttpConnectionInfo* con_info = (HttpConnectionInfo*) *con_cls; | |
if (NULL != con_info) | |
delete con_info; | |
con_info = NULL; | |
*con_cls = NULL; | |
} | |
int OnboardingServer::serverHandler(MHD_Daemon *daemon) { | |
unique_lock<mutex> lck(serverMutex); | |
serverCv.wait(lck); | |
/* | |
while(isServerUp) { | |
this_thread::sleep_for(chrono::seconds(2)); | |
}*/ | |
MHD_stop_daemon (daemon); | |
cout << "OnboardingServer is DOWN....." << endl; | |
return 0; | |
} | |
int OnboardingServer::startOnboardingServer(function<void (vector<PropAP>*)> listFunc, | |
function<bool (const char*, const char*)> connectFunc) { | |
cout << "Starting OnboardingServer....." << endl; | |
if(isServerUp) { | |
cout << "OnboardingServer is already UP....." << endl; | |
return 0; | |
} | |
MHD_Daemon *daemon; | |
daemon = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG | MHD_USE_POLL, PORT, NULL, NULL, &OnboardingServer::httpRequestHandler, NULL, | |
MHD_OPTION_NOTIFY_COMPLETED, request_completed, NULL, MHD_OPTION_END); | |
if (NULL == daemon) { | |
cout << "Error during starting OnboardingServer" << endl; | |
return -1; | |
} | |
listCallback = listFunc; | |
connectCallback = connectFunc; | |
cout << "OnboardingServer is UP....." << endl; | |
unique_lock<mutex> lck(isServerUpMutex); | |
isServerUp = true; | |
lck.unlock(); | |
onboardingServerThread = thread(serverHandler, daemon); | |
onboardingServerThread.detach(); | |
return 0; | |
} | |
int OnboardingServer::stopOnboardingServer() { | |
cout << "Stopping OnboardingServer....." << endl; | |
if(!isServerUp) { | |
cout << "OnboardingServer is already DOWN....." << endl; | |
return 0; | |
} else { | |
unique_lock<mutex> lckServerUp(isServerUpMutex); | |
isServerUp = false; | |
lckServerUp.unlock(); | |
unique_lock<mutex> lckServer(serverMutex); | |
serverCv.notify_all(); | |
return 0; | |
} | |
return 0; | |
} | |
int OnboardingServer::requestTimeoutCheckerFunction(void *userdata, | |
curl_off_t dltotal, curl_off_t dlnow, | |
curl_off_t ultotal, curl_off_t ulnow) { | |
double curtime = 0; | |
curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &curtime); | |
if(curtime >= TMS_REQUEST_TIMEOUT) { | |
cout << "Timeout has been reached for TMS call." << endl; | |
return 1; | |
} | |
cout <<"TESTEST"<<endl; | |
return 0; | |
} | |
bool OnboardingServer::callTms() { | |
curl = curl_easy_init(); | |
CURLcode res; | |
if(curl) { | |
json_object * jobj = json_object_new_object(); | |
const char* tmsBody; | |
json_object_object_add(jobj, "mac_address", json_object_new_string(macAddress.c_str())); | |
json_object_object_add(jobj, "data", json_object_new_string(tmsData.c_str())); | |
tmsBody = json_object_to_json_string(jobj); | |
cout << "####TMSBODY: "<< tmsBody << endl; | |
curl_easy_setopt(curl, CURLOPT_URL, ARCELIK_TMS_ENDPOINT.c_str()); | |
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, tmsBody); | |
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)strlen(tmsBody)); | |
// Timeout stayla | |
curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, requestTimeoutCheckerFunction); | |
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); | |
cout << "Pushing data to TMS..." << endl; | |
res = curl_easy_perform(curl); | |
if(res != CURLE_OK) { | |
cout << "TMS fail" << endl; | |
return false; | |
} else { | |
cout << "TMS success" << endl; | |
return true; | |
} | |
curl_easy_cleanup(curl); | |
} else { | |
return false; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment