Skip to content

Instantly share code, notes, and snippets.

@eckucukoglu
Created July 7, 2017 08:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eckucukoglu/f394e6dc0a71324667fb809f097c8059 to your computer and use it in GitHub Desktop.
Save eckucukoglu/f394e6dc0a71324667fb809f097c8059 to your computer and use it in GitHub Desktop.
#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