diff --git a/dap-sdk/core/include/dap_file_utils.h b/dap-sdk/core/include/dap_file_utils.h index 92cfe9812c49b4540b6c1d608de58e3470ce7a3e..9bc55055d72e00a02bdfc5d0d30ac3cca3ab4060 100755 --- a/dap-sdk/core/include/dap_file_utils.h +++ b/dap-sdk/core/include/dap_file_utils.h @@ -44,6 +44,9 @@ #else +#ifndef O_BINARY +# define O_BINARY 0 +#endif #define DAP_DIR_SEPARATOR '/' #define DAP_DIR_SEPARATOR_S "/" #define DAP_IS_DIR_SEPARATOR(c) ((c) == DAP_DIR_SEPARATOR) @@ -102,4 +105,10 @@ char* dap_path_get_dirname(const char *a_file_name); */ dap_list_name_directories_t *dap_get_subs(const char *a_path_name); + +/* + * Reads an entire file into allocated memory, with error checking. + */ +bool dap_file_get_contents(const char *filename, char **contents, size_t *length); + #endif // _FILE_UTILS_H_ diff --git a/dap-sdk/core/src/dap_file_utils.c b/dap-sdk/core/src/dap_file_utils.c index 910c64a79ee21dfc1aa2463b6cc3f39921b93894..b57a898265a98fe8433ef2e0fbf7744f3a22f332 100755 --- a/dap-sdk/core/src/dap_file_utils.c +++ b/dap-sdk/core/src/dap_file_utils.c @@ -25,6 +25,11 @@ #include <stdlib.h> #include <stdint.h> #include <errno.h> +#include <fcntl.h> +#include <stdbool.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> #if (OS_TARGET == OS_MACOS) #include <stdio.h> #else @@ -404,3 +409,203 @@ dap_list_name_directories_t *dap_get_subs(const char *a_path_dir){ #endif return list; } + +static bool get_contents_stdio(const char *filename, FILE *f, char **contents, size_t *length) +{ + char buf[4096]; + size_t bytes; /* always <= sizeof(buf) */ + char *str = NULL; + size_t total_bytes = 0; + size_t total_allocated = 0; + char *tmp; + assert(f != NULL); + while(!feof(f)) { + int save_errno; + + bytes = fread(buf, 1, sizeof(buf), f); + save_errno = errno; + + if(total_bytes > ULONG_MAX - bytes) + goto file_too_large; + + /* Possibility of overflow eliminated above. */ + while(total_bytes + bytes >= total_allocated) { + if(str) { + if(total_allocated > ULONG_MAX / 2) + goto file_too_large; + total_allocated *= 2; + } + else { + total_allocated = MIN(bytes + 1, sizeof(buf)); + } + + tmp = DAP_REALLOC(str, total_allocated); + + if(tmp == NULL) + goto error; + + str = tmp; + } + + if(ferror(f)) + goto error; + + assert(str != NULL); + memcpy(str + total_bytes, buf, bytes); + total_bytes += bytes; + } + + fclose(f); + + if(total_allocated == 0) + { + str = DAP_NEW_SIZE(char, 1); + total_bytes = 0; + } + + str[total_bytes] = '\0'; + + if(length) + *length = total_bytes; + + *contents = str; + + return true; + + file_too_large: + error: + + DAP_DELETE(str); + fclose(f); + return false; +} + +#ifndef _WIN32 + +static bool dap_get_contents_regfile(const char *filename, struct stat *stat_buf, int fd, char **contents, + size_t *length) +{ + char *buf; + size_t bytes_read; + size_t size; + size_t alloc_size; + + size = stat_buf->st_size; + + alloc_size = size + 1; + buf = DAP_NEW_SIZE(char, alloc_size); + + if(buf == NULL) { + goto error; + } + + bytes_read = 0; + while(bytes_read < size) { + size_t rc; + + rc = read(fd, buf + bytes_read, size - bytes_read); + + if(rc < 0) { + if(errno != EINTR) { + DAP_DELETE(buf); + goto error; + } + } + else if(rc == 0) + break; + else + bytes_read += rc; + } + + buf[bytes_read] = '\0'; + + if(length) + *length = bytes_read; + + *contents = buf; + + close(fd); + + return true; + + error: + + close(fd); + + return false; +} + +static bool dap_get_contents_posix(const char *filename, char **contents, size_t *length) +{ + struct stat stat_buf; + int fd; + + /* O_BINARY useful on Cygwin */ + fd = open(filename, O_RDONLY | O_BINARY); + + if(fd < 0) + return false; + + /* I don't think this will ever fail, aside from ENOMEM, but. */ + if(fstat(fd, &stat_buf) < 0) { + close(fd); + return false; + } + + if(stat_buf.st_size > 0 && S_ISREG(stat_buf.st_mode)) { + bool retval = dap_get_contents_regfile(filename, + &stat_buf, + fd, + contents, + length); + return retval; + } + else { + FILE *f; + bool retval; + f = fdopen(fd, "r"); + if(f == NULL) + return false; + retval = get_contents_stdio(filename, f, contents, length); + return retval; + } +} + +#else /* _WIN32 */ + +static bool dap_get_contents_win32(const char *filename, char **contents, size_t *length) +{ + FILE *f; + bool retval; + + f = fopen(filename, "rb"); + + if(f == NULL) + { + return false; + } + retval = get_contents_stdio (filename, f, contents, length, error); + return retval; +} + +#endif + +/* + * Reads an entire file into allocated memory, with error checking. + */ +bool dap_file_get_contents(const char *filename, char **contents, size_t *length) +{ + dap_return_val_if_fail(filename != NULL, false); + dap_return_val_if_fail(contents != NULL, false); + + *contents = NULL; + if(length) + *length = 0; + +#ifdef _WIN32 + return dap_get_contents_win32 (filename, contents, length); +#else + return dap_get_contents_posix(filename, contents, length); +#endif +} + diff --git a/modules/net/dap_chain_net_news.c b/modules/net/dap_chain_net_news.c new file mode 100644 index 0000000000000000000000000000000000000000..9a132c43ce37f003602e2053f3627ab27f289903 --- /dev/null +++ b/modules/net/dap_chain_net_news.c @@ -0,0 +1,126 @@ +/* + * Authors: + * Alexander Lysikov <alexander.lysikov@demlabs.net> + * DeM Labs Inc. https://demlabs.net + * Kelvin Project https://github.com/kelvinblockchain + * Copyright (c) 2020 + * All rights reserved. + + This file is part of DAP (Deus Applications Prototypes) the open source project + + DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + DAP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with any DAP based project. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stddef.h> + +#include "dap_common.h" +#include "dap_string.h" +#include "dap_strfuncs.h" +#include "dap_file_utils.h" +#include "dap_config.h" + +#include "http_status_code.h" +#include "dap_http_simple.h" +#include "dap_enc_http.h" +//#include "<dap_chain_global_db_driver.h> +#include "dap_chain_global_db.h" +#include "dap_chain_net_news.h" +#define LOG_TAG "chain_net_news" + +#define NEWS_URL "/news" +#define GROUP_NEWS "cdb.news" +#define DEFAULT_LANG "en" + +/* Set news in the selected language + * a_lang - a language like "en", "ru", "fr" + * a_data_news - news data + * a_data_news_len length of news + */ +int dap_chain_net_news_write(char *a_lang, byte_t *a_data_news, size_t a_data_news_len) +{ + if(!a_data_news || !a_data_news_len) + return -2; + if(!a_lang) + a_lang = DEFAULT_LANG; + size_t l_data_len_out = 0; + if(dap_chain_global_db_gr_set(a_lang, a_data_news, a_data_news_len, GROUP_NEWS)) + return 0; + return -1; +} + +/* Get news in the selected language + * a_lang - a language like "en", "ru", "fr" + */ +byte_t* dap_chain_net_news_read(const char *a_lang, size_t *a_news_len) +{ + if(!a_lang) + return NULL; + byte_t *l_ret_data = NULL; + size_t l_data_len_num = 0; + dap_store_obj_t *l_obj = dap_chain_global_db_obj_gr_get(a_lang, &l_data_len_num, GROUP_NEWS); + if(l_obj && l_obj->value_len) { + l_ret_data = DAP_NEW_Z_SIZE(byte_t, l_obj->value_len); + memcpy(l_ret_data, l_obj->value, l_obj->value_len); + if(a_news_len) + *a_news_len = l_obj->value_len; + } + dap_store_obj_free(l_obj, l_data_len_num); + return l_ret_data; +} + +/** + * @brief news_http_proc + * @param a_http_simple + * @param a_arg + */ +static void news_http_proc(struct dap_http_simple *a_http_simple, void * a_arg) +{ + log_it(L_DEBUG, "news_http_proc request"); + http_status_code_t * return_code = (http_status_code_t*) a_arg; + const char *l_lang = DEFAULT_LANG; + if(dap_strcmp(a_http_simple->http->url_path, NEWS_URL)) { + l_lang = a_http_simple->http->url_path; + } + + if(l_lang) + { + size_t l_news_data_len = 0; + // get news in the selected language + char *l_news_data = dap_chain_net_news_read(l_lang, &l_news_data_len); + // get news in the default language + if(!l_news_data && dap_strcmp(a_http_simple->http->in_query_string, "LocalNewsOnly")) + l_news_data = dap_chain_net_news_read(DEFAULT_LANG, &l_news_data_len); + a_http_simple->reply = l_news_data ? l_news_data : dap_strdup("no news"); + a_http_simple->reply_size = l_news_data_len; + *return_code = Http_Status_OK; + } + else { + log_it(L_ERROR, "Wrong request. Must be %s/<lang_code>, example http:/<addr>%s/en", NEWS_URL, NEWS_URL); + a_http_simple->reply = dap_strdup_printf("Wrong request. Must be %s/<lang_code>, example http:/<addr>%s/en", + NEWS_URL, NEWS_URL); + a_http_simple->reply_size = strlen(a_http_simple->reply); + *return_code = Http_Status_NotFound; + } +} + +/** + * @brief dap_chain_net_news_add_proc + * @param sh HTTP server instance + */ +void dap_chain_net_news_add_proc(struct dap_http * sh) +{ + const char * url = NEWS_URL; + dap_http_simple_proc_add(sh, url, 14096, news_http_proc); +} + diff --git a/modules/net/dap_chain_net_news.h b/modules/net/dap_chain_net_news.h new file mode 100644 index 0000000000000000000000000000000000000000..0982b05159e95c2af2484f1512deeb21a51c235f --- /dev/null +++ b/modules/net/dap_chain_net_news.h @@ -0,0 +1,39 @@ +/* + * Authors: + * Alexander Lysikov <alexander.lysikov@demlabs.net> + * DeM Labs Inc. https://demlabs.net + * Kelvin Project https://github.com/kelvinblockchain + * Copyright (c) 2020 + * All rights reserved. + + This file is part of DAP (Deus Applications Prototypes) the open source project + + DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + DAP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with any DAP based project. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "dap_http.h" + +/* Set news in the selected language + * a_lang - a language like "en", "ru", "fr" + * a_data_news - news data + * a_data_news_len length of news + */ +int dap_chain_net_news_write(char *a_lang, byte_t *a_data_news, size_t a_data_news_len); + +/* Get news in the selected language + * a_lang - a language like "en", "ru", "fr" + */ +byte_t* dap_chain_net_news_read(const char *a_lang, size_t *a_news_len); + +void dap_chain_net_news_add_proc(struct dap_http * sh); diff --git a/modules/net/dap_chain_node_cli.c b/modules/net/dap_chain_node_cli.c index 3b742cf1404bdb19ba646cc8cbecbe078c580c00..1f4fe7696df1502b0356b1f51933ae1159fb1e56 100644 --- a/modules/net/dap_chain_node_cli.c +++ b/modules/net/dap_chain_node_cli.c @@ -1011,6 +1011,10 @@ int dap_chain_node_cli_init(dap_config_t * g_config) dap_chain_node_cli_cmd_item_create ("exit", com_exit, NULL, "Stop application and exit", "exit\n" ); + // News + dap_chain_node_cli_cmd_item_create("news", com_news, NULL, "Add News for VPN clients. Language code is a text code like \"en\", \"ru\", \"fr\"", + "news [-text <news text> | -file <filename with news>] -lang <language code> \n"); + // create thread for waiting of clients pthread_t l_thread_id; diff --git a/modules/net/include/dap_chain_node_cli_cmd.h b/modules/net/include/dap_chain_node_cli_cmd.h index 505911d1d5af8a0fee5bc35d09a802266fa7457b..cc6821e6f864c8df5ef0635916d200da3b98cdaf 100644 --- a/modules/net/include/dap_chain_node_cli_cmd.h +++ b/modules/net/include/dap_chain_node_cli_cmd.h @@ -133,6 +133,9 @@ int com_stats(int argc, char ** argv, void *arg_func, char **str_reply); int com_exit(int argc, char ** argv, void *arg_func, char **str_reply); +// Add News for VPN clients +int com_news(int a_argc, char ** a_argv, void *a_arg_func, char **a_str_reply); + // vpn_client command int com_vpn_client(int a_argc, char ** a_argv, void *arg_func, char **a_str_reply);