Files
ACSreader/web.c
2023-01-02 11:14:12 +01:00

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;
}