314 lines
10 KiB
C
314 lines
10 KiB
C
#define _GNU_SOURCE
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <syslog.h>
|
|
#include <inttypes.h>
|
|
#include <curl/curl.h>
|
|
#include <cjson/cJSON.h>
|
|
#include <pthread.h>
|
|
#include "config.h"
|
|
#include "web.h"
|
|
#include "log.h"
|
|
#include "jsontypes.h"
|
|
#include "reader.h"
|
|
#include "display.h"
|
|
#include "global.h"
|
|
|
|
//------------------- Web request Callback -------------------
|
|
struct memory_t {
|
|
char *memory;
|
|
size_t size;
|
|
};
|
|
|
|
static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
|
|
{
|
|
size_t realsize = size * nmemb;
|
|
struct memory_t *mem = (struct memory_t *)userp;
|
|
|
|
mem->memory = realloc(mem->memory, mem->size + realsize + 1);
|
|
if(mem->memory == NULL) {
|
|
/* out of memory! */
|
|
writesyslog(LOG_ERR, "not enough memory (realloc returned NULL)");
|
|
return 0;
|
|
}
|
|
|
|
memcpy(&(mem->memory[mem->size]), contents, realsize);
|
|
mem->size += realsize;
|
|
mem->memory[mem->size] = 0;
|
|
|
|
return realsize;
|
|
}
|
|
|
|
//---------------- Web Request JSON -------------------------------
|
|
|
|
void web_request_json(char *url, const char *json, struct reader_t *reader){
|
|
CURL *curl_handle;
|
|
struct memory_t chunk;
|
|
struct curl_slist *headers = NULL; /* http headers to send with request */
|
|
|
|
reader->state = 0;
|
|
reader->opentime = 0;
|
|
reader->cardnumber = 0;
|
|
|
|
#ifdef TEST
|
|
printf("Server request = %s\n", url);
|
|
printf("Json send data = %s\n", json);
|
|
#endif
|
|
|
|
chunk.memory = malloc(1); /* will be grown as needed by the realloc above */
|
|
chunk.size = 0; /* no data at this point */
|
|
|
|
/* set content type */
|
|
headers = curl_slist_append(headers, "Accept: application/json");
|
|
headers = curl_slist_append(headers, "Content-Type: application/json");
|
|
|
|
curl_global_init(CURL_GLOBAL_ALL);
|
|
curl_handle = curl_easy_init();
|
|
curl_easy_setopt(curl_handle, CURLOPT_URL, url);
|
|
curl_easy_setopt(curl_handle, CURLOPT_CUSTOMREQUEST, "POST");
|
|
curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, headers);
|
|
curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, json);
|
|
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
|
|
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); //send all data to this function
|
|
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk); //we pass our 'chunk' struct to the callback function
|
|
curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT, 5); // complete connection within 5 seconds
|
|
curl_easy_setopt(curl_handle, CURLOPT_FAILONERROR, ACS_TRUE); //fail on error code >= 400
|
|
char errbuf[CURL_ERROR_SIZE];
|
|
curl_easy_setopt(curl_handle, CURLOPT_ERRORBUFFER, errbuf);
|
|
errbuf[0] = '\0';
|
|
|
|
CURLcode res = curl_easy_perform(curl_handle);
|
|
|
|
if(res == CURLE_OK) {
|
|
cJSON *retjson = cJSON_Parse(chunk.memory);
|
|
if(retjson == NULL){
|
|
writesyslog(LOG_ERR, "web_request: cJSON_Parse failed\n");
|
|
reader->state = SERVERERROR;
|
|
}
|
|
else{
|
|
#ifdef TEST
|
|
printf("Server answer: %s\n", cJSON_PrintUnformatted(retjson));
|
|
#endif
|
|
|
|
if(cJSON_GetObjectItem(retjson,"State") != NULL){
|
|
reader->state = cJSON_GetObjectItem(retjson,"State")->valueint;
|
|
}
|
|
if(cJSON_GetObjectItem(retjson,"OpenTime") != NULL){
|
|
reader->opentime = (unsigned int)cJSON_GetObjectItem(retjson,"OpenTime")->valueint;
|
|
}
|
|
if(cJSON_GetObjectItem(retjson, "CardNumber") != NULL){
|
|
reader->cardnumber = cJSON_GetObjectItem(retjson,"CardNumber")->valueint;
|
|
}
|
|
}
|
|
cJSON_Delete(retjson);
|
|
}
|
|
else{ //curl returned a error
|
|
char *log;
|
|
if(asprintf(&log, "web_request: curl failed: %d : %s\n", res, curl_easy_strerror(res)) > 0 ){
|
|
writesyslog(LOG_ERR, log);
|
|
}
|
|
free(log);
|
|
writesyslog(LOG_ERR, errbuf);
|
|
|
|
if(res == CURLE_COULDNT_RESOLVE_HOST){
|
|
reader->state = RESOLVEERROR;
|
|
}else if(res == CURLE_OPERATION_TIMEDOUT){
|
|
reader->state = CONNECTIONTIMEOUT;
|
|
}else if(res == CURLE_HTTP_RETURNED_ERROR || res == CURLE_PEER_FAILED_VERIFICATION){
|
|
reader->state = SERVERERROR;
|
|
}else{
|
|
reader->state = UNKNOWNERROR;
|
|
}
|
|
}
|
|
|
|
/* cleanup curl stuff */
|
|
curl_easy_cleanup(curl_handle);
|
|
free(chunk.memory);
|
|
/* we're done with libcurl, so clean it up */
|
|
curl_global_cleanup();
|
|
}
|
|
//----------------------- Print Errors --------------------------------------
|
|
|
|
void server_display_error(returnstate_t state, struct config_t *config){
|
|
char *log;
|
|
char *ln1, *ln2;
|
|
int len = 0;
|
|
int ret1, ret2;
|
|
switch(state){
|
|
case UNKNOWNERROR:
|
|
len = asprintf(&log, "Unknown error");
|
|
ret1 = asprintf(&ln1, "Unknown error");
|
|
ret2 = asprintf(&ln2, "%s", config->serveraddress);
|
|
break;
|
|
case CONNECTIONTIMEOUT:
|
|
len = asprintf(&log, "Connection timeout to server: %s", config->serveraddress);
|
|
ret1 = asprintf(&ln1, "Connection timout");
|
|
ret2 = asprintf(&ln2, "%s", config->serveraddress);
|
|
break;
|
|
case RESOLVEERROR:
|
|
len = asprintf(&log, "Can't resolve server address: %s", config->serveraddress);
|
|
ret1 = asprintf(&ln1, "Resolve error");
|
|
ret2 = asprintf(&ln2, "%s", config->serveraddress);
|
|
break;
|
|
case SERVERERROR:
|
|
len = asprintf(&log, "Error in ACS server: %s", config->serveraddress);
|
|
ret1 = asprintf(&ln1, "Error in server");
|
|
ret2 = asprintf(&ln2, "%s", config->serveraddress);
|
|
break;
|
|
case CREDENTIALERROR:
|
|
len = asprintf(&log, "Error in credential on server: %s", config->serveraddress);
|
|
ret1 = asprintf(&ln1, "Error in credential");
|
|
ret2 = asprintf(&ln2, "%s", config->serveraddress);
|
|
break;
|
|
case LOGERROR:
|
|
len = asprintf(&log, "Error in log on server: %s", config->serveraddress);
|
|
ret1 = asprintf(&ln1, "Error in log");
|
|
ret2 = asprintf(&ln2, "%s", config->serveraddress);
|
|
break;
|
|
case LOCKSTATEERROR:
|
|
len = asprintf(&log, "Error in lockstate on server: %s", config->serveraddress);
|
|
ret1 = asprintf(&ln1, "Error in lockstate");
|
|
ret2 = asprintf(&ln2, "%s", config->serveraddress);
|
|
break;
|
|
case OPENTIMEERROR:
|
|
len = asprintf(&log, "Error in opentime on server: %s", config->serveraddress);
|
|
ret1 = asprintf(&ln1, "Error in opentime");
|
|
ret2 = asprintf(&ln2, "%s", config->serveraddress);
|
|
break;
|
|
case DEVICEINACTIVE:
|
|
len = asprintf(&log, "Device not active on server: %s", config->serveraddress);
|
|
ret1 = asprintf(&ln1, "Device not active");
|
|
ret2 = asprintf(&ln2, "%s", config->serveraddress);
|
|
break;
|
|
default:
|
|
len = asprintf(&log, "switch default - server errors");
|
|
ret1 = asprintf(&ln1, "Switch default server");
|
|
ret2 = asprintf(&ln2, "cannot happen !");
|
|
}
|
|
if(len > 0){
|
|
int fd = display_open();
|
|
display_clear(fd);
|
|
display_write(fd, 1, 0, 0, ln1);
|
|
display_write(fd, 2, 0, 0, ln2);
|
|
display_timer(fd, DISPLAY_TIME);
|
|
close(fd);
|
|
|
|
writesyslog(LOG_ERR, log);
|
|
}
|
|
free(ln1);
|
|
free(ln2);
|
|
free(log);
|
|
}
|
|
|
|
|
|
//----------------------- Request functions ----------------------------------
|
|
void server_credential_request(struct reader_t *reader, struct config_t *config){
|
|
char *url;
|
|
if(asprintf(&url, "https://%s:%ld/v2/api/CredentialRequest", config->serveraddress, config->serverport) <= 0){
|
|
writesyslog(LOG_ERR, "server_credential_request: asprintf failed");
|
|
return;
|
|
}
|
|
|
|
cJSON *sendjson = cJSON_CreateObject();
|
|
cJSON_AddStringToObject(sendjson, "Device", config->device);
|
|
cJSON_AddStringToObject(sendjson, "Name", config->name);
|
|
cJSON_AddStringToObject(sendjson, "ReaderData", (const char *)reader->buff);
|
|
cJSON_AddNumberToObject(sendjson, "ProductClass", (double)config->ProductClass);
|
|
cJSON_AddNumberToObject(sendjson, "Reader", reader->reader);
|
|
cJSON_AddStringToObject(sendjson, "ReaderName", reader->readername);
|
|
|
|
web_request_json(url, cJSON_PrintUnformatted(sendjson), reader);
|
|
|
|
cJSON_Delete(sendjson);
|
|
free(url);
|
|
|
|
if(reader->state != ACCESSGRANTED && reader->state != ACCESSDENIED){
|
|
server_display_error(reader->state, config);
|
|
}
|
|
}
|
|
|
|
//****************** LockState *******************************
|
|
int server_send_lockstate(struct config_t *config, lockstates_t lockstate){
|
|
char *url;
|
|
if(asprintf(&url, "https://%s:%ld/v2/api/LockState", config->serveraddress, config->serverport) <= 0){
|
|
writesyslog(LOG_ERR, "server_send_lockstate: asprintf failed");
|
|
return -1;
|
|
}
|
|
|
|
cJSON *sendjson = cJSON_CreateObject();
|
|
cJSON_AddStringToObject(sendjson, "Device", config->device);
|
|
cJSON_AddStringToObject(sendjson, "Name", config->name);
|
|
cJSON_AddNumberToObject(sendjson, "ProductClass", (double)config->ProductClass);
|
|
cJSON_AddNumberToObject(sendjson, "LockState", lockstate);
|
|
|
|
struct reader_t reader;
|
|
web_request_json(url, cJSON_PrintUnformatted(sendjson), &reader);
|
|
|
|
cJSON_Delete(sendjson);
|
|
free(url);
|
|
|
|
if(reader.state != LOCKSTATEOK){
|
|
server_display_error(reader.state, config);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//****************** Add Log *******************************
|
|
int server_send_log(struct config_t *config, logtypes_t logtype, const char *logtext){
|
|
char *url;
|
|
if(asprintf(&url, "https://%s:%ld/v2/api/addlog", config->serveraddress, config->serverport) <= 0){
|
|
writesyslog(LOG_ERR, "server_send_log: asprintf failed");
|
|
return -1;
|
|
}
|
|
|
|
cJSON *sendjson = cJSON_CreateObject();
|
|
cJSON_AddStringToObject(sendjson, "Device", config->device);
|
|
cJSON_AddStringToObject(sendjson, "Name", config->name);
|
|
cJSON_AddStringToObject(sendjson, "Message", logtext);
|
|
cJSON_AddNumberToObject(sendjson, "ProductClass", (double)config->ProductClass);
|
|
cJSON_AddNumberToObject(sendjson, "LogType", logtype);
|
|
|
|
struct reader_t reader;
|
|
web_request_json(url, cJSON_PrintUnformatted(sendjson), &reader);
|
|
|
|
cJSON_Delete(sendjson);
|
|
free(url);
|
|
|
|
if(reader.state != LOGOK){
|
|
server_display_error(reader.state, config);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//****************** get OpenTime *******************************
|
|
unsigned int server_get_opentime(struct config_t *config){
|
|
char *url;
|
|
if(asprintf(&url, "https://%s:%ld/v2/api/opentime", config->serveraddress, config->serverport) <= 0){
|
|
writesyslog(LOG_ERR, "server_get_opentime: asprintf failed");
|
|
return 0;
|
|
}
|
|
|
|
cJSON *sendjson = cJSON_CreateObject();
|
|
cJSON_AddStringToObject(sendjson, "Device", config->device);
|
|
cJSON_AddStringToObject(sendjson, "Name", config->name);
|
|
cJSON_AddNumberToObject(sendjson, "ProductClass", (double)config->ProductClass);
|
|
|
|
struct reader_t reader;
|
|
web_request_json(url, cJSON_PrintUnformatted(sendjson), &reader);
|
|
|
|
cJSON_Delete(sendjson);
|
|
free(url);
|
|
|
|
if(reader.state != OPENTIMEOK){
|
|
server_display_error(reader.state, config);
|
|
return 0;
|
|
}
|
|
|
|
return reader.opentime;
|
|
}
|