feat(http-get-param): initial commit
This commit is contained in:
parent
904d7fd959
commit
095995f6c1
|
@ -0,0 +1 @@
|
||||||
|
cfg-sib00_rgncycle.txt
|
|
@ -0,0 +1,8 @@
|
||||||
|
pq =
|
||||||
|
{
|
||||||
|
db = "database";
|
||||||
|
host = "localhost";
|
||||||
|
port = 5432;
|
||||||
|
secret = "secret";
|
||||||
|
user = "user";
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
/*to use exit*/
|
||||||
|
#include <stdlib.h>
|
||||||
|
/*to use *print**/
|
||||||
|
#include <stdio.h>
|
||||||
|
/*to user file2char*/
|
||||||
|
#include "file2char.h"
|
||||||
|
|
||||||
|
int convert_file2char(char const* path, char **buf){
|
||||||
|
/*declarations*/
|
||||||
|
FILE *fp;
|
||||||
|
long lSize;
|
||||||
|
|
||||||
|
/*TODO Check path for validity!*/
|
||||||
|
/*fopen()
|
||||||
|
*filename
|
||||||
|
*mode
|
||||||
|
*return: set errno value in error case
|
||||||
|
*/
|
||||||
|
fp=fopen(path,"r");
|
||||||
|
|
||||||
|
if(fp){
|
||||||
|
fprintf(stdout,"file opened.\n");
|
||||||
|
|
||||||
|
/*set offset to file end*/
|
||||||
|
/*fseek()
|
||||||
|
*stream
|
||||||
|
*offset
|
||||||
|
*origin
|
||||||
|
*/
|
||||||
|
fseek(fp,0L,SEEK_END);
|
||||||
|
if (ferror(fp)){
|
||||||
|
printf ("Error seeking file\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*get file size*/
|
||||||
|
lSize = ftell( fp );
|
||||||
|
fprintf(stdout,"lSize: %ld.\n",lSize);
|
||||||
|
|
||||||
|
/*set offset to file start*/
|
||||||
|
fseek(fp,0,SEEK_SET);
|
||||||
|
if (ferror(fp)){
|
||||||
|
printf ("Error seeking file\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*allocate memory for entire content + null termination*/
|
||||||
|
*buf=(char *)malloc((lSize+1)*sizeof(char));
|
||||||
|
if(!*buf){
|
||||||
|
fclose(fp);
|
||||||
|
fputs("Error allocating memory",stderr);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
fprintf(stdout,"mem allocated.\n");
|
||||||
|
|
||||||
|
/*copy file into buffer*/
|
||||||
|
/*fread()
|
||||||
|
*ptr
|
||||||
|
*size
|
||||||
|
*count
|
||||||
|
*stream
|
||||||
|
*/
|
||||||
|
if( 1!=fread(*buf,lSize,1,fp)){
|
||||||
|
fclose(fp);
|
||||||
|
free(*buf);
|
||||||
|
fputs("Error reading entire file",stderr);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
fprintf(stdout,"file read.\n");
|
||||||
|
|
||||||
|
/*close file*/
|
||||||
|
if(EOF==fclose(fp)){
|
||||||
|
free(*buf);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
fprintf(stdout,"file closed.\n");
|
||||||
|
|
||||||
|
(*buf)[lSize] = '\0';
|
||||||
|
fprintf(stdout,"mem null terminated.\n");
|
||||||
|
}else{
|
||||||
|
perror(path);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
/*done*/
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
/*We can use CPP tricks to avoid parsing the same header file more than once*/
|
||||||
|
#ifndef FILE2CHAR_H
|
||||||
|
#define FILE2CHAR_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* convert_file2char reads the file identified by 'path' into a character buffer
|
||||||
|
* pointed at by 'buf'.
|
||||||
|
* On success, 0 is returned.
|
||||||
|
* On failure, exit(EXIT_FAILURE) is returned.
|
||||||
|
*
|
||||||
|
* WARNING: convert_file2char malloc()s memory to '*buf' which must be freed by
|
||||||
|
* the caller.
|
||||||
|
*/
|
||||||
|
int convert_file2char(char const* path, char **buf);
|
||||||
|
|
||||||
|
#endif /* FILE2CHAR_H */
|
|
@ -0,0 +1,405 @@
|
||||||
|
/*to create API*/
|
||||||
|
#include <ulfius.h>
|
||||||
|
/*to connect to Postgresql*/
|
||||||
|
#include <libpq-fe.h>
|
||||||
|
/* to use JSON in response body*/
|
||||||
|
#include <jansson.h>
|
||||||
|
/*to use strcat*/
|
||||||
|
#include <string.h>
|
||||||
|
/*to use inet_ntoa*/
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
/*to use *print**/
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/*to use struct pq_confo*/
|
||||||
|
#include "pqconfo.h"
|
||||||
|
/*to use file2char*/
|
||||||
|
#include "file2char.h"
|
||||||
|
|
||||||
|
#define ROUTE_HELLO "/hello"
|
||||||
|
#define ROUTE_ENTITIES "/entities"
|
||||||
|
#define PREFIX "/test"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* callback functions declaration
|
||||||
|
*/
|
||||||
|
int callback_get_hello (const struct _u_request * request, struct _u_response * response, void * user_data);
|
||||||
|
|
||||||
|
int callback_default (const struct _u_request * request, struct _u_response * response, void * user_data);
|
||||||
|
|
||||||
|
int callback_get_entities (const struct _u_request * request, struct _u_response * response, void * user_data);
|
||||||
|
|
||||||
|
int callback_get_entity (const struct _u_request * request, struct _u_response * response, void * user_data);
|
||||||
|
|
||||||
|
int callback_set_entity (const struct _u_request * request, struct _u_response * response, void * user_data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* decode a u_map into a string
|
||||||
|
*/
|
||||||
|
char * print_map(const struct _u_map * map) {
|
||||||
|
/*declaration*/
|
||||||
|
char * line, * to_return = NULL;
|
||||||
|
const char **keys, * value;
|
||||||
|
int len, i;
|
||||||
|
|
||||||
|
if (map != NULL) {
|
||||||
|
keys = u_map_enum_keys(map);
|
||||||
|
for (i=0; keys[i] != NULL; i++) {
|
||||||
|
value = u_map_get(map, keys[i]);
|
||||||
|
len = snprintf(NULL, 0, "key is %s, value is %s", keys[i], value);
|
||||||
|
line = malloc((size_t)(len+1));
|
||||||
|
snprintf(line, (size_t)(len+1), "key is %s, value is %s", keys[i], value);
|
||||||
|
if (to_return != NULL) {
|
||||||
|
len = (int)(strlen(to_return) + strlen(line) + 1);
|
||||||
|
to_return = realloc(to_return, (size_t)(len+1));
|
||||||
|
if (strlen(to_return) > 0) {
|
||||||
|
//concatenate strings
|
||||||
|
strcat(to_return, "\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
to_return = malloc((strlen(line) + 1));
|
||||||
|
to_return[0] = 0;
|
||||||
|
}
|
||||||
|
strcat(to_return, line);
|
||||||
|
free(line);
|
||||||
|
}
|
||||||
|
return to_return;
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
/*declaration*/
|
||||||
|
struct _u_instance instance;
|
||||||
|
int frameworkRet, apiPort, apiPortRet, cx;
|
||||||
|
/*TODO How is const defined?*/
|
||||||
|
const int pqConInfoSize = 100;
|
||||||
|
char pqConInfo[pqConInfoSize];
|
||||||
|
int pqConfoRet;
|
||||||
|
const struct pq_confo * pqConfo;
|
||||||
|
|
||||||
|
printf("main() Started...\n");
|
||||||
|
if (argc != 3) {
|
||||||
|
fprintf(stderr, "Usage: ./main <API port> <path to config file>\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("main() argv[1]: %s\n", argv[1]);
|
||||||
|
printf("main() argv[2]: %s\n", argv[2]);
|
||||||
|
|
||||||
|
/*get Postgresql connection info from config*/
|
||||||
|
/*TODO Validate argv!*/
|
||||||
|
pqConfoRet=get_pq_confo(argv[2],&pqConfo);
|
||||||
|
if(pqConfoRet){
|
||||||
|
fprintf(stderr, "Postgresql connection information are NOT valid\n");
|
||||||
|
return 2;
|
||||||
|
}else{
|
||||||
|
fprintf(stdout,"pqConfoRet: %d\n",pqConfoRet);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*create pq connection info*/
|
||||||
|
cx = snprintf(pqConInfo,pqConInfoSize,"postgresql://%s:%s@%s:%d/%s",pqConfo->user,pqConfo->secret,pqConfo->host,pqConfo->port,pqConfo->db);
|
||||||
|
if(0>cx && cx>=pqConInfoSize){
|
||||||
|
fprintf(stderr,"main() error creating pqConInfo\n");
|
||||||
|
/*free Postgresql connection info*/
|
||||||
|
pqConfoRet=free_pq_confo(&pqConfo);
|
||||||
|
if(pqConfoRet){
|
||||||
|
fprintf(stderr, "Postgresql connection information are NOT free\n");
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*free Postgresql connection info*/
|
||||||
|
pqConfoRet=free_pq_confo(&pqConfo);
|
||||||
|
if(pqConfoRet){
|
||||||
|
fprintf(stderr, "Postgresql connection information are NOT free\n");
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*store command line argument in variable*/
|
||||||
|
/*validate user input*/
|
||||||
|
/*omit injection*/
|
||||||
|
/*stream:argv*/
|
||||||
|
apiPortRet = sscanf(argv[1], "%d", &apiPort);
|
||||||
|
/*valid user input:1 successfully filled item*/
|
||||||
|
if (apiPortRet != 1) {
|
||||||
|
fprintf(stderr, "The argument must be an integer\n");
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
if (apiPort < 0) {
|
||||||
|
fprintf(stderr, "Error passing a negative port\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
printf("main() port: %d\n", apiPort);
|
||||||
|
|
||||||
|
/*TODO Is mem leaked when connection to pq failes?*/
|
||||||
|
|
||||||
|
if (ulfius_init_instance(&instance, apiPort, NULL, NULL) != U_OK) {
|
||||||
|
printf("main() Error ulfius_init_instance, abort");
|
||||||
|
return 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*connect to database*/
|
||||||
|
//TODO This is a synchronous call! Shall we block the rest?
|
||||||
|
PGconn *conn = PQconnectdb(pqConInfo);
|
||||||
|
if (PQstatus(conn) == CONNECTION_BAD) {
|
||||||
|
fprintf(stderr, "Connection to database failed: %s\n",
|
||||||
|
PQerrorMessage(conn));
|
||||||
|
PQfinish(conn);
|
||||||
|
return 8;
|
||||||
|
}else if(PQstatus(conn)==CONNECTION_OK){
|
||||||
|
printf("main() connected to database\n");
|
||||||
|
}else{
|
||||||
|
printf("main() connection status NOT known\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO Why?
|
||||||
|
u_map_put(instance.default_headers, "Access-Control-Allow-Origin", "*");
|
||||||
|
|
||||||
|
// Maximum body size sent by the client is 1 Kb
|
||||||
|
instance.max_post_body_size = 1024;
|
||||||
|
|
||||||
|
// Endpoint list declaration
|
||||||
|
ulfius_add_endpoint_by_val(&instance, "GET", ROUTE_HELLO, NULL, 0, &callback_get_hello, NULL);
|
||||||
|
|
||||||
|
//user_data: pass pq connection information to callback
|
||||||
|
ulfius_add_endpoint_by_val(&instance, "GET", ROUTE_ENTITIES, "/info", 0, &callback_get_entities, (void *)conn);
|
||||||
|
|
||||||
|
//user_data: pass pq connection information to callback
|
||||||
|
ulfius_add_endpoint_by_val(&instance, "GET", ROUTE_ENTITIES, "/:id/info", 0, &callback_get_entity, (void *)conn);
|
||||||
|
|
||||||
|
//user_data: pass pq connection information to callback
|
||||||
|
ulfius_add_endpoint_by_val(&instance, "GET", ROUTE_ENTITIES, "/update", 0, &callback_set_entity, (void *)conn);
|
||||||
|
|
||||||
|
// default_endpoint declaration
|
||||||
|
ulfius_set_default_endpoint(&instance, &callback_default, NULL);
|
||||||
|
|
||||||
|
// Start the framework
|
||||||
|
// Open an http connection
|
||||||
|
frameworkRet = ulfius_start_framework(&instance);
|
||||||
|
|
||||||
|
if (frameworkRet == U_OK) {
|
||||||
|
printf("main() Start framework on port %d\n", instance.port);
|
||||||
|
/*wait*/
|
||||||
|
while(1){
|
||||||
|
sleep(3600);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printf("main() Error starting framework; frameworkRet: %d\n",frameworkRet);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("main() End framework\n");
|
||||||
|
|
||||||
|
/*clean up API*/
|
||||||
|
ulfius_stop_framework(&instance);
|
||||||
|
ulfius_clean_instance(&instance);
|
||||||
|
|
||||||
|
/*clean up Postgresql connection*/
|
||||||
|
PQfinish(conn);
|
||||||
|
|
||||||
|
printf("main() Done.\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback function that put a "Hello World!" string in the response
|
||||||
|
*/
|
||||||
|
int callback_get_hello (const struct _u_request * request, struct _u_response * response, void * user_data) {
|
||||||
|
ulfius_set_string_body_response(response, 200, "Hello World!");
|
||||||
|
return U_CALLBACK_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default callback function called if no endpoint has a match
|
||||||
|
*/
|
||||||
|
int callback_default (const struct _u_request * request, struct _u_response * response, void * user_data) {
|
||||||
|
ulfius_set_string_body_response(response, 404, "Page not found, do what you want");
|
||||||
|
return U_CALLBACK_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback function for route /entities to reply the entity at question
|
||||||
|
*/
|
||||||
|
int callback_get_entity (const struct _u_request * request, struct _u_response * response, void * user_data) {
|
||||||
|
/*declarations*/
|
||||||
|
char *url_params;
|
||||||
|
char *response_body;
|
||||||
|
int r;
|
||||||
|
const char **keys;
|
||||||
|
const char *value;
|
||||||
|
char *line;
|
||||||
|
int len;
|
||||||
|
int i;
|
||||||
|
PGconn *conn;
|
||||||
|
char *prepStmEntities;
|
||||||
|
PGresult *pqRes;
|
||||||
|
int nbRecords,nbFields;
|
||||||
|
json_t *arrayRecords, *arrayFields, *stringField;
|
||||||
|
|
||||||
|
printf("callback_get_entity() Started...\n");
|
||||||
|
url_params = print_map(request->map_url);
|
||||||
|
r=asprintf(
|
||||||
|
&response_body,
|
||||||
|
"parameters from the url are \n%s\n\n",
|
||||||
|
url_params);
|
||||||
|
//printf("callback_get_entity() %d characters generated\n",r);
|
||||||
|
|
||||||
|
if(request->map_url != NULL){
|
||||||
|
keys=u_map_enum_keys(request->map_url);
|
||||||
|
if(keys[0] == NULL){
|
||||||
|
//TODO error
|
||||||
|
printf("callback_get_entity() param NOT available\n");
|
||||||
|
//TODO Why this casting?
|
||||||
|
(void)(request);
|
||||||
|
(void)(user_data);
|
||||||
|
ulfius_set_string_body_response(response, 200, "This is the /entity/:id/info route: Param error!");
|
||||||
|
}else{
|
||||||
|
value = u_map_get(request->map_url, keys[0]);
|
||||||
|
//printf("callback_get_entity() key is %s, value is %s\n", keys[0], value);
|
||||||
|
|
||||||
|
conn = (PGconn *)user_data;
|
||||||
|
|
||||||
|
/*define prepared statement*/
|
||||||
|
len=snprintf(NULL,0,"SELECT * FROM entities WHERE id=%s;",value);
|
||||||
|
prepStmEntities=malloc((size_t)(len+1));
|
||||||
|
//TODO Release prepStmEntities!
|
||||||
|
snprintf(prepStmEntities,(size_t)(len+1),"SELECT * FROM entities WHERE id=%s;",value);
|
||||||
|
//printf("callback_get_entity() prepStmEntities: %s\n",prepStmEntities);
|
||||||
|
|
||||||
|
/*create prepared statement*/
|
||||||
|
/*conn:connection*/
|
||||||
|
/*stm:statement*/
|
||||||
|
/*0:number of passed parameters*/
|
||||||
|
/*NULL: server figures out parameter type*/
|
||||||
|
/*paramValues:pointer of an array of strings containing parameters*/
|
||||||
|
/*NULL:relevant for binary parameters*/
|
||||||
|
/*NULL:relevant for binary parameters*/
|
||||||
|
/*0:obtain result in text format*/
|
||||||
|
//TODO How to pass params?
|
||||||
|
pqRes = PQexecParams(conn, prepStmEntities, 0, NULL, NULL, NULL, NULL, 0);
|
||||||
|
if(PQresultStatus(pqRes) != PGRES_TUPLES_OK) {
|
||||||
|
/*handle error*/
|
||||||
|
printf("callback_get_entity() No data retrieved\n");
|
||||||
|
/*clean up result*/
|
||||||
|
PQclear(pqRes);
|
||||||
|
//TODO Why this casting?
|
||||||
|
(void)(request);
|
||||||
|
(void)(user_data);
|
||||||
|
ulfius_set_string_body_response(response, 200, "This is the /entity/:id/info route: Dba error!");
|
||||||
|
}else{
|
||||||
|
/*evaluate result*/
|
||||||
|
nbRecords = PQntuples(pqRes);
|
||||||
|
//printf("callback_get_entity() nbRecords: %d\n",nbRecords);
|
||||||
|
nbFields = PQnfields(pqRes);
|
||||||
|
arrayRecords=json_array();
|
||||||
|
for(int i=0;i<nbRecords;i++){
|
||||||
|
arrayFields=json_array();
|
||||||
|
for(int j=0;j<nbFields;j++){
|
||||||
|
stringField = json_string(PQgetvalue(pqRes,i,j));
|
||||||
|
json_array_append(arrayFields, stringField);
|
||||||
|
json_decref(stringField);
|
||||||
|
}
|
||||||
|
json_array_append(arrayRecords, arrayFields);
|
||||||
|
json_decref(arrayFields);
|
||||||
|
}
|
||||||
|
/*clean up result*/
|
||||||
|
PQclear(pqRes);
|
||||||
|
/*set response body*/
|
||||||
|
ulfius_set_json_body_response(response, 200, arrayRecords);
|
||||||
|
/*clean up JSON*/
|
||||||
|
json_decref(arrayRecords);
|
||||||
|
//TODO Why this casting?
|
||||||
|
(void)(request);
|
||||||
|
(void)(user_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*clean up remainings*/
|
||||||
|
free(url_params);
|
||||||
|
free(response_body);
|
||||||
|
printf("callback_get_entity() Done.\n");
|
||||||
|
return U_CALLBACK_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback function for route /entities to update an existing entity
|
||||||
|
*/
|
||||||
|
int callback_set_entity (const struct _u_request * request, struct _u_response * response, void * user_data) {
|
||||||
|
/*declarations*/
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback function for route /entities to reply all entities
|
||||||
|
*/
|
||||||
|
int callback_get_entities (const struct _u_request * request, struct _u_response * response, void * user_data) {
|
||||||
|
/*declarations*/
|
||||||
|
PGconn *conn;
|
||||||
|
char *prepStmEntities;
|
||||||
|
PGresult *pqRes;
|
||||||
|
int nbRecords,nbFields;
|
||||||
|
json_t *arrayRecords, *arrayFields, *stringField;
|
||||||
|
|
||||||
|
printf("callback_get_entities() Started...\n");
|
||||||
|
conn = (PGconn *)user_data;
|
||||||
|
|
||||||
|
/*define prepared statement*/
|
||||||
|
prepStmEntities = "SELECT * FROM entities;";
|
||||||
|
/*create prepared statement*/
|
||||||
|
/*conn:connection*/
|
||||||
|
/*stm:statement*/
|
||||||
|
/*1:number of passed parameters*/
|
||||||
|
/*NULL: server figures out parameter type*/
|
||||||
|
/*paramValues:pointer of an array of strings containing parameters*/
|
||||||
|
/*NULL:relevant for binary parameters*/
|
||||||
|
/*NULL:relevant for binary parameters*/
|
||||||
|
/*0:obtain result in text format*/
|
||||||
|
pqRes = PQexecParams(conn, prepStmEntities, 0, NULL, NULL, NULL, NULL, 0);
|
||||||
|
if (PQresultStatus(pqRes) != PGRES_TUPLES_OK) {
|
||||||
|
printf("callback_get_entities() No data retrieved\n");
|
||||||
|
/*clean up result*/
|
||||||
|
PQclear(pqRes);
|
||||||
|
//TODO Why this casting?
|
||||||
|
(void)(request);
|
||||||
|
(void)(user_data);
|
||||||
|
ulfius_set_string_body_response(response, 200, "This is the /entities route: Dba error!");
|
||||||
|
printf("callback_get_entities() Done.\n");
|
||||||
|
return U_CALLBACK_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*evaluate result*/
|
||||||
|
nbRecords = PQntuples(pqRes);
|
||||||
|
nbFields = PQnfields(pqRes);
|
||||||
|
arrayRecords=json_array();
|
||||||
|
for(int i=0;i<nbRecords;i++){
|
||||||
|
arrayFields=json_array();
|
||||||
|
for(int j=0;j<nbFields;j++){
|
||||||
|
/*not password, verification_token_id, created_account*/
|
||||||
|
if(j!=6&&j!=8&&j!=10){
|
||||||
|
stringField = json_string(PQgetvalue(pqRes,i,j));
|
||||||
|
json_array_append(arrayFields, stringField);
|
||||||
|
json_decref(stringField);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
json_array_append(arrayRecords, arrayFields);
|
||||||
|
json_decref(arrayFields);
|
||||||
|
}
|
||||||
|
/*clean up result*/
|
||||||
|
PQclear(pqRes);
|
||||||
|
/*set response body*/
|
||||||
|
ulfius_set_json_body_response(response, 200, arrayRecords);
|
||||||
|
/*clean up JSON*/
|
||||||
|
json_decref(arrayRecords);
|
||||||
|
//TODO Why this casting?
|
||||||
|
(void)(request);
|
||||||
|
(void)(user_data);
|
||||||
|
printf("callback_get_entities() Done.\n");
|
||||||
|
return U_CALLBACK_CONTINUE;
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
#target: dependency_1 dependency_2 dependency_3 ...
|
||||||
|
# command
|
||||||
|
#
|
||||||
|
RM = /bin/rm -f
|
||||||
|
OBJ = main.o pqconfo.o file2char.o
|
||||||
|
EXE = main
|
||||||
|
CC = /usr/bin/gcc
|
||||||
|
CFLAGS = -Wall
|
||||||
|
#
|
||||||
|
all: $(EXE)
|
||||||
|
#
|
||||||
|
$(EXE): $(OBJ)
|
||||||
|
$(CC) $(CFLAGS) $(OBJ) -L/usr/lib/x86_64-linux-gnu -lconfig -lulfius -lpq -ljansson -o $(EXE)
|
||||||
|
#
|
||||||
|
pqconfo.o: pqconfo.c pqconfo.h
|
||||||
|
$(CC) -c pqconfo.c -o pqconfo.o
|
||||||
|
#
|
||||||
|
file2char.o: file2char.c file2char.h
|
||||||
|
$(CC) -c file2char.c -o file2char.o
|
||||||
|
#
|
||||||
|
main.o: main.c
|
||||||
|
$(CC) -I/usr/include/postgresql -c main.c -o main.o
|
||||||
|
#
|
||||||
|
clean:
|
||||||
|
$(RM) $(OBJ) $(EXE) *~
|
|
@ -0,0 +1,89 @@
|
||||||
|
/*to use malloc*/
|
||||||
|
#include <stdlib.h>
|
||||||
|
/*to use libconfig*/
|
||||||
|
#include <libconfig.h>
|
||||||
|
/*to use struct pq_confo*/
|
||||||
|
#include "pqconfo.h"
|
||||||
|
|
||||||
|
/*get Postgresql connection information*/
|
||||||
|
int get_pq_confo(const char * file,const struct pq_confo ** confo){
|
||||||
|
/*declaration*/
|
||||||
|
config_t cfg;
|
||||||
|
const char * db, * host, * secret, * user;
|
||||||
|
int port;
|
||||||
|
|
||||||
|
fprintf(stdout,"get_pq_confo() Started...\n");
|
||||||
|
/*initialise new and EMPTY config*/
|
||||||
|
config_init(&cfg);
|
||||||
|
|
||||||
|
/* Read the file. If there is an error, report it and exit. */
|
||||||
|
/*TODO Validate config file name!*/
|
||||||
|
if(! config_read_file(&cfg, file))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "get_pq_confo() %s:%d - %s\n", config_error_file(&cfg),
|
||||||
|
config_error_line(&cfg), config_error_text(&cfg));
|
||||||
|
/*destroy config, BUT NOT the structure*/
|
||||||
|
config_destroy(&cfg);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
fprintf(stdout,"get_pq_confo() Parsing config file done\n");
|
||||||
|
|
||||||
|
/*lookup db string*/
|
||||||
|
if(config_lookup_string(&cfg, "pq.db", &db)){
|
||||||
|
printf("get_pq_confo() db: %s\n", db);
|
||||||
|
}else{
|
||||||
|
fprintf(stderr, "get_pq_confo() NO 'db' setting in config file found.\n");
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*lookup host string*/
|
||||||
|
if(config_lookup_string(&cfg, "pq.host", &host)){
|
||||||
|
printf("get_pq_confo() host: %s\n", host);
|
||||||
|
}else{
|
||||||
|
fprintf(stderr, "get_pq_confo() NO 'host' setting in config file found.\n");
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*lookup secret string*/
|
||||||
|
if(!config_lookup_string(&cfg, "pq.secret", &secret)){
|
||||||
|
fprintf(stderr, "get_pq_confo() NO 'secret' setting in config file found.\n");
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*lookup user string*/
|
||||||
|
if(config_lookup_string(&cfg, "pq.user", &user)){
|
||||||
|
printf("get_pq_confo() user: %s\n", user);
|
||||||
|
}else{
|
||||||
|
fprintf(stderr, "get_pq_confo() NO 'user' setting in config file found.\n");
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*lookup port int*/
|
||||||
|
if(config_lookup_int(&cfg, "pq.port", &port)){
|
||||||
|
printf("get_pq_confo() port: %d\n", port);
|
||||||
|
}else{
|
||||||
|
fprintf(stderr, "get_pq_confo() NO 'port' setting in config file found.\n");
|
||||||
|
return 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*create struct*/
|
||||||
|
struct pq_confo * pqConfo = (struct pq_confo *)malloc( sizeof(struct pq_confo));
|
||||||
|
sprintf(pqConfo->db,"%s",db);
|
||||||
|
sprintf(pqConfo->host,"%s",host);
|
||||||
|
pqConfo->port=port;
|
||||||
|
sprintf(pqConfo->secret,"%s",secret);
|
||||||
|
sprintf(pqConfo->user,"%s",user);
|
||||||
|
*confo = pqConfo;
|
||||||
|
|
||||||
|
/*destroy config, BUT NOT the structure*/
|
||||||
|
config_destroy(&cfg);
|
||||||
|
|
||||||
|
/*return success*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*free Postgresql connection information*/
|
||||||
|
int free_pq_confo(const struct pq_confo ** confo){
|
||||||
|
free((struct pq_confo *)*confo);
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
/*We can use CPP tricks to avoid parsing the same header file more than once*/
|
||||||
|
#ifndef PQCONFO_H
|
||||||
|
# define PQCONFO_H
|
||||||
|
|
||||||
|
/*structure for Postgresql connection information*/
|
||||||
|
struct pq_confo
|
||||||
|
{
|
||||||
|
char db[23];
|
||||||
|
char host[23];
|
||||||
|
int port;
|
||||||
|
char secret[42];
|
||||||
|
char user[23];
|
||||||
|
};
|
||||||
|
|
||||||
|
/*get Postgresql connection information*/
|
||||||
|
int get_pq_confo(const char * file,const struct pq_confo ** confo);
|
||||||
|
|
||||||
|
/*free Postgresql connection information*/
|
||||||
|
int free_pq_confo(const struct pq_confo ** confo);
|
||||||
|
|
||||||
|
#endif /* PQCONFO_H */
|
|
@ -0,0 +1,21 @@
|
||||||
|
# rgncycle-libulfius
|
||||||
|
|
||||||
|
libulfius API for rgncycle
|
||||||
|
|
||||||
|
* build
|
||||||
|
|
||||||
|
```
|
||||||
|
make
|
||||||
|
```
|
||||||
|
|
||||||
|
* run
|
||||||
|
|
||||||
|
```
|
||||||
|
./main
|
||||||
|
```
|
||||||
|
|
||||||
|
* run Valgrind tool `Memcheck`
|
||||||
|
|
||||||
|
```
|
||||||
|
valgrind --leak-check=yes -s ./main
|
||||||
|
```
|
Loading…
Reference in New Issue