diff --git a/include/dap_client_remote.h b/include/dap_client_remote.h index 29cbfc81fe71b4ef33d5b103621d6686b127019c..b3b663bf988807f2a6a780a8c37dc949bab86fcf 100755 --- a/include/dap_client_remote.h +++ b/include/dap_client_remote.h @@ -1,129 +1,131 @@ -/* - * Authors: - * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net> - * DeM Labs Inc. https://demlabs.net - * Kelvin Project https://github.com/kelvinblockchain - * Copyright (c) 2017-2018 - * 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/>. -*/ -#pragma once - -#include <stdint.h> -#include <stddef.h> -#include <stdbool.h> -#include "uthash.h" - -#ifndef WIN32 -#include <sys/epoll.h> -#include <sys/timerfd.h> -#endif - -#ifndef EPOLL_HANDLE - #ifndef WIN32 - #define EPOLL_HANDLE int - #else - #define EPOLL_HANDLE HANDLE - #endif -#endif - -typedef char str_ip[16]; - -typedef struct dap_server dap_server_t; -typedef struct dap_server_thread_s dap_server_thread_t; - -struct dap_client_remote; - -typedef void (*dap_server_client_callback_t) (struct dap_client_remote *,void * arg); // Callback for specific client operations - -#define DAP_CLIENT_REMOTE_BUF 500000 -#define CLIENT_ID_SIZE 12 - -typedef char dap_server_client_id[CLIENT_ID_SIZE]; - -typedef struct traffic_stats { - - size_t buf_size_total; - size_t buf_size_total_old; // for calculate speed - double speed_mbs; // MegaBits per second -} traffic_stats_t; - -typedef struct dap_client_remote { - - int socket; - dap_server_client_id id; - - uint32_t flags; - bool close_denied; - bool kill_signal; - - uint16_t port; - str_ip s_ip; - - uint32_t buf_out_zero_count; - char buf_in[DAP_CLIENT_REMOTE_BUF]; // Internal buffer for input data - - size_t buf_in_size; // size of data that is in the input buffer - - traffic_stats_t upload_stat; - traffic_stats_t download_stat; - - char buf_out[DAP_CLIENT_REMOTE_BUF]; // Internal buffer for output data - size_t buf_out_offset; - - char hostaddr[1024]; // Address - char service[128]; - - size_t buf_out_size; // size of data that is in the output buffer - struct epoll_event pevent; - - EPOLL_HANDLE efd; // Epoll fd - int tn; // working thread index - - time_t time_connection; - time_t last_time_active; - - struct dap_server *server; - - UT_hash_handle hh; - struct dap_client_remote *next, *prev; - struct dap_client_remote *knext, *kprev; - - void *_internal; - void *_inheritor; // Internal data to specific client type, usualy states for state machine - -} dap_client_remote_t; // Node of bidirectional list of clients - -int dap_client_remote_init( void ); // Init clients module -void dap_client_remote_deinit( void ); // Deinit clients module - -dap_client_remote_t *dap_client_remote_create( dap_server_t *sh, int s, dap_server_thread_t *dsth ); -dap_client_remote_t *dap_client_remote_find( int sock, struct dap_server *sh); // Find client by socket - -bool dap_client_remote_is_ready_to_read( dap_client_remote_t * sc ); -bool dap_client_remote_is_ready_to_write( dap_client_remote_t * sc ); -void dap_client_remote_ready_to_read( dap_client_remote_t * sc,bool is_ready ); -void dap_client_remote_ready_to_write( dap_client_remote_t * sc,bool is_ready ); - -size_t dap_client_remote_write( dap_client_remote_t *sc, const void * data, size_t data_size ); -size_t dap_client_remote_write_f( dap_client_remote_t *a_client, const char * a_format,... ); -size_t dap_client_remote_read( dap_client_remote_t *sc, void * data, size_t data_size ); - -void dap_client_remote_remove( dap_client_remote_t *sc, struct dap_server * sh ); // Removes the client from the list - -void dap_client_remote_shrink_buf_in( dap_client_remote_t * cl, size_t shrink_size ); - +/* + * Authors: + * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net> + * DeM Labs Inc. https://demlabs.net + * Kelvin Project https://github.com/kelvinblockchain + * Copyright (c) 2017-2018 + * 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/>. +*/ +#pragma once + +#include <stdint.h> +#include <stddef.h> +#include <stdbool.h> +#include "uthash.h" + +#ifndef WIN32 +#include <sys/epoll.h> +#include <sys/timerfd.h> +#endif + +#ifndef EPOLL_HANDLE + #ifndef WIN32 + #define EPOLL_HANDLE int + #else + #define EPOLL_HANDLE HANDLE + #endif +#endif + +typedef char str_ip[16]; + +typedef struct dap_server dap_server_t; +typedef struct dap_server_thread_s dap_server_thread_t; + +struct dap_client_remote; + +typedef void (*dap_server_client_callback_t) (struct dap_client_remote *,void * arg); // Callback for specific client operations + +#define DAP_CLIENT_REMOTE_BUF 500000 +#define CLIENT_ID_SIZE 12 + +typedef char dap_server_client_id[CLIENT_ID_SIZE]; + +typedef struct traffic_stats { + + size_t buf_size_total; + size_t buf_size_total_old; // for calculate speed + double speed_mbs; // MegaBits per second +} traffic_stats_t; + +typedef struct dap_client_remote { + + int socket; + dap_server_client_id id; + + uint32_t flags; + bool no_close; + bool kill_signal; + + uint16_t port; + str_ip s_ip; + + uint32_t buf_out_zero_count; + char buf_in[DAP_CLIENT_REMOTE_BUF]; // Internal buffer for input data + + size_t buf_in_size; // size of data that is in the input buffer + + traffic_stats_t upload_stat; + traffic_stats_t download_stat; + + char buf_out[DAP_CLIENT_REMOTE_BUF]; // Internal buffer for output data + size_t buf_out_offset; + + char hostaddr[1024]; // Address + char service[128]; + + size_t buf_out_size; // size of data that is in the output buffer + struct epoll_event pevent; + + EPOLL_HANDLE efd; // Epoll fd + int tn; // working thread index + + time_t time_connection; + time_t last_time_active; + + struct dap_server *server; + dap_server_thread_t *thread; + + UT_hash_handle hh; + struct dap_client_remote *next, *prev; + struct dap_client_remote *knext, *kprev; + + void *_internal; + void *_inheritor; // Internal data to specific client type, usualy states for state machine + +} dap_client_remote_t; // Node of bidirectional list of clients + +int dap_client_remote_init( void ); // Init clients module +void dap_client_remote_deinit( void ); // Deinit clients module + +dap_client_remote_t *dap_client_remote_create( dap_server_t *sh, int s, dap_server_thread_t *dsth ); +dap_client_remote_t *dap_client_remote_find( int sock, dap_server_thread_t *t ); + +bool dap_client_remote_is_ready_to_read( dap_client_remote_t * sc ); +bool dap_client_remote_is_ready_to_write( dap_client_remote_t * sc ); +void dap_client_remote_ready_to_read( dap_client_remote_t * sc,bool is_ready ); +void dap_client_remote_ready_to_write( dap_client_remote_t * sc,bool is_ready ); + +size_t dap_client_remote_write( dap_client_remote_t *sc, const void * data, size_t data_size ); +size_t dap_client_remote_write_f( dap_client_remote_t *a_client, const char * a_format,... ); +size_t dap_client_remote_read( dap_client_remote_t *sc, void * data, size_t data_size ); + +//void dap_client_remote_remove( dap_client_remote_t *sc, struct dap_server * sh ); // Removes the client from the list +void dap_client_remote_remove( dap_client_remote_t *sc ); + +void dap_client_remote_shrink_buf_in( dap_client_remote_t * cl, size_t shrink_size ); + diff --git a/include/dap_events.h b/include/dap_events.h index 1b2d52ae807b080dba10cb2ad9a65c9959e3d069..2b27453f87088e5d8c3c26a4b57b391f98001439 100755 --- a/include/dap_events.h +++ b/include/dap_events.h @@ -1,94 +1,94 @@ -/* - * Authors: - * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net> - * DeM Labs Inc. https://demlabs.net - * Kelvin Project https://github.com/kelvinblockchain - * Copyright (c) 2017-2019 - * 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/>. -*/ -#pragma once - -#ifndef WIN32 -#include <netinet/in.h> - -#include <stdint.h> -#include <pthread.h> -#define EPOLL_HANDLE int -#else -#define EPOLL_HANDLE HANDLE -#endif - -#include "uthash.h" -#include "dap_events_socket.h" -#include "dap_server.h" - -struct dap_events; - -typedef void (*dap_events_callback_t) (struct dap_events *, void *arg); // Callback for specific server's operations - -typedef struct dap_thread { - pthread_t tid; -} dap_thread_t; - -struct dap_worker; - -typedef struct dap_events { - - dap_events_socket_t *sockets; // Hashmap of event sockets - dap_events_socket_t *dlsockets; // Dlist of event sockets - dap_events_socket_t *to_kill_sockets; // Dlist of event sockets - - pthread_rwlock_t sockets_rwlock; - void *_inheritor; // Pointer to the internal data, HTTP for example - dap_thread_t proc_thread; - pthread_rwlock_t servers_rwlock; - -} dap_events_t; - -typedef struct dap_worker -{ - uint32_t event_sockets_count; - uint32_t event_to_kill_count; - - EPOLL_HANDLE epoll_fd; - uint32_t number_thread; - pthread_mutex_t locker_on_count; - dap_events_t *events; - -} dap_worker_t; - -int32_t dap_events_init( uint32_t a_threads_count, size_t conn_t ); // Init server module -void dap_events_deinit( ); // Deinit server module - -void dap_events_thread_wake_up( dap_thread_t *th ); -dap_events_t* dap_events_new( ); -void dap_events_delete( dap_events_t * sh ); -//void dap_events_socket_remove_and_delete( dap_events_socket_t* a_es ); -void dap_events_socket_remove_and_delete(dap_events_socket_t* a_es, bool preserve_inheritor ); - -void dap_events_kill_socket( dap_events_socket_t *a_es ); - -int32_t dap_events_start( dap_events_t *sh ); -int32_t dap_events_wait( dap_events_t *sh ); - -uint32_t dap_worker_get_index_min( ); -dap_worker_t *dap_worker_get_min( ); - -void dap_worker_add_events_socket( dap_events_socket_t * a_events_socket ); -void dap_worker_print_all( ); - +/* + * Authors: + * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net> + * DeM Labs Inc. https://demlabs.net + * Kelvin Project https://github.com/kelvinblockchain + * Copyright (c) 2017-2019 + * 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/>. +*/ +#pragma once + +#ifndef WIN32 +#include <netinet/in.h> + +#include <stdint.h> +#include <pthread.h> +#define EPOLL_HANDLE int +#else +#define EPOLL_HANDLE HANDLE +#endif + +#include "uthash.h" +#include "dap_events_socket.h" +#include "dap_server.h" + +struct dap_events; + +typedef void (*dap_events_callback_t) (struct dap_events *, void *arg); // Callback for specific server's operations + +typedef struct dap_thread { + pthread_t tid; +} dap_thread_t; + +struct dap_worker; + +typedef struct dap_events { + + dap_events_socket_t *sockets; // Hashmap of event sockets + dap_events_socket_t *dlsockets; // Dlist of event sockets + dap_events_socket_t *to_kill_sockets; // Dlist of event sockets + + pthread_rwlock_t sockets_rwlock; + void *_inheritor; // Pointer to the internal data, HTTP for example + dap_thread_t proc_thread; + pthread_rwlock_t servers_rwlock; + +} dap_events_t; + +typedef struct dap_worker +{ + uint32_t event_sockets_count; + uint32_t event_to_kill_count; + + EPOLL_HANDLE epoll_fd; + uint32_t number_thread; + pthread_mutex_t locker_on_count; + dap_events_t *events; + +} dap_worker_t; + +int32_t dap_events_init( uint32_t a_threads_count, size_t conn_t ); // Init server module +void dap_events_deinit( ); // Deinit server module + +void dap_events_thread_wake_up( dap_thread_t *th ); +dap_events_t* dap_events_new( ); +void dap_events_delete( dap_events_t * sh ); +//void dap_events_socket_remove_and_delete( dap_events_socket_t* a_es ); +void dap_events_socket_remove_and_delete(dap_events_socket_t* a_es, bool preserve_inheritor ); + +void dap_events_kill_socket( dap_events_socket_t *a_es ); + +int32_t dap_events_start( dap_events_t *sh ); +int32_t dap_events_wait( dap_events_t *sh ); + +uint32_t dap_worker_get_index_min( ); +dap_worker_t *dap_worker_get_min( ); + +void dap_worker_add_events_socket( dap_events_socket_t * a_events_socket ); +void dap_worker_print_all( ); + diff --git a/include/dap_events_socket.h b/include/dap_events_socket.h index 0a3dd3bfe02b7ade9ae36f2912c12ce35340d5e0..ea1822433b904a84acd302b8abb7694fd9d2e8d6 100755 --- a/include/dap_events_socket.h +++ b/include/dap_events_socket.h @@ -1,158 +1,158 @@ -/* - * Authors: - * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net> - * DeM Labs Inc. https://demlabs.net - * Kelvin Project https://github.com/kelvinblockchain - * Copyright (c) 2017-2019 - * 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/>. -*/ -#pragma once - -#include <stdint.h> -#include <stddef.h> -#include <stdbool.h> -#include "uthash.h" -#ifndef _WIN32 -#include <sys/epoll.h> -#endif - -struct dap_events; -struct dap_events_socket; -struct dap_worker; - -typedef struct dap_server dap_server_t; -typedef void (*dap_events_socket_callback_t) (struct dap_events_socket *,void * arg); // Callback for specific client operations - -typedef struct dap_events_socket_callbacks { - - dap_events_socket_callback_t new_callback; // Create new client callback - dap_events_socket_callback_t delete_callback; // Delete client callback - dap_events_socket_callback_t read_callback; // Read function - dap_events_socket_callback_t write_callback; // Write function - dap_events_socket_callback_t error_callback; // Error processing function - -} dap_events_socket_callbacks_t; - -#define DAP_EVENTS_SOCKET_BUF 100000 - -#if 0 -typedef struct dap_events_socket { - - int socket; - bool signal_close; - - bool _ready_to_write; - bool _ready_to_read; - - uint32_t buf_out_zero_count; - union{ - uint8_t buf_in[DAP_EVENTS_SOCKET_BUF+1]; // Internal buffer for input data - char buf_in_str[DAP_EVENTS_SOCKET_BUF+1]; - }; - size_t buf_in_size; // size of data that is in the input buffer - - uint8_t buf_out[DAP_EVENTS_SOCKET_BUF+1]; // Internal buffer for output data - - char hostaddr[1024]; // Address - char service[128]; - - size_t buf_out_size; // size of data that is in the output buffer - - struct dap_events *events; - - struct dap_worker *dap_worker; - dap_events_socket_callbacks_t *callbacks; - - time_t time_connection; - time_t last_ping_request; - bool is_pingable; - - UT_hash_handle hh; - - void * _inheritor; // Inheritor data to specific client type, usualy states for state machine -} dap_events_socket_t; // Node of bidirectional list of clients -#endif - -typedef struct dap_events_socket { - - int32_t socket; - - uint32_t flags; -// bool signal_close; - bool close_denied; - bool kill_signal; -// bool _ready_to_write; -// bool _ready_to_read; - - uint32_t buf_out_zero_count; - union{ - uint8_t buf_in[DAP_EVENTS_SOCKET_BUF+1]; // Internal buffer for input data - char buf_in_str[DAP_EVENTS_SOCKET_BUF+1]; - }; - size_t buf_in_size; // size of data that is in the input buffer - - uint8_t buf_out[DAP_EVENTS_SOCKET_BUF+1]; // Internal buffer for output data - - char hostaddr[1024]; // Address - char service[128]; - - size_t buf_out_size; // size of data that is in the output buffer - - struct dap_events *events; - struct dap_worker *dap_worker; - struct epoll_event ev; - - dap_events_socket_callbacks_t *callbacks; - - time_t time_connection; - time_t last_time_active; - time_t last_ping_request; - bool is_pingable; - - UT_hash_handle hh; - struct dap_events_socket *next, *prev; - struct dap_events_socket *knext, *kprev; - - void *_inheritor; // Inheritor data to specific client type, usualy states for state machine - -} dap_events_socket_t; // Node of bidirectional list of clients - -int dap_events_socket_init(); // Init clients module -void dap_events_socket_deinit(); // Deinit clients module - -void dap_events_socket_create_after(dap_events_socket_t * a_es); - -dap_events_socket_t * dap_events_socket_wrap_no_add(struct dap_events * a_events, - int s, dap_events_socket_callbacks_t * a_callbacks); // Create new client and add it to the list - - -dap_events_socket_t * dap_events_socket_find(int sock, struct dap_events * sh); // Find client by socket - -bool dap_events_socket_is_ready_to_read(dap_events_socket_t * sc); -bool dap_events_socket_is_ready_to_write(dap_events_socket_t * sc); -void dap_events_socket_set_readable(dap_events_socket_t * sc,bool is_ready); -void dap_events_socket_set_writable(dap_events_socket_t * sc,bool is_ready); - -size_t dap_events_socket_write(dap_events_socket_t *sc, const void * data, size_t data_size); -size_t dap_events_socket_write_f(dap_events_socket_t *sc, const char * format,...); -size_t dap_events_socket_read(dap_events_socket_t *sc, void * data, size_t data_size); - -void dap_events_socket_delete(dap_events_socket_t *sc,bool preserve_inheritor); // Removes the client from the list - -void dap_events_socket_shrink_buf_in(dap_events_socket_t * cl, size_t shrink_size); - +/* + * Authors: + * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net> + * DeM Labs Inc. https://demlabs.net + * Kelvin Project https://github.com/kelvinblockchain + * Copyright (c) 2017-2019 + * 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/>. +*/ +#pragma once + +#include <stdint.h> +#include <stddef.h> +#include <stdbool.h> +#include "uthash.h" +#ifndef _WIN32 +#include <sys/epoll.h> +#endif + +struct dap_events; +struct dap_events_socket; +struct dap_worker; + +typedef struct dap_server dap_server_t; +typedef void (*dap_events_socket_callback_t) (struct dap_events_socket *,void * arg); // Callback for specific client operations + +typedef struct dap_events_socket_callbacks { + + dap_events_socket_callback_t new_callback; // Create new client callback + dap_events_socket_callback_t delete_callback; // Delete client callback + dap_events_socket_callback_t read_callback; // Read function + dap_events_socket_callback_t write_callback; // Write function + dap_events_socket_callback_t error_callback; // Error processing function + +} dap_events_socket_callbacks_t; + +#define DAP_EVENTS_SOCKET_BUF 100000 + +#if 0 +typedef struct dap_events_socket { + + int socket; + bool signal_close; + + bool _ready_to_write; + bool _ready_to_read; + + uint32_t buf_out_zero_count; + union{ + uint8_t buf_in[DAP_EVENTS_SOCKET_BUF+1]; // Internal buffer for input data + char buf_in_str[DAP_EVENTS_SOCKET_BUF+1]; + }; + size_t buf_in_size; // size of data that is in the input buffer + + uint8_t buf_out[DAP_EVENTS_SOCKET_BUF+1]; // Internal buffer for output data + + char hostaddr[1024]; // Address + char service[128]; + + size_t buf_out_size; // size of data that is in the output buffer + + struct dap_events *events; + + struct dap_worker *dap_worker; + dap_events_socket_callbacks_t *callbacks; + + time_t time_connection; + time_t last_ping_request; + bool is_pingable; + + UT_hash_handle hh; + + void * _inheritor; // Inheritor data to specific client type, usualy states for state machine +} dap_events_socket_t; // Node of bidirectional list of clients +#endif + +typedef struct dap_events_socket { + + int32_t socket; + + uint32_t flags; +// bool signal_close; + bool no_close; + bool kill_signal; +// bool _ready_to_write; +// bool _ready_to_read; + + uint32_t buf_out_zero_count; + union{ + uint8_t buf_in[DAP_EVENTS_SOCKET_BUF+1]; // Internal buffer for input data + char buf_in_str[DAP_EVENTS_SOCKET_BUF+1]; + }; + size_t buf_in_size; // size of data that is in the input buffer + + uint8_t buf_out[DAP_EVENTS_SOCKET_BUF+1]; // Internal buffer for output data + + char hostaddr[1024]; // Address + char service[128]; + + size_t buf_out_size; // size of data that is in the output buffer + + struct dap_events *events; + struct dap_worker *dap_worker; + struct epoll_event ev; + + dap_events_socket_callbacks_t *callbacks; + + time_t time_connection; + time_t last_time_active; + time_t last_ping_request; + bool is_pingable; + + UT_hash_handle hh; + struct dap_events_socket *next, *prev; + struct dap_events_socket *knext, *kprev; + + void *_inheritor; // Inheritor data to specific client type, usualy states for state machine + +} dap_events_socket_t; // Node of bidirectional list of clients + +int dap_events_socket_init(); // Init clients module +void dap_events_socket_deinit(); // Deinit clients module + +void dap_events_socket_create_after(dap_events_socket_t * a_es); + +dap_events_socket_t * dap_events_socket_wrap_no_add(struct dap_events * a_events, + int s, dap_events_socket_callbacks_t * a_callbacks); // Create new client and add it to the list + + +dap_events_socket_t * dap_events_socket_find(int sock, struct dap_events * sh); // Find client by socket + +bool dap_events_socket_is_ready_to_read(dap_events_socket_t * sc); +bool dap_events_socket_is_ready_to_write(dap_events_socket_t * sc); +void dap_events_socket_set_readable(dap_events_socket_t * sc,bool is_ready); +void dap_events_socket_set_writable(dap_events_socket_t * sc,bool is_ready); + +size_t dap_events_socket_write(dap_events_socket_t *sc, const void * data, size_t data_size); +size_t dap_events_socket_write_f(dap_events_socket_t *sc, const char * format,...); +size_t dap_events_socket_read(dap_events_socket_t *sc, void * data, size_t data_size); + +void dap_events_socket_delete(dap_events_socket_t *sc,bool preserve_inheritor); // Removes the client from the list + +void dap_events_socket_shrink_buf_in(dap_events_socket_t * cl, size_t shrink_size); + diff --git a/include/dap_memcached.h b/include/dap_memcached.h index 40b87576dcfa52220ad37cda38436779e18ce119..169a1bf2d6126acaff65dc6dcd8599b80c9d2b8f 100755 --- a/include/dap_memcached.h +++ b/include/dap_memcached.h @@ -1,50 +1,50 @@ -#pragma once - - -#include <stdint.h> -#include <stdbool.h> - -#include "dap_common.h" - -/** - * @brief dap_memcached_init - * @param server_host - * @param port - * @return - */ -int dap_memcached_init(const char *server_host, uint16_t port); - -/** - * @brief is_dap_memcache_enable - * @return - */ -bool dap_memcache_is_enable(void); - -/** - * @brief dap_memcached_deinit - */ -void dap_memcached_deinit(void); - -/** - * @brief dap_memcache_put - * @param key - * @param value - * @param value_size - * @param expiration if 0 value is never expire - * @return - */ -bool dap_memcache_put(const char* key, void *value, size_t value_size, time_t expiration); - -/** - * @brief dap_memcache_get - * @param key - * @return true if key found - */ -bool dap_memcache_get(const char* key, size_t * value_size, void ** result); - -/** - * @brief dap_memcache_delete - * @param key - * @return - */ -bool dap_memcache_delete(const char* key); +#pragma once + + +#include <stdint.h> +#include <stdbool.h> + +#include "dap_common.h" + +/** + * @brief dap_memcached_init + * @param server_host + * @param port + * @return + */ +int dap_memcached_init(const char *server_host, uint16_t port); + +/** + * @brief is_dap_memcache_enable + * @return + */ +bool dap_memcache_is_enable(void); + +/** + * @brief dap_memcached_deinit + */ +void dap_memcached_deinit(void); + +/** + * @brief dap_memcache_put + * @param key + * @param value + * @param value_size + * @param expiration if 0 value is never expire + * @return + */ +bool dap_memcache_put(const char* key, void *value, size_t value_size, time_t expiration); + +/** + * @brief dap_memcache_get + * @param key + * @return true if key found + */ +bool dap_memcache_get(const char* key, size_t * value_size, void ** result); + +/** + * @brief dap_memcache_delete + * @param key + * @return + */ +bool dap_memcache_delete(const char* key); diff --git a/include/dap_server.h b/include/dap_server.h index 0aada31337fae99308b3f0010c6e0111a24146f1..eb668b3c4ae520471009a12f6a5177107bf4aca2 100755 --- a/include/dap_server.h +++ b/include/dap_server.h @@ -1,147 +1,146 @@ -/* - Copyright (c) 2017-2018 (c) Project "DeM Labs Inc" https://github.com/demlabsinc - 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 Lesser 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with any DAP based project. If not, see <http://www.gnu.org/licenses/>. -*/ -#pragma once - -#ifndef _WIN32 -#include <netinet/in.h> - -#include <stdint.h> -#include <pthread.h> - -#include <sys/epoll.h> -#include <sys/timerfd.h> -#define EPOLL_HANDLE int -#else -#define EPOLL_HANDLE HANDLE -#endif - -#include "uthash.h" -#include "utlist.h" - -#include "dap_cpu_monitor.h" -#include "dap_client_remote.h" - -typedef enum dap_server_type {DAP_SERVER_TCP} dap_server_type_t; - -#define DAP_BIT( x ) ( 1 << x ) - -#define DAP_SOCK_READY_TO_READ DAP_BIT( 0 ) -#define DAP_SOCK_READY_TO_WRITE DAP_BIT( 1 ) -#define DAP_SOCK_SIGNAL_CLOSE DAP_BIT( 2 ) -#define DAP_SOCK_ACTIVE DAP_BIT( 3 ) - -typedef struct dap_server_thread_s { - - EPOLL_HANDLE epoll_fd; - - uint32_t thread_num; - uint32_t connections_count; - uint32_t to_kill_count; - - struct epoll_event *epoll_events; - dap_client_remote_t *dap_remote_clients; - dap_client_remote_t *dap_clients_to_kill; - - pthread_mutex_t mutex_dlist_add_remove; - -} dap_server_thread_t; - -struct dap_server; - -typedef void (*dap_server_callback_t)( struct dap_server *,void * arg ); // Callback for specific server's operations - -typedef struct dap_server { - - dap_server_type_t type; // Server's type - uint16_t port; // Listen port - char *address; // Listen address - - dap_client_remote_t *clients; // Hashmap of clients - - int32_t socket_listener; // Socket for listener - EPOLL_HANDLE epoll_fd; // Epoll fd - - struct sockaddr_in listener_addr; // Kernel structure for listener's binded address - - void *_inheritor; // Pointer to the internal data, HTTP for example - - pthread_mutex_t mutex_on_hash; - dap_cpu_stats_t cpu_stats; - - dap_server_callback_t server_delete_callback; - - dap_server_client_callback_t client_new_callback; // Create new client callback - dap_server_client_callback_t client_delete_callback; // Delete client callback - dap_server_client_callback_t client_read_callback; // Read function - dap_server_client_callback_t client_write_callback; // Write function - dap_server_client_callback_t client_error_callback; // Error processing function - -} dap_server_t; - -int32_t dap_server_init( uint32_t count_threads ); // Init server module -void dap_server_deinit( void ); // Deinit server module - -dap_server_t *dap_server_listen( const char *addr, uint16_t port, dap_server_type_t type ); - -int32_t dap_server_loop( dap_server_t *d_server ); - -#define DL_LIST_REMOVE_NODE( head, obj, _prev_, _next_, total ) \ - \ - if ( obj->_next_ ) { \ - \ - if ( obj->_prev_ ) \ - obj->_next_->_prev_ = obj->_prev_; \ - else { \ - \ - obj->_next_->_prev_ = NULL; \ - head = obj->_next_; \ - } \ - } \ - \ - if ( obj->_prev_ ) { \ - \ - if ( obj->_next_ ) \ - obj->_prev_->_next_ = obj->_next_; \ - else { \ - \ - obj->_prev_->_next_ = NULL; \ - } \ - } \ - -- total; - -#define DL_LIST_ADD_NODE_HEAD( head, obj, _prev_, _next_, total )\ - \ - if ( !total ) { \ - \ - obj->_prev_ = NULL; \ - obj->_next_ = NULL; \ - \ - head = obj; \ - } \ - else { \ - \ - head->_prev_ = obj; \ - \ - obj->_prev_ = NULL; \ - obj->_next_ = head; \ - \ - head = obj; \ - } \ - ++ total; +/* + Copyright (c) 2017-2018 (c) Project "DeM Labs Inc" https://github.com/demlabsinc + 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 Lesser 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with any DAP based project. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#ifndef _WIN32 +#include <netinet/in.h> + +#include <stdint.h> +#include <pthread.h> + +#include <sys/epoll.h> +#include <sys/timerfd.h> +#define EPOLL_HANDLE int +#else +#define EPOLL_HANDLE HANDLE +#endif + +#include "uthash.h" +#include "utlist.h" + +#include "dap_cpu_monitor.h" +#include "dap_client_remote.h" + +typedef enum dap_server_type {DAP_SERVER_TCP} dap_server_type_t; + +#define BIT( x ) ( 1 << x ) + +#define DAP_SOCK_READY_TO_READ BIT( 0 ) +#define DAP_SOCK_READY_TO_WRITE BIT( 1 ) +#define DAP_SOCK_SIGNAL_CLOSE BIT( 2 ) +#define DAP_SOCK_ACTIVE BIT( 3 ) + +typedef struct dap_server_thread_s { + + EPOLL_HANDLE epoll_fd; + + uint32_t thread_num; + uint32_t connections_count; + uint32_t to_kill_count; + + struct epoll_event *epoll_events; + dap_client_remote_t *dap_remote_clients; + dap_client_remote_t *hclients; // Hashmap of clients + dap_client_remote_t *dap_clients_to_kill; + + pthread_mutex_t mutex_dlist_add_remove; + pthread_mutex_t mutex_on_hash; + +} dap_server_thread_t; + +struct dap_server; + +typedef void (*dap_server_callback_t)( struct dap_server *,void * arg ); // Callback for specific server's operations + +typedef struct dap_server { + + dap_server_type_t type; // Server's type + uint16_t port; // Listen port + char *address; // Listen address + + int32_t socket_listener; // Socket for listener + EPOLL_HANDLE epoll_fd; // Epoll fd + + struct sockaddr_in listener_addr; // Kernel structure for listener's binded address + + void *_inheritor; // Pointer to the internal data, HTTP for example + + dap_cpu_stats_t cpu_stats; + + dap_server_callback_t server_delete_callback; + + dap_server_client_callback_t client_new_callback; // Create new client callback + dap_server_client_callback_t client_delete_callback; // Delete client callback + dap_server_client_callback_t client_read_callback; // Read function + dap_server_client_callback_t client_write_callback; // Write function + dap_server_client_callback_t client_error_callback; // Error processing function + +} dap_server_t; + +int32_t dap_server_init( uint32_t count_threads ); // Init server module +void dap_server_deinit( void ); // Deinit server module + +dap_server_t *dap_server_listen( const char *addr, uint16_t port, dap_server_type_t type ); + +int32_t dap_server_loop( dap_server_t *d_server ); + +#define DL_LIST_REMOVE_NODE( head, obj, _prev_, _next_, total ) \ + \ + if ( obj->_next_ ) { \ + \ + if ( obj->_prev_ ) \ + obj->_next_->_prev_ = obj->_prev_; \ + else { \ + \ + obj->_next_->_prev_ = NULL; \ + head = obj->_next_; \ + } \ + } \ + \ + if ( obj->_prev_ ) { \ + \ + if ( obj->_next_ ) \ + obj->_prev_->_next_ = obj->_next_; \ + else { \ + \ + obj->_prev_->_next_ = NULL; \ + } \ + } \ + -- total; + +#define DL_LIST_ADD_NODE_HEAD( head, obj, _prev_, _next_, total )\ + \ + if ( !total ) { \ + \ + obj->_prev_ = NULL; \ + obj->_next_ = NULL; \ + \ + head = obj; \ + } \ + else { \ + \ + head->_prev_ = obj; \ + \ + obj->_prev_ = NULL; \ + obj->_next_ = head; \ + \ + head = obj; \ + } \ + ++ total; diff --git a/include/dap_traffic_track.h b/include/dap_traffic_track.h index 1cfae9d22689621d0c99a746f96d07a9321543a3..899a77a80c2e457f8bddc3e922e9409820862ae0 100755 --- a/include/dap_traffic_track.h +++ b/include/dap_traffic_track.h @@ -1,50 +1,50 @@ -/* - * Authors: - * Anatoliy Jurotich <anatoliy.kurotich@demlabs.net> - * DeM Labs Inc. https://demlabs.net - * Kelvin Project https://github.com/kelvinblockchain - * Copyright (c) 2017-2018 - * 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/>. -*/ - -#pragma once - -#include "dap_client_remote.h" -#include "dap_server.h" - -typedef void (*dap_traffic_callback_t) (dap_server_t *); - -/** - * @brief dap_traffic_track_init - * @param clients - * @param timeout callback - */ -void dap_traffic_track_init( dap_server_t *server, time_t timeout ); - -/** - * @brief dap_traffic_track_deinit - */ -void dap_traffic_track_deinit( void ); - -/** - * @brief dap_traffic_add_callback - */ -void dap_traffic_callback_set( dap_traffic_callback_t ); - -void dap_traffic_callback_stop( void ); - +/* + * Authors: + * Anatoliy Jurotich <anatoliy.kurotich@demlabs.net> + * DeM Labs Inc. https://demlabs.net + * Kelvin Project https://github.com/kelvinblockchain + * Copyright (c) 2017-2018 + * 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/>. +*/ + +#pragma once + +#include "dap_client_remote.h" +#include "dap_server.h" + +typedef void (*dap_traffic_callback_t) (dap_server_t *); + +/** + * @brief dap_traffic_track_init + * @param clients + * @param timeout callback + */ +void dap_traffic_track_init( dap_server_t *server, time_t timeout ); + +/** + * @brief dap_traffic_track_deinit + */ +void dap_traffic_track_deinit( void ); + +/** + * @brief dap_traffic_add_callback + */ +void dap_traffic_callback_set( dap_traffic_callback_t ); + +void dap_traffic_callback_stop( void ); + diff --git a/src/dap_client_remote.c b/src/dap_client_remote.c index ad163e09a938950d907a69ea9e4b5a3f6fb48fb4..6f60751ff90eee8ff93421a8558268648f8e5733 100755 --- a/src/dap_client_remote.c +++ b/src/dap_client_remote.c @@ -1,345 +1,345 @@ -/* - * Authors: - * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net> - * DeM Labs Inc. https://demlabs.net - * Kelvin Project https://github.com/kelvinblockchain - * Copyright (c) 2017-2018 - * 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 <stdlib.h> -#include <stdio.h> -#include <string.h> - -#ifndef _WIN32 -#include <unistd.h> -#include <arpa/inet.h> -#include <sys/epoll.h> -#include <sys/timerfd.h> -#else -#include <winsock2.h> -#include <windows.h> -#include <mswsock.h> -#include <ws2tcpip.h> -#include <io.h> -#include "wrappers.h" -#include <wepoll.h> -#include <pthread.h> -#endif - -#include "dap_common.h" -#include "dap_server.h" -#include "dap_client_remote.h" - -#define LOG_TAG "dap_client_remote" - -/** - * @brief dap_client_init Init clients module - * @return Zero if ok others if no - */ -int dap_client_remote_init( ) -{ - log_it( L_NOTICE, "Initialized socket client module" ); - - return 0; -} - -/** - * @brief dap_client_deinit Deinit clients module - */ -void dap_client_remote_deinit( ) -{ - - return; -} - -/** - * @brief _save_ip_and_port - * @param cl - */ -void _save_ip_and_port( dap_client_remote_t * cl ) -{ - struct sockaddr_in ip_adr_get; - socklen_t ip_adr_len; - - getpeername( cl->socket, (struct sockaddr * restrict)&ip_adr_get, &ip_adr_len ); - - cl->port = ntohs( ip_adr_get.sin_port ); - strcpy( cl->s_ip, inet_ntoa(ip_adr_get.sin_addr) ); -} - -/** - * @brief dap_client_remote_create Create new client and add it to the list - * @param sh Server instance - * @param s Client's socket - * @return Pointer to the new list's node - */ -dap_client_remote_t *dap_client_remote_create( dap_server_t *sh, int s, dap_server_thread_t *dsth ) -{ - dap_client_remote_t *dsc = DAP_NEW_Z( dap_client_remote_t ); - - dap_random_string_fill( dsc->id, CLIENT_ID_SIZE ); - - dsc->socket = s; - dsc->server = sh; - dsc->tn = dsth->thread_num; - dsc->efd = dsth->epoll_fd; - dsc->time_connection = dsc->last_time_active = time( NULL) ; - - dsc->pevent.events = EPOLLIN | EPOLLOUT | EPOLLERR; - dsc->pevent.data.ptr = dsc; - - dsc->flags = DAP_SOCK_READY_TO_READ; - dsc->buf_out_offset = 0; - - _save_ip_and_port( dsc ); - - pthread_mutex_lock( &sh->mutex_on_hash ); - HASH_ADD_INT( sh->clients, socket, dsc ); - pthread_mutex_unlock( &sh->mutex_on_hash ); - - if ( sh->client_new_callback ) - sh->client_new_callback( dsc, NULL ); // Init internal structure - - log_it(L_DEBUG, "Create remote client: ip: %s port %d", dsc->s_ip, dsc->port ); - - //log_it(L_DEBUG, "Create new client. ID: %s", dsc->id); - return dsc; -} - -/** - * @brief safe_client_remove Removes the client from the list - * @param sc Client instance - */ -void dap_client_remote_remove( dap_client_remote_t *sc, struct dap_server * sh ) -{ - log_it(L_DEBUG, "dap_client_remote_remove [THREAD %u] efd %u", sc->tn , sc->efd ); - -// EPOLL_HANDLE efd; // Epoll fd -// int tn; // working thread index - - pthread_mutex_lock( &sh->mutex_on_hash ); - HASH_DEL( sc->server->clients, sc ); - pthread_mutex_unlock( &sh->mutex_on_hash ); - - if( sc->server->client_delete_callback ) - sc->server->client_delete_callback( sc, NULL ); // Init internal structure - - if( sc->_inheritor ) - free( sc->_inheritor ); - - if( sc->socket ) - close( sc->socket ); - - free( sc ); -} - -/** - * @brief dap_server_client_find - * @param sock - * @param sh - * @return - */ -dap_client_remote_t *dap_client_remote_find( int sock, struct dap_server *sh ) -{ - dap_client_remote_t *ret = NULL; - - pthread_mutex_lock( &sh->mutex_on_hash ); - HASH_FIND_INT( sh->clients, &sock, ret ); - pthread_mutex_unlock( &sh->mutex_on_hash ); - - return ret; -} - -/** - * @brief dap_client_remote_ready_to_read - * @param sc - * @param isReady - */ -void dap_client_remote_ready_to_read( dap_client_remote_t *sc, bool is_ready ) -{ - if( is_ready == (bool)(sc->flags & DAP_SOCK_READY_TO_READ) ) - return; - -// log_it( L_ERROR, "remote_ready_to_read() %u efd %X", sc->socket, sc->efd ); - - if ( is_ready ) - sc->flags |= DAP_SOCK_READY_TO_READ; - else - sc->flags ^= DAP_SOCK_READY_TO_READ; - - int events = EPOLLERR; - - if( sc->flags & DAP_SOCK_READY_TO_READ ) - events |= EPOLLIN; - - if( sc->flags & DAP_SOCK_READY_TO_WRITE ) - events |= EPOLLOUT; - - sc->pevent.events = events; - - if( epoll_ctl(sc->efd, EPOLL_CTL_MOD, sc->socket, &sc->pevent) != 0 ) - log_it( L_ERROR, "epoll_ctl failed 000" ); -} - -/** - * @brief dap_client_remote_ready_to_write - * @param sc - * @param isReady - */ -void dap_client_remote_ready_to_write( dap_client_remote_t *sc, bool is_ready ) -{ - if ( is_ready == (bool)(sc->flags & DAP_SOCK_READY_TO_WRITE) ) - return; - -// log_it( L_ERROR, "remote_ready_to_write() %u efd %X", sc->socket, sc->efd ); - - if ( is_ready ) - sc->flags |= DAP_SOCK_READY_TO_WRITE; - else - sc->flags ^= DAP_SOCK_READY_TO_WRITE; - - int events = EPOLLERR; - - if( sc->flags & DAP_SOCK_READY_TO_READ ) - events |= EPOLLIN; - - if( sc->flags & DAP_SOCK_READY_TO_WRITE ) - events |= EPOLLOUT; - - sc->pevent.events = events; - - if( epoll_ctl(sc->efd, EPOLL_CTL_MOD, sc->socket, &sc->pevent) != 0 ) - log_it( L_ERROR, "epoll_ctl failed 001" ); -} - -/** - * @brief dap_client_write Write data to the client - * @param sc Client instance - * @param data Pointer to data - * @param data_size Size of data to write - * @return Number of bytes that were placed into the buffer - */ -size_t dap_client_remote_write( dap_client_remote_t *sc, const void * data, size_t data_size ) -{ - if ( sc->buf_out_size + data_size > sizeof(sc->buf_out) ) { - log_it( L_WARNING, "Client buffer overflow. Packet loosed" ); - return 0; - } - - memcpy( sc->buf_out + sc->buf_out_size, data, data_size ); - sc->buf_out_size += data_size; - return data_size; -} - -/** - * @brief dap_client_write_f Write formatted text to the client - * @param a_client Client instance - * @param a_format Format - * @return Number of bytes that were placed into the buffer - */ -size_t dap_client_remote_write_f( dap_client_remote_t *a_client, const char * a_format, ... ) -{ - size_t max_data_size = sizeof( a_client->buf_out ) - a_client->buf_out_size; - - va_list ap; - va_start( ap, a_format ); - - int ret = vsnprintf( a_client->buf_out + a_client->buf_out_size, max_data_size, a_format, ap ); - - va_end( ap ); - - if( ret > 0 ) { - a_client->buf_out_size += (unsigned long)ret; - return (size_t)ret; - } - else { - log_it( L_ERROR, "Can't write out formatted data '%s'", a_format ); - return 0; - } -} - -/** - * @brief dap_client_read Read data from input buffer - * @param a_client Client instasnce - * @param a_data Pointer to memory where to store the data - * @param a_data_size Size of data to read - * @return Actual bytes number that were read - */ -size_t dap_client_remote_read( dap_client_remote_t *a_client, void *a_data, size_t a_data_size ) -{ - if ( a_data_size < a_client->buf_in_size ) { - - memcpy( a_data, a_client->buf_in, a_data_size ); - memmove( a_client->buf_in, a_client->buf_in + a_data_size, a_client->buf_in_size - a_data_size ); - } - else { - if ( a_data_size > a_client->buf_in_size ) { - a_data_size = a_client->buf_in_size; - } - memcpy( a_data, a_client->buf_in, a_data_size ); - } - - a_client->buf_in_size -= a_data_size; - - return a_data_size; -} - - -/** - * @brief dap_client_remote_shrink_client_buf_in Shrink input buffer (shift it left) - * @param a_client Client instance - * @param a_shrink_size Size on wich we shrink the buffer with shifting it left - */ -void dap_client_remote_shrink_buf_in( dap_client_remote_t *a_client, size_t a_shrink_size ) -{ -#if 0 - if((a_shrink_size==0)||(a_client->buf_in_size==0) ){ - return; - }else if(a_client->buf_in_size>a_shrink_size){ - size_t buf_size=a_client->buf_in_size-a_shrink_size; - void * buf = malloc(buf_size); - memcpy(buf,a_client->buf_in+ a_shrink_size,buf_size ); - memcpy(a_client->buf_in,buf,buf_size); - a_client->buf_in_size=buf_size; - free(buf); - }else { - a_client->buf_in_size=0; - } -#endif - - if ( a_shrink_size == 0 || a_client->buf_in_size == 0 ) - return; - - if ( a_client->buf_in_size > a_shrink_size ) { - - size_t buf_size = a_client->buf_in_size - a_shrink_size; - memmove( a_client->buf_in, a_client->buf_in + a_shrink_size, buf_size ); -/** - void *buf = malloc( buf_size ); - memcpy( buf, a_client->buf_in + a_shrink_size, buf_size ); - memcpy( a_client->buf_in, buf, buf_size ); - // holy shit - a_client->buf_in_size = buf_size; - free( buf ); -**/ - a_client->buf_in_size = buf_size; - } - else { - a_client->buf_in_size = 0; - } -} +/* + * Authors: + * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net> + * DeM Labs Inc. https://demlabs.net + * Kelvin Project https://github.com/kelvinblockchain + * Copyright (c) 2017-2018 + * 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 <stdlib.h> +#include <stdio.h> +#include <string.h> + +#ifndef _WIN32 +#include <unistd.h> +#include <arpa/inet.h> +#include <sys/epoll.h> +#include <sys/timerfd.h> +#else +#include <winsock2.h> +#include <windows.h> +#include <mswsock.h> +#include <ws2tcpip.h> +#include <io.h> +#include "wrappers.h" +#include <wepoll.h> +#include <pthread.h> +#endif + +#include "dap_common.h" +#include "dap_server.h" +#include "dap_client_remote.h" + +#define LOG_TAG "dap_client_remote" + +/** + * @brief dap_client_init Init clients module + * @return Zero if ok others if no + */ +int dap_client_remote_init( ) +{ + log_it( L_NOTICE, "Initialized socket client module" ); + + return 0; +} + +/** + * @brief dap_client_deinit Deinit clients module + */ +void dap_client_remote_deinit( ) +{ + + return; +} + +/** + * @brief _save_ip_and_port + * @param cl + */ +void _save_ip_and_port( dap_client_remote_t * cl ) +{ + struct sockaddr_in ip_adr_get; + socklen_t ip_adr_len; + + getpeername( cl->socket, (struct sockaddr * restrict)&ip_adr_get, &ip_adr_len ); + + cl->port = ntohs( ip_adr_get.sin_port ); + strcpy( cl->s_ip, inet_ntoa(ip_adr_get.sin_addr) ); +} + +/** + * @brief dap_client_remote_create Create new client and add it to the list + * @param sh Server instance + * @param s Client's socket + * @return Pointer to the new list's node + */ +dap_client_remote_t *dap_client_remote_create( dap_server_t *sh, int s, dap_server_thread_t *t ) +{ + dap_client_remote_t *dsc = DAP_NEW_Z( dap_client_remote_t ); + + dap_random_string_fill( dsc->id, CLIENT_ID_SIZE ); + + dsc->socket = s; + dsc->server = sh; + dsc->tn = t->thread_num; + dsc->thread = t; + dsc->efd = t->epoll_fd; + dsc->time_connection = dsc->last_time_active = time( NULL) ; + + dsc->pevent.events = EPOLLIN | EPOLLOUT | EPOLLERR; + dsc->pevent.data.ptr = dsc; + + dsc->flags = DAP_SOCK_READY_TO_READ; + dsc->buf_out_offset = 0; + + _save_ip_and_port( dsc ); + + pthread_mutex_lock( &t->mutex_on_hash ); + HASH_ADD_INT( t->hclients, socket, dsc ); + pthread_mutex_unlock( &t->mutex_on_hash ); + + if ( sh->client_new_callback ) + sh->client_new_callback( dsc, NULL ); // Init internal structure + + log_it(L_DEBUG, "Create remote client: ip: %s port %d", dsc->s_ip, dsc->port ); + + //log_it(L_DEBUG, "Create new client. ID: %s", dsc->id); + return dsc; +} + +/** + * @brief safe_client_remove Removes the client from the list + * @param sc Client instance + */ +void dap_client_remote_remove( dap_client_remote_t *sc ) +{ + log_it(L_DEBUG, "dap_client_remote_remove [THREAD %u] efd %u", sc->tn , sc->efd ); + + dap_server_thread_t *t = sc->thread; + + pthread_mutex_lock( &t->mutex_on_hash ); + HASH_DEL( t->hclients, sc ); + pthread_mutex_unlock( &t->mutex_on_hash ); + + if( sc->server->client_delete_callback ) + sc->server->client_delete_callback( sc, NULL ); // Init internal structure + + if( sc->_inheritor ) + free( sc->_inheritor ); + + if( sc->socket ) + close( sc->socket ); + + free( sc ); +} + +/** + * @brief dap_server_client_find + * @param sock + * @param sh + * @return + */ +dap_client_remote_t *dap_client_remote_find( int sock, dap_server_thread_t *t ) +{ + dap_client_remote_t *ret = NULL; + + pthread_mutex_lock( &t->mutex_on_hash ); + HASH_FIND_INT( t->hclients, &sock, ret ); + pthread_mutex_unlock( &t->mutex_on_hash ); + + return ret; +} + +/** + * @brief dap_client_remote_ready_to_read + * @param sc + * @param isReady + */ +void dap_client_remote_ready_to_read( dap_client_remote_t *sc, bool is_ready ) +{ + if( is_ready == (bool)(sc->flags & DAP_SOCK_READY_TO_READ) ) + return; + +// log_it( L_ERROR, "remote_ready_to_read() %u efd %X", sc->socket, sc->efd ); + + if ( is_ready ) + sc->flags |= DAP_SOCK_READY_TO_READ; + else + sc->flags ^= DAP_SOCK_READY_TO_READ; + + int events = EPOLLERR; + + if( sc->flags & DAP_SOCK_READY_TO_READ ) + events |= EPOLLIN; + + if( sc->flags & DAP_SOCK_READY_TO_WRITE ) + events |= EPOLLOUT; + + sc->pevent.events = events; + + if( epoll_ctl(sc->efd, EPOLL_CTL_MOD, sc->socket, &sc->pevent) != 0 ) + log_it( L_ERROR, "epoll_ctl failed 000" ); +} + +/** + * @brief dap_client_remote_ready_to_write + * @param sc + * @param isReady + */ +void dap_client_remote_ready_to_write( dap_client_remote_t *sc, bool is_ready ) +{ + if ( is_ready == (bool)(sc->flags & DAP_SOCK_READY_TO_WRITE) ) + return; + +// log_it( L_ERROR, "remote_ready_to_write() %u efd %X", sc->socket, sc->efd ); + + if ( is_ready ) + sc->flags |= DAP_SOCK_READY_TO_WRITE; + else + sc->flags ^= DAP_SOCK_READY_TO_WRITE; + + int events = EPOLLERR; + + if( sc->flags & DAP_SOCK_READY_TO_READ ) + events |= EPOLLIN; + + if( sc->flags & DAP_SOCK_READY_TO_WRITE ) + events |= EPOLLOUT; + + sc->pevent.events = events; + + if( epoll_ctl(sc->efd, EPOLL_CTL_MOD, sc->socket, &sc->pevent) != 0 ) + log_it( L_ERROR, "epoll_ctl failed 001" ); +} + +/** + * @brief dap_client_write Write data to the client + * @param sc Client instance + * @param data Pointer to data + * @param data_size Size of data to write + * @return Number of bytes that were placed into the buffer + */ +size_t dap_client_remote_write( dap_client_remote_t *sc, const void * data, size_t data_size ) +{ + if ( sc->buf_out_size + data_size > sizeof(sc->buf_out) ) { + log_it( L_WARNING, "Client buffer overflow. Packet loosed" ); + return 0; + } + + memcpy( sc->buf_out + sc->buf_out_size, data, data_size ); + sc->buf_out_size += data_size; + return data_size; +} + +/** + * @brief dap_client_write_f Write formatted text to the client + * @param a_client Client instance + * @param a_format Format + * @return Number of bytes that were placed into the buffer + */ +size_t dap_client_remote_write_f( dap_client_remote_t *a_client, const char * a_format, ... ) +{ + size_t max_data_size = sizeof( a_client->buf_out ) - a_client->buf_out_size; + + va_list ap; + va_start( ap, a_format ); + + int ret = vsnprintf( a_client->buf_out + a_client->buf_out_size, max_data_size, a_format, ap ); + + va_end( ap ); + + if( ret > 0 ) { + a_client->buf_out_size += (unsigned long)ret; + return (size_t)ret; + } + else { + log_it( L_ERROR, "Can't write out formatted data '%s'", a_format ); + return 0; + } +} + +/** + * @brief dap_client_read Read data from input buffer + * @param a_client Client instasnce + * @param a_data Pointer to memory where to store the data + * @param a_data_size Size of data to read + * @return Actual bytes number that were read + */ +size_t dap_client_remote_read( dap_client_remote_t *a_client, void *a_data, size_t a_data_size ) +{ + if ( a_data_size < a_client->buf_in_size ) { + + memcpy( a_data, a_client->buf_in, a_data_size ); + memmove( a_client->buf_in, a_client->buf_in + a_data_size, a_client->buf_in_size - a_data_size ); + } + else { + if ( a_data_size > a_client->buf_in_size ) { + a_data_size = a_client->buf_in_size; + } + memcpy( a_data, a_client->buf_in, a_data_size ); + } + + a_client->buf_in_size -= a_data_size; + + return a_data_size; +} + + +/** + * @brief dap_client_remote_shrink_client_buf_in Shrink input buffer (shift it left) + * @param a_client Client instance + * @param a_shrink_size Size on wich we shrink the buffer with shifting it left + */ +void dap_client_remote_shrink_buf_in( dap_client_remote_t *a_client, size_t a_shrink_size ) +{ +#if 0 + if((a_shrink_size==0)||(a_client->buf_in_size==0) ){ + return; + }else if(a_client->buf_in_size>a_shrink_size){ + size_t buf_size=a_client->buf_in_size-a_shrink_size; + void * buf = malloc(buf_size); + memcpy(buf,a_client->buf_in+ a_shrink_size,buf_size ); + memcpy(a_client->buf_in,buf,buf_size); + a_client->buf_in_size=buf_size; + free(buf); + }else { + a_client->buf_in_size=0; + } +#endif + + if ( a_shrink_size == 0 || a_client->buf_in_size == 0 ) + return; + + if ( a_client->buf_in_size > a_shrink_size ) { + + size_t buf_size = a_client->buf_in_size - a_shrink_size; + memmove( a_client->buf_in, a_client->buf_in + a_shrink_size, buf_size ); +/** + void *buf = malloc( buf_size ); + memcpy( buf, a_client->buf_in + a_shrink_size, buf_size ); + memcpy( a_client->buf_in, buf, buf_size ); + // holy shit + a_client->buf_in_size = buf_size; + free( buf ); +**/ + a_client->buf_in_size = buf_size; + } + else { + a_client->buf_in_size = 0; + } +} diff --git a/src/dap_events.c b/src/dap_events.c index 5c6e730ce78c5017b2699cc612a6cb180442a0f7..36d981f503a1434d2555a9c2de1fee2b37653fde 100755 --- a/src/dap_events.c +++ b/src/dap_events.c @@ -1,596 +1,600 @@ -/* - * Authors: - * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net> - * DeM Labs Inc. https://demlabs.net - * Kelvin Project https://github.com/kelvinblockchain - * Copyright (c) 2017-2019 - * 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/>. -*/ -#define __USE_GNU - -#include <string.h> -#include <time.h> -#include <stdio.h> -#include <stdio.h> -#include <stdlib.h> -#include <stddef.h> -#include <stdint.h> - -#ifndef _WIN32 -#include <arpa/inet.h> -#include <netinet/in.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <sys/stat.h> - -#include <sys/epoll.h> - -#include <netdb.h> -#include <unistd.h> -#include <fcntl.h> -#include <errno.h> -#include <signal.h> - -#if 1 -#include <sys/timerfd.h> -#elif defined(DAP_OS_ANDROID) -#define NO_POSIX_SHED -#define NO_TIMER -#endif - -#else - -#undef _WIN32_WINNT -#define _WIN32_WINNT 0x0600 -#include <winsock2.h> -#include <windows.h> -#include <mswsock.h> -#include <ws2tcpip.h> -#include <io.h> -#include "wrappers.h" -#include <wepoll.h> -#include <pthread.h> - -//#define NO_TIMER - -#endif - -#include <utlist.h> -#include <sched.h> - -#include "dap_common.h" -#include "dap_events.h" - -#define DAP_MAX_EPOLL_EVENTS 8192 - -//typedef struct open_connection_info_s { -// dap_events_socket_t *es; -// struct open_connection_info *prev; -// struct open_connection_info *next; -//} dap_events_socket_info_t; - -//dap_events_socket_info_t **s_dap_events_sockets; - -static uint32_t s_threads_count = 1; -static size_t s_connection_timeout = 600; -static struct epoll_event *g_epoll_events = NULL; - -dap_worker_t *s_workers = NULL; -dap_thread_t *s_threads = NULL; - -#define LOG_TAG "dap_events" - -uint32_t s_get_cpu_count( ) -{ -#ifdef _WIN32 - SYSTEM_INFO si; - - GetSystemInfo( &si ); - return si.dwNumberOfProcessors; -#else -#ifndef NO_POSIX_SHED - cpu_set_t cs; - CPU_ZERO( &cs ); - sched_getaffinity( 0, sizeof(cs), &cs ); - - uint32_t count = 0; - for ( int i = 0; i < 32; i++ ){ - if ( CPU_ISSET(i, &cs) ) - count ++; - } - return count; -#else - return 1; -#endif -#endif -} - -/** - * @brief sa_server_init Init server module - * @arg a_threads_count number of events processor workers in parallel threads - * @return Zero if ok others if no - */ -int32_t dap_events_init( uint32_t a_threads_count, size_t conn_timeout ) -{ - s_threads_count = a_threads_count ? a_threads_count : s_get_cpu_count( ); - - if ( conn_timeout ) - s_connection_timeout = conn_timeout; - - s_workers = (dap_worker_t *) calloc( 1, sizeof(dap_worker_t) * s_threads_count ); - s_threads = (dap_thread_t *) calloc( 1, sizeof(dap_thread_t) * s_threads_count ); - if ( !s_workers || !s_threads ) - goto err; - - g_epoll_events = (struct epoll_event *)malloc( sizeof(struct epoll_event) * DAP_MAX_EPOLL_EVENTS * s_threads_count ); - if ( !g_epoll_events ) - goto err; - - if ( dap_events_socket_init() != 0 ) { - - log_it( L_CRITICAL, "Can't init client submodule dap_events_socket_init( )" ); - goto err; - } - - log_it( L_NOTICE, "Initialized socket server module" ); - - #ifndef _WIN32 - signal( SIGPIPE, SIG_IGN ); - #endif - return 0; - -err: - dap_events_deinit( ); - return -1; -} - -/** - * @brief sa_server_deinit Deinit server module - */ -void dap_events_deinit( ) -{ - dap_events_socket_deinit( ); - - if ( g_epoll_events ) - free( g_epoll_events ); - - if ( s_threads ) - free( s_threads ); - - if ( s_workers ) - free( s_workers ); -} - -/** - * @brief server_new Creates new empty instance of server_t - * @return New instance - */ -dap_events_t * dap_events_new( ) -{ - dap_events_t *ret = (dap_events_t *)calloc( 1, sizeof(dap_events_t) ); - - pthread_rwlock_init( &ret->sockets_rwlock, NULL ); - pthread_rwlock_init( &ret->servers_rwlock, NULL ); - - return ret; -} - -/** - * @brief server_delete Delete event processor instance - * @param sh Pointer to the server instance - */ -void dap_events_delete( dap_events_t *a_events ) -{ - dap_events_socket_t *cur, *tmp; - - if ( a_events ) { - - HASH_ITER( hh, a_events->sockets,cur, tmp ) { - dap_events_socket_delete( cur, false ); - } - - if ( a_events->_inheritor ) - free( a_events->_inheritor ); - - pthread_rwlock_destroy( &a_events->servers_rwlock ); - pthread_rwlock_destroy( &a_events->sockets_rwlock ); - - free( a_events ); - } -} - -void dap_events_kill_socket( dap_events_socket_t *a_es ) -{ - if ( !a_es ) { - log_it( L_ERROR, "dap_events_kill_socket( NULL )" ); - return; - } - - uint32_t tn = a_es->dap_worker->number_thread; - - dap_worker_t *w = a_es->dap_worker; - dap_events_t *d_ev = w->events; - - pthread_mutex_lock( &w->locker_on_count ); - if ( a_es->kill_signal ) { - pthread_mutex_unlock( &w->locker_on_count ); - return; - } - - log_it( L_DEBUG, "KILL %u socket! [ thread %u ]", a_es->socket, tn ); - - a_es->kill_signal = true; - DL_LIST_ADD_NODE_HEAD( d_ev->to_kill_sockets, a_es, kprev, knext, w->event_to_kill_count ); - - pthread_mutex_unlock( &w->locker_on_count ); -} - - -/** - * @brief s_socket_info_all_check_activity - * @param n_thread - * @param sh - */ -static void s_socket_all_check_activity( dap_worker_t *dap_worker, dap_events_t *d_ev, time_t cur_time ) -{ - dap_events_socket_t *a_es, *tmp; - - pthread_mutex_lock( &dap_worker->locker_on_count ); - DL_FOREACH_SAFE( d_ev->dlsockets, a_es, tmp ) { - - if ( !a_es->kill_signal && cur_time >= a_es->last_time_active + s_connection_timeout && !a_es->close_denied ) { - - log_it( L_INFO, "Socket %u timeout, closing...", a_es->socket ); - - if ( epoll_ctl( dap_worker->epoll_fd, EPOLL_CTL_DEL, a_es->socket, &a_es->ev) == -1 ) - log_it( L_ERROR,"Can't remove event socket's handler from the epoll_fd" ); - else - log_it( L_DEBUG,"Removed epoll's event from dap_worker #%u", dap_worker->number_thread ); - - dap_worker->event_sockets_count --; - DL_DELETE( d_ev->dlsockets, a_es ); - dap_events_socket_delete( a_es, false ); - } - } - pthread_mutex_unlock( &dap_worker->locker_on_count ); - -} - -/** - * @brief thread_worker_function - * @param arg - * @return - */ -static void *thread_worker_function( void *arg ) -{ - dap_events_socket_t *cur, *tmp; - dap_worker_t *w = (dap_worker_t *)arg; - time_t next_time_timeout_check = time( NULL ) + s_connection_timeout / 2; - uint32_t tn = w->number_thread; - - #ifndef _WIN32 - #ifndef NO_POSIX_SHED - cpu_set_t mask; - CPU_ZERO( &mask ); - CPU_SET( tn, &mask ); - - if ( pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &mask) != 0 ) - { - log_it(L_CRITICAL, "Error pthread_setaffinity_np() You really have %d or more core in CPU?", *(int*)arg); - abort(); - } - #endif - #else - - if ( !SetThreadAffinityMask( GetCurrentThread(), (DWORD_PTR)(1 << tn) ) ) { - log_it( L_CRITICAL, "Error pthread_setaffinity_np() You really have %d or more core in CPU?", tn ); - abort(); - } - #endif - - log_it(L_INFO, "Worker %d started, epoll fd %d", w->number_thread, w->epoll_fd); - - struct epoll_event *events = &g_epoll_events[ DAP_MAX_EPOLL_EVENTS * tn ]; - -// memset( &ev, 0, sizeof(ev) ); -// memset( &events, 0, sizeof(events) ); - - size_t total_sent; int bytes_sent; - - while( 1 ) { - - int selected_sockets = epoll_wait( w->epoll_fd, events, DAP_MAX_EPOLL_EVENTS, 1000 ); - if ( selected_sockets == -1 ) - break; - - time_t cur_time = time( NULL ); - - for( int32_t n = 0; n < selected_sockets; n ++ ) { - - cur = (dap_events_socket_t *)events[n].data.ptr; - - if ( !cur ) { - - log_it( L_ERROR,"dap_events_socket NULL" ); - continue; - } - - if ( events[n].events & EPOLLERR ) { - log_it( L_ERROR,"Socket error: %s",strerror(errno) ); - cur->flags |= DAP_SOCK_SIGNAL_CLOSE; - cur->callbacks->error_callback( cur, NULL ); // Call callback to process error event - } - - cur->last_time_active = cur_time; - - if( events[n].events & EPOLLIN ) { - - //log_it(DEBUG,"Comes connection in active read set"); - if( cur->buf_in_size == sizeof(cur->buf_in) ) { - log_it( L_WARNING, "Buffer is full when there is smth to read. Its dropped!" ); - cur->buf_in_size = 0; - } - - int32_t bytes_read = recv( cur->socket, (char *)(cur->buf_in + cur->buf_in_size), - sizeof(cur->buf_in) - cur->buf_in_size, 0 ); - if( bytes_read > 0 ) { - cur->buf_in_size += bytes_read; - //log_it(DEBUG, "Received %d bytes", bytes_read); - cur->callbacks->read_callback( cur, NULL ); // Call callback to process read event. At the end of callback buf_in_size should be zero if everything was read well - } - else if( bytes_read < 0 ) { - log_it( L_ERROR,"Some error occured in recv() function: %s",strerror(errno) ); - dap_events_socket_set_readable( cur, false ); - cur->flags |= DAP_SOCK_SIGNAL_CLOSE; - } - else if ( bytes_read == 0 ) { - log_it( L_INFO, "Client socket disconnected" ); - dap_events_socket_set_readable( cur, false ); - cur->flags |= DAP_SOCK_SIGNAL_CLOSE; - } - } - - // Socket is ready to write - if( ( (events[n].events & EPOLLOUT) || (cur->flags & DAP_SOCK_READY_TO_WRITE) ) && !(cur->flags & DAP_SOCK_SIGNAL_CLOSE) ) { - ///log_it(DEBUG, "Main loop output: %u bytes to send",sa_cur->buf_out_size); - cur->callbacks->write_callback( cur, NULL ); // Call callback to process write event - - if( cur->flags & DAP_SOCK_READY_TO_WRITE ) { - - static const uint32_t buf_out_zero_count_max = 20; - cur->buf_out[cur->buf_out_size] = 0; - - if( !cur->buf_out_size ) { - - log_it(L_WARNING, "Output: nothing to send. Why we are in write socket set?"); - cur->buf_out_zero_count ++; - - if( cur->buf_out_zero_count > buf_out_zero_count_max ) { // How many time buf_out on write event could be empty - log_it( L_ERROR, "Output: nothing to send %u times, remove socket from the write set", buf_out_zero_count_max ); - dap_events_socket_set_writable( cur, false ); - } - } - else - cur->buf_out_zero_count = 0; - } - for ( total_sent = 0; total_sent < cur->buf_out_size; ) { // If after callback there is smth to send - we do it - - bytes_sent = send( cur->socket, (char *)(cur->buf_out + total_sent), - cur->buf_out_size - total_sent, MSG_DONTWAIT | MSG_NOSIGNAL ); - - if ( bytes_sent < 0 ) { - log_it(L_ERROR,"Some error occured in send() function"); - cur->flags |= DAP_SOCK_SIGNAL_CLOSE; - break; - } - total_sent += bytes_sent; - //log_it(L_DEBUG, "Output: %u from %u bytes are sent ", total_sent,sa_cur->buf_out_size); - } - //log_it(L_DEBUG,"Output: sent %u bytes",total_sent); - cur->buf_out_size = 0; - } - - if ( (cur->flags & DAP_SOCK_SIGNAL_CLOSE) && !cur->close_denied ) { - - pthread_mutex_lock( &w->locker_on_count ); - - if ( cur->kill_signal ) { - pthread_mutex_unlock( &w->locker_on_count ); - continue; - } - -// pthread_mutex_unlock( &dsth->mutex_dlist_add_remove ); -// dap_server_kill_socket( dap_cur ); -// continue; - - log_it( L_INFO, "Got signal to close %s, sock %u [thread %u]", cur->hostaddr, cur->socket, tn ); - - dap_events_socket_remove_and_delete( cur, false ); - pthread_mutex_unlock( &w->locker_on_count ); - } - } // for - - #ifndef NO_TIMER - if ( cur_time >= next_time_timeout_check ) { - - s_socket_all_check_activity( w, w->events, cur_time ); - next_time_timeout_check = cur_time + s_connection_timeout / 2; - } - #endif - - pthread_mutex_lock( &w->locker_on_count ); - if ( !w->event_to_kill_count ) { - - pthread_mutex_unlock( &w->locker_on_count ); - continue; - } - - cur = w->events->to_kill_sockets; - - do { - -// if ( cur->close_denied ) { -// cur = cur->knext; -// continue; -// } - - log_it( L_INFO, "Kill %u socket .... [ thread %u ]", cur->socket, tn ); - - tmp = cur->knext; - DL_LIST_REMOVE_NODE( w->events->to_kill_sockets, cur, kprev, knext, w->event_to_kill_count ); - - dap_events_socket_remove_and_delete( cur, false ); - cur = tmp; - - } while ( cur ); - - log_it( L_INFO, "[ Thread %u ] coneections: %u, to kill: %u", tn, w->event_sockets_count, w->event_to_kill_count ); - pthread_mutex_unlock( &w->locker_on_count ); - - } // while - - return NULL; -} - -/** - * @brief dap_worker_get_min - * @return - */ -dap_worker_t *dap_worker_get_min( ) -{ - return &s_workers[dap_worker_get_index_min()]; -} - -/** - * @brief dap_worker_get_index_min - * @return - */ -uint32_t dap_worker_get_index_min( ) -{ - uint32_t min = 0; - uint32_t i; - - for( i = 1; i < s_threads_count; i++ ) { - - if ( s_workers[min].event_sockets_count > s_workers[i].event_sockets_count ) - min = i; - } - - return min; -} - -/** - * @brief dap_worker_print_all - */ -void dap_worker_print_all( ) -{ - uint32_t i; - - for( i = 0; i < s_threads_count; i ++ ) { - - log_it( L_INFO, "Worker: %d, count open connections: %d", - s_workers[i].number_thread, s_workers[i].event_sockets_count ); - } -} - -/** - * @brief sa_server_loop Main server loop - * @param sh Server instance - * @return Zero if ok others if not - */ -int dap_events_start( dap_events_t *a_events ) -{ - for( uint32_t i = 0; i < s_threads_count; i++) { - - s_workers[i].epoll_fd = epoll_create( DAP_MAX_EPOLL_EVENTS ); - if ( (intptr_t)s_workers[i].epoll_fd == -1 ) { - log_it(L_CRITICAL, "Error create epoll fd"); - return -1; - } - - s_workers[i].event_to_kill_count = 0; - s_workers[i].event_sockets_count = 0; - s_workers[i].number_thread = i; - s_workers[i].events = a_events; - - pthread_mutex_init( &s_workers[i].locker_on_count, NULL ); - pthread_create( &s_threads[i].tid, NULL, thread_worker_function, &s_workers[i] ); - } - - return 0; -} - -/** - * @brief dap_events_wait - * @param sh - * @return - */ -int dap_events_wait( dap_events_t *sh ) -{ - (void) sh; - - for( uint32_t i = 0; i < s_threads_count; i ++ ) { - void *ret; - pthread_join( s_threads[i].tid, &ret ); - } - - return 0; -} - - - -/** - * @brief dap_worker_add_events_socket - * @param a_worker - * @param a_events_socket - */ -void dap_worker_add_events_socket( dap_events_socket_t *a_es) -{ -// struct epoll_event ev = {0}; - dap_worker_t *l_worker = dap_worker_get_min( ); - - a_es->dap_worker = l_worker; - a_es->events = a_es->dap_worker->events; -} - -/** - * @brief dap_events_socket_delete - * @param a_es - */ -void dap_events_socket_remove_and_delete( dap_events_socket_t *a_es, bool preserve_inheritor ) -{ - if ( epoll_ctl( a_es->dap_worker->epoll_fd, EPOLL_CTL_DEL, a_es->socket, &a_es->ev) == -1 ) - log_it( L_ERROR,"Can't remove event socket's handler from the epoll_fd" ); - else - log_it( L_DEBUG,"Removed epoll's event from dap_worker #%u", a_es->dap_worker->number_thread ); - - DL_DELETE( a_es->events->dlsockets, a_es ); - a_es->dap_worker->event_sockets_count --; - - dap_events_socket_delete( a_es, preserve_inheritor ); -} - -/** - * @brief dap_events__thread_wake_up - * @param th - */ -void dap_events_thread_wake_up( dap_thread_t *th ) -{ - (void) th; - //pthread_kill(th->tid,SIGUSR1); -} +/* + * Authors: + * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net> + * DeM Labs Inc. https://demlabs.net + * Kelvin Project https://github.com/kelvinblockchain + * Copyright (c) 2017-2019 + * 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/>. +*/ +#define __USE_GNU + +#include <string.h> +#include <time.h> +#include <stdio.h> +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <stdint.h> + +#ifndef _WIN32 +#include <arpa/inet.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <sys/epoll.h> + +#include <netdb.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <signal.h> + +#if 1 +#include <sys/timerfd.h> +#elif defined(DAP_OS_ANDROID) +#define NO_POSIX_SHED +#define NO_TIMER +#endif + +#else + +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0600 +#include <winsock2.h> +#include <windows.h> +#include <mswsock.h> +#include <ws2tcpip.h> +#include <io.h> +#include "wrappers.h" +#include <wepoll.h> +#include <pthread.h> + +//#define NO_TIMER + +#endif + +#include <utlist.h> +#include <sched.h> + +#include "dap_common.h" +#include "dap_events.h" + +#define DAP_MAX_EPOLL_EVENTS 8192 + +//typedef struct open_connection_info_s { +// dap_events_socket_t *es; +// struct open_connection_info *prev; +// struct open_connection_info *next; +//} dap_events_socket_info_t; + +//dap_events_socket_info_t **s_dap_events_sockets; + +static uint32_t s_threads_count = 1; +static size_t s_connection_timeout = 600; +static struct epoll_event *g_epoll_events = NULL; + +dap_worker_t *s_workers = NULL; +dap_thread_t *s_threads = NULL; + +#define LOG_TAG "dap_events" + +uint32_t s_get_cpu_count( ) +{ +#ifdef _WIN32 + SYSTEM_INFO si; + + GetSystemInfo( &si ); + return si.dwNumberOfProcessors; +#else +#ifndef NO_POSIX_SHED + cpu_set_t cs; + CPU_ZERO( &cs ); + sched_getaffinity( 0, sizeof(cs), &cs ); + + uint32_t count = 0; + for ( int i = 0; i < 32; i++ ){ + if ( CPU_ISSET(i, &cs) ) + count ++; + } + return count; +#else + return 1; +#endif +#endif +} + +/** + * @brief sa_server_init Init server module + * @arg a_threads_count number of events processor workers in parallel threads + * @return Zero if ok others if no + */ +int32_t dap_events_init( uint32_t a_threads_count, size_t conn_timeout ) +{ + s_threads_count = a_threads_count ? a_threads_count : s_get_cpu_count( ); + + if ( conn_timeout ) + s_connection_timeout = conn_timeout; + + s_workers = (dap_worker_t *) calloc( 1, sizeof(dap_worker_t) * s_threads_count ); + s_threads = (dap_thread_t *) calloc( 1, sizeof(dap_thread_t) * s_threads_count ); + if ( !s_workers || !s_threads ) + goto err; + + g_epoll_events = (struct epoll_event *)malloc( sizeof(struct epoll_event) * DAP_MAX_EPOLL_EVENTS * s_threads_count ); + if ( !g_epoll_events ) + goto err; + + if ( dap_events_socket_init() != 0 ) { + + log_it( L_CRITICAL, "Can't init client submodule dap_events_socket_init( )" ); + goto err; + } + + log_it( L_NOTICE, "Initialized socket server module" ); + + #ifndef _WIN32 + signal( SIGPIPE, SIG_IGN ); + #endif + return 0; + +err: + dap_events_deinit( ); + return -1; +} + +/** + * @brief sa_server_deinit Deinit server module + */ +void dap_events_deinit( ) +{ + dap_events_socket_deinit( ); + + if ( g_epoll_events ) + free( g_epoll_events ); + + if ( s_threads ) + free( s_threads ); + + if ( s_workers ) + free( s_workers ); +} + +/** + * @brief server_new Creates new empty instance of server_t + * @return New instance + */ +dap_events_t * dap_events_new( ) +{ + dap_events_t *ret = (dap_events_t *)calloc( 1, sizeof(dap_events_t) ); + + pthread_rwlock_init( &ret->sockets_rwlock, NULL ); + pthread_rwlock_init( &ret->servers_rwlock, NULL ); + + return ret; +} + +/** + * @brief server_delete Delete event processor instance + * @param sh Pointer to the server instance + */ +void dap_events_delete( dap_events_t *a_events ) +{ + dap_events_socket_t *cur, *tmp; + + if ( a_events ) { + + HASH_ITER( hh, a_events->sockets,cur, tmp ) { + dap_events_socket_delete( cur, false ); + } + + if ( a_events->_inheritor ) + free( a_events->_inheritor ); + + pthread_rwlock_destroy( &a_events->servers_rwlock ); + pthread_rwlock_destroy( &a_events->sockets_rwlock ); + + free( a_events ); + } +} + +void dap_events_kill_socket( dap_events_socket_t *a_es ) +{ + if ( !a_es ) { + log_it( L_ERROR, "dap_events_kill_socket( NULL )" ); + return; + } + + uint32_t tn = a_es->dap_worker->number_thread; + + dap_worker_t *w = a_es->dap_worker; + dap_events_t *d_ev = w->events; + + pthread_mutex_lock( &w->locker_on_count ); + if ( a_es->kill_signal ) { + pthread_mutex_unlock( &w->locker_on_count ); + return; + } + + log_it( L_DEBUG, "KILL %u socket! [ thread %u ]", a_es->socket, tn ); + + a_es->kill_signal = true; + DL_LIST_ADD_NODE_HEAD( d_ev->to_kill_sockets, a_es, kprev, knext, w->event_to_kill_count ); + + pthread_mutex_unlock( &w->locker_on_count ); +} + + +/** + * @brief s_socket_info_all_check_activity + * @param n_thread + * @param sh + */ +static void s_socket_all_check_activity( dap_worker_t *dap_worker, dap_events_t *d_ev, time_t cur_time ) +{ + dap_events_socket_t *a_es, *tmp; + + pthread_mutex_lock( &dap_worker->locker_on_count ); + DL_FOREACH_SAFE( d_ev->dlsockets, a_es, tmp ) { + + if ( !a_es->kill_signal && cur_time >= a_es->last_time_active + s_connection_timeout && !a_es->no_close ) { + + log_it( L_INFO, "Socket %u timeout, closing...", a_es->socket ); + + if ( epoll_ctl( dap_worker->epoll_fd, EPOLL_CTL_DEL, a_es->socket, &a_es->ev) == -1 ) + log_it( L_ERROR,"Can't remove event socket's handler from the epoll_fd" ); + else + log_it( L_DEBUG,"Removed epoll's event from dap_worker #%u", dap_worker->number_thread ); + + dap_worker->event_sockets_count --; + DL_DELETE( d_ev->dlsockets, a_es ); + dap_events_socket_delete( a_es, false ); + } + } + pthread_mutex_unlock( &dap_worker->locker_on_count ); + +} + +/** + * @brief thread_worker_function + * @param arg + * @return + */ +static void *thread_worker_function( void *arg ) +{ + dap_events_socket_t *cur, *tmp; + dap_worker_t *w = (dap_worker_t *)arg; + time_t next_time_timeout_check = time( NULL ) + s_connection_timeout / 2; + uint32_t tn = w->number_thread; + + #ifndef _WIN32 + #ifndef NO_POSIX_SHED + cpu_set_t mask; + CPU_ZERO( &mask ); + CPU_SET( tn, &mask ); + + if ( pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &mask) != 0 ) + { + log_it(L_CRITICAL, "Error pthread_setaffinity_np() You really have %d or more core in CPU?", *(int*)arg); + abort(); + } + #endif + #else + + if ( !SetThreadAffinityMask( GetCurrentThread(), (DWORD_PTR)(1 << tn) ) ) { + log_it( L_CRITICAL, "Error pthread_setaffinity_np() You really have %d or more core in CPU?", tn ); + abort(); + } + #endif + + log_it(L_INFO, "Worker %d started, epoll fd %d", w->number_thread, w->epoll_fd); + + struct epoll_event *events = &g_epoll_events[ DAP_MAX_EPOLL_EVENTS * tn ]; + +// memset( &ev, 0, sizeof(ev) ); +// memset( &events, 0, sizeof(events) ); + + size_t total_sent; int bytes_sent; + + while( 1 ) { + + int selected_sockets = epoll_wait( w->epoll_fd, events, DAP_MAX_EPOLL_EVENTS, 1000 ); + + if ( selected_sockets == -1 ) { + if ( errno == EINTR ) + continue; + break; + } + + time_t cur_time = time( NULL ); + + for( int32_t n = 0; n < selected_sockets; n ++ ) { + + cur = (dap_events_socket_t *)events[n].data.ptr; + + if ( !cur ) { + + log_it( L_ERROR,"dap_events_socket NULL" ); + continue; + } + + if ( events[n].events & EPOLLERR ) { + log_it( L_ERROR,"Socket error: %s",strerror(errno) ); + cur->flags |= DAP_SOCK_SIGNAL_CLOSE; + cur->callbacks->error_callback( cur, NULL ); // Call callback to process error event + } + + cur->last_time_active = cur_time; + + if( events[n].events & EPOLLIN ) { + + //log_it(DEBUG,"Comes connection in active read set"); + if( cur->buf_in_size == sizeof(cur->buf_in) ) { + log_it( L_WARNING, "Buffer is full when there is smth to read. Its dropped!" ); + cur->buf_in_size = 0; + } + + int32_t bytes_read = recv( cur->socket, (char *)(cur->buf_in + cur->buf_in_size), + sizeof(cur->buf_in) - cur->buf_in_size, 0 ); + if( bytes_read > 0 ) { + cur->buf_in_size += bytes_read; + //log_it(DEBUG, "Received %d bytes", bytes_read); + cur->callbacks->read_callback( cur, NULL ); // Call callback to process read event. At the end of callback buf_in_size should be zero if everything was read well + } + else if( bytes_read < 0 ) { + log_it( L_ERROR,"Some error occured in recv() function: %s",strerror(errno) ); + dap_events_socket_set_readable( cur, false ); + cur->flags |= DAP_SOCK_SIGNAL_CLOSE; + } + else if ( bytes_read == 0 ) { + log_it( L_INFO, "Client socket disconnected" ); + dap_events_socket_set_readable( cur, false ); + cur->flags |= DAP_SOCK_SIGNAL_CLOSE; + } + } + + // Socket is ready to write + if( ( (events[n].events & EPOLLOUT) || (cur->flags & DAP_SOCK_READY_TO_WRITE) ) && !(cur->flags & DAP_SOCK_SIGNAL_CLOSE) ) { + ///log_it(DEBUG, "Main loop output: %u bytes to send",sa_cur->buf_out_size); + cur->callbacks->write_callback( cur, NULL ); // Call callback to process write event + + if( cur->flags & DAP_SOCK_READY_TO_WRITE ) { + + static const uint32_t buf_out_zero_count_max = 20; + cur->buf_out[cur->buf_out_size] = 0; + + if( !cur->buf_out_size ) { + + log_it(L_WARNING, "Output: nothing to send. Why we are in write socket set?"); + cur->buf_out_zero_count ++; + + if( cur->buf_out_zero_count > buf_out_zero_count_max ) { // How many time buf_out on write event could be empty + log_it( L_ERROR, "Output: nothing to send %u times, remove socket from the write set", buf_out_zero_count_max ); + dap_events_socket_set_writable( cur, false ); + } + } + else + cur->buf_out_zero_count = 0; + } + for ( total_sent = 0; total_sent < cur->buf_out_size; ) { // If after callback there is smth to send - we do it + + bytes_sent = send( cur->socket, (char *)(cur->buf_out + total_sent), + cur->buf_out_size - total_sent, MSG_DONTWAIT | MSG_NOSIGNAL ); + + if ( bytes_sent < 0 ) { + log_it(L_ERROR,"Some error occured in send() function"); + cur->flags |= DAP_SOCK_SIGNAL_CLOSE; + break; + } + total_sent += bytes_sent; + //log_it(L_DEBUG, "Output: %u from %u bytes are sent ", total_sent,sa_cur->buf_out_size); + } + //log_it(L_DEBUG,"Output: sent %u bytes",total_sent); + cur->buf_out_size = 0; + } + + if ( (cur->flags & DAP_SOCK_SIGNAL_CLOSE) && !cur->no_close ) { + + pthread_mutex_lock( &w->locker_on_count ); + + if ( cur->kill_signal ) { + pthread_mutex_unlock( &w->locker_on_count ); + continue; + } + +// pthread_mutex_unlock( &dsth->mutex_dlist_add_remove ); +// dap_server_kill_socket( dap_cur ); +// continue; + + log_it( L_INFO, "Got signal to close %s, sock %u [thread %u]", cur->hostaddr, cur->socket, tn ); + + dap_events_socket_remove_and_delete( cur, false ); + pthread_mutex_unlock( &w->locker_on_count ); + } + } // for + + #ifndef NO_TIMER + if ( cur_time >= next_time_timeout_check ) { + + s_socket_all_check_activity( w, w->events, cur_time ); + next_time_timeout_check = cur_time + s_connection_timeout / 2; + } + #endif + + pthread_mutex_lock( &w->locker_on_count ); + if ( !w->event_to_kill_count ) { + + pthread_mutex_unlock( &w->locker_on_count ); + continue; + } + + cur = w->events->to_kill_sockets; + + do { + +// if ( cur->no_close ) { +// cur = cur->knext; +// continue; +// } + + log_it( L_INFO, "Kill %u socket .... [ thread %u ]", cur->socket, tn ); + + tmp = cur->knext; + DL_LIST_REMOVE_NODE( w->events->to_kill_sockets, cur, kprev, knext, w->event_to_kill_count ); + + dap_events_socket_remove_and_delete( cur, false ); + cur = tmp; + + } while ( cur ); + + log_it( L_INFO, "[ Thread %u ] coneections: %u, to kill: %u", tn, w->event_sockets_count, w->event_to_kill_count ); + pthread_mutex_unlock( &w->locker_on_count ); + + } // while + + return NULL; +} + +/** + * @brief dap_worker_get_min + * @return + */ +dap_worker_t *dap_worker_get_min( ) +{ + return &s_workers[dap_worker_get_index_min()]; +} + +/** + * @brief dap_worker_get_index_min + * @return + */ +uint32_t dap_worker_get_index_min( ) +{ + uint32_t min = 0; + uint32_t i; + + for( i = 1; i < s_threads_count; i++ ) { + + if ( s_workers[min].event_sockets_count > s_workers[i].event_sockets_count ) + min = i; + } + + return min; +} + +/** + * @brief dap_worker_print_all + */ +void dap_worker_print_all( ) +{ + uint32_t i; + + for( i = 0; i < s_threads_count; i ++ ) { + + log_it( L_INFO, "Worker: %d, count open connections: %d", + s_workers[i].number_thread, s_workers[i].event_sockets_count ); + } +} + +/** + * @brief sa_server_loop Main server loop + * @param sh Server instance + * @return Zero if ok others if not + */ +int dap_events_start( dap_events_t *a_events ) +{ + for( uint32_t i = 0; i < s_threads_count; i++) { + + s_workers[i].epoll_fd = epoll_create( DAP_MAX_EPOLL_EVENTS ); + if ( (intptr_t)s_workers[i].epoll_fd == -1 ) { + log_it(L_CRITICAL, "Error create epoll fd"); + return -1; + } + + s_workers[i].event_to_kill_count = 0; + s_workers[i].event_sockets_count = 0; + s_workers[i].number_thread = i; + s_workers[i].events = a_events; + + pthread_mutex_init( &s_workers[i].locker_on_count, NULL ); + pthread_create( &s_threads[i].tid, NULL, thread_worker_function, &s_workers[i] ); + } + + return 0; +} + +/** + * @brief dap_events_wait + * @param sh + * @return + */ +int dap_events_wait( dap_events_t *sh ) +{ + (void) sh; + + for( uint32_t i = 0; i < s_threads_count; i ++ ) { + void *ret; + pthread_join( s_threads[i].tid, &ret ); + } + + return 0; +} + + + +/** + * @brief dap_worker_add_events_socket + * @param a_worker + * @param a_events_socket + */ +void dap_worker_add_events_socket( dap_events_socket_t *a_es) +{ +// struct epoll_event ev = {0}; + dap_worker_t *l_worker = dap_worker_get_min( ); + + a_es->dap_worker = l_worker; + a_es->events = a_es->dap_worker->events; +} + +/** + * @brief dap_events_socket_delete + * @param a_es + */ +void dap_events_socket_remove_and_delete( dap_events_socket_t *a_es, bool preserve_inheritor ) +{ + if ( epoll_ctl( a_es->dap_worker->epoll_fd, EPOLL_CTL_DEL, a_es->socket, &a_es->ev) == -1 ) + log_it( L_ERROR,"Can't remove event socket's handler from the epoll_fd" ); + else + log_it( L_DEBUG,"Removed epoll's event from dap_worker #%u", a_es->dap_worker->number_thread ); + + DL_DELETE( a_es->events->dlsockets, a_es ); + a_es->dap_worker->event_sockets_count --; + + dap_events_socket_delete( a_es, preserve_inheritor ); +} + +/** + * @brief dap_events__thread_wake_up + * @param th + */ +void dap_events_thread_wake_up( dap_thread_t *th ) +{ + (void) th; + //pthread_kill(th->tid,SIGUSR1); +} diff --git a/src/dap_events_socket.c b/src/dap_events_socket.c index c5c06040aa28b24511afb37633adac990f743fb6..c90b4139ab69a80d09fa14044e131e168f183d48 100755 --- a/src/dap_events_socket.c +++ b/src/dap_events_socket.c @@ -1,367 +1,367 @@ -/* - * Authors: - * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net> - * DeM Labs Inc. https://demlabs.net - * Kelvin Project https://github.com/kelvinblockchain - * Copyright (c) 2017-2019 - * 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 <stdlib.h> -#include <stdio.h> -#include <stdarg.h> -#include <string.h> -#include <assert.h> - -#ifndef _WIN32 -#include <sys/epoll.h> -#include <unistd.h> -#include <fcntl.h> -#else -#undef _WIN32_WINNT -#define _WIN32_WINNT 0x0600 -#include <winsock2.h> -#include <windows.h> -#include <mswsock.h> -#include <ws2tcpip.h> -#include <io.h> -#include "wrappers.h" -#include <wepoll.h> -#include <pthread.h> -#endif - -#include "dap_common.h" -#include "dap_events.h" - -#include "dap_events_socket.h" - -#define LOG_TAG "dap_events_socket" - -/** - * @brief dap_events_socket_init Init clients module - * @return Zero if ok others if no - */ -int dap_events_socket_init( ) -{ - log_it(L_NOTICE,"Initialized socket client module"); - return 0; -} - -/** - * @brief dap_events_socket_deinit Deinit clients module - */ -void dap_events_socket_deinit( ) -{ - -} - - -/** - * @brief dap_events_socket_wrap - * @param a_events - * @param w - * @param s - * @param a_callbacks - * @return - */ -dap_events_socket_t *dap_events_socket_wrap_no_add( dap_events_t *a_events, - int a_sock, dap_events_socket_callbacks_t *a_callbacks ) -{ -// assert(a_events); - assert(a_callbacks); - - log_it( L_DEBUG,"Dap event socket wrapped around %d sock a_events = %X", a_sock, a_events ); - - dap_events_socket_t *ret = DAP_NEW_Z( dap_events_socket_t ); - - ret->socket = a_sock; - ret->events = a_events; - ret->callbacks = a_callbacks; - ret->flags = DAP_SOCK_READY_TO_READ; - ret->close_denied = true; - - log_it( L_DEBUG,"Dap event socket wrapped around %d sock a_events = %X", a_sock, a_events ); - - return ret; -} - -/** - * @brief dap_events_socket_create_after - * @param a_es - */ -void dap_events_socket_create_after( dap_events_socket_t *a_es ) -{ - if ( a_es->callbacks->new_callback ) - a_es->callbacks->new_callback( a_es, NULL ); // Init internal structure - - a_es->last_time_active = a_es->last_ping_request = time( NULL ); - - dap_worker_add_events_socket( a_es ); - - pthread_mutex_lock( &a_es->dap_worker->locker_on_count ); - - a_es->dap_worker->event_sockets_count ++; - DL_APPEND( a_es->events->dlsockets, a_es ); - - pthread_rwlock_wrlock( &a_es->events->sockets_rwlock ); - HASH_ADD_INT( a_es->events->sockets, socket, a_es ); - pthread_rwlock_unlock( &a_es->events->sockets_rwlock ); - - a_es->ev.events = EPOLLIN | EPOLLERR | EPOLLOUT; - a_es->ev.data.ptr = a_es; - - if ( epoll_ctl( a_es->dap_worker->epoll_fd, EPOLL_CTL_ADD, a_es->socket, &a_es->ev ) == 1 ) - log_it( L_CRITICAL, "Can't add event socket's handler to epoll_fd" ); - - pthread_mutex_unlock( &a_es->dap_worker->locker_on_count ); -} - -/** - * @brief dap_events_socket_wrap - * @param a_events - * @param w - * @param s - * @param a_callbacks - * @return - */ -dap_events_socket_t * dap_events_socket_wrap2( dap_server_t *a_server, struct dap_events *a_events, - int a_sock, dap_events_socket_callbacks_t *a_callbacks ) -{ - assert( a_events ); - assert( a_callbacks ); - assert( a_server ); - - log_it( L_DEBUG,"Sap event socket wrapped around %d sock", a_sock ); - dap_events_socket_t * ret = DAP_NEW_Z( dap_events_socket_t ); - - ret->socket = a_sock; - ret->events = a_events; - ret->callbacks = a_callbacks; - - ret->flags = DAP_SOCK_READY_TO_READ; - ret->is_pingable = true; - ret->last_time_active = ret->last_ping_request = time( NULL ); - - pthread_rwlock_wrlock( &a_events->sockets_rwlock ); - HASH_ADD_INT( a_events->sockets, socket, ret ); - pthread_rwlock_unlock( &a_events->sockets_rwlock ); - - if( a_callbacks->new_callback ) - a_callbacks->new_callback( ret, NULL ); // Init internal structure - - return ret; -} - -/** - * @brief dap_events_socket_find - * @param sock - * @param sh - * @return - */ -dap_events_socket_t *dap_events_socket_find( int sock, struct dap_events *a_events ) -{ - dap_events_socket_t *ret = NULL; - - pthread_rwlock_rdlock( &a_events->sockets_rwlock ); - HASH_FIND_INT( a_events->sockets, &sock, ret ); - pthread_rwlock_unlock( &a_events->sockets_rwlock ); - - return ret; -} - -/** - * @brief dap_events_socket_ready_to_read - * @param sc - * @param isReady - */ -void dap_events_socket_set_readable( dap_events_socket_t *sc, bool is_ready ) -{ - if( is_ready == (bool)(sc->flags & DAP_SOCK_READY_TO_READ) ) - return; - - sc->ev.events = EPOLLERR; - - if ( is_ready ) - sc->flags |= DAP_SOCK_READY_TO_READ; - else - sc->flags ^= DAP_SOCK_READY_TO_READ; - - int events = EPOLLERR; - - if( sc->flags & DAP_SOCK_READY_TO_READ ) - events |= EPOLLIN; - - if( sc->flags & DAP_SOCK_READY_TO_WRITE ) - events |= EPOLLOUT; - - sc->ev.events = events; - - if ( epoll_ctl(sc->dap_worker->epoll_fd, EPOLL_CTL_MOD, sc->socket, &sc->ev) == -1 ) - log_it( L_ERROR,"Can't update read client socket state in the epoll_fd" ); - else - dap_events_thread_wake_up( &sc->events->proc_thread ); -} - -/** - * @brief dap_events_socket_ready_to_write - * @param sc - * @param isReady - */ -void dap_events_socket_set_writable( dap_events_socket_t *sc, bool is_ready ) -{ - if ( is_ready == (bool)(sc->flags & DAP_SOCK_READY_TO_WRITE) ) - return; - - if ( is_ready ) - sc->flags |= DAP_SOCK_READY_TO_WRITE; - else - sc->flags ^= DAP_SOCK_READY_TO_WRITE; - - int events = EPOLLERR; - - if( sc->flags & DAP_SOCK_READY_TO_READ ) - events |= EPOLLIN; - - if( sc->flags & DAP_SOCK_READY_TO_WRITE ) - events |= EPOLLOUT; - - sc->ev.events = events; - - if ( epoll_ctl(sc->dap_worker->epoll_fd, EPOLL_CTL_MOD, sc->socket, &sc->ev) == -1 ) - log_it(L_ERROR,"Can't update write client socket state in the epoll_fd"); - else - dap_events_thread_wake_up( &sc->events->proc_thread ); -} - - -/** - * @brief dap_events_socket_remove Removes the client from the list - * @param sc Connection instance - */ -void dap_events_socket_delete( dap_events_socket_t *a_es, bool preserve_inheritor ) -{ - if ( !a_es ) return; - - log_it( L_DEBUG, "es is going to be removed from the lists and free the memory (0x%016X)", a_es ); - - pthread_rwlock_wrlock( &a_es->events->sockets_rwlock ); - HASH_DEL( a_es->events->sockets, a_es ); - pthread_rwlock_unlock( &a_es->events->sockets_rwlock ); - - log_it( L_DEBUG, "dap_events_socket wrapped around %d socket is removed", a_es->socket ); - - if( a_es->callbacks->delete_callback ) - a_es->callbacks->delete_callback( a_es, NULL ); // Init internal structure - - if ( a_es->_inheritor && !preserve_inheritor ) - free( a_es->_inheritor ); - - if ( a_es->socket ) - close( a_es->socket ); - - free( a_es ); -} - -/** - * @brief dap_events_socket_write Write data to the client - * @param sc Conn instance - * @param data Pointer to data - * @param data_size Size of data to write - * @return Number of bytes that were placed into the buffer - */ -size_t dap_events_socket_write(dap_events_socket_t *sc, const void * data, size_t data_size) -{ - log_it(L_DEBUG,"dap_events_socket_write %u sock data %X size %u", sc->socket, data, data_size ); - - data_size = ((sc->buf_out_size+data_size)<(sizeof(sc->buf_out)))?data_size:(sizeof(sc->buf_out)-sc->buf_out_size ); - memcpy(sc->buf_out+sc->buf_out_size,data,data_size); - sc->buf_out_size+=data_size; - return data_size; -} - -/** - * @brief dap_events_socket_write_f Write formatted text to the client - * @param sc Conn instance - * @param format Format - * @return Number of bytes that were placed into the buffer - */ -size_t dap_events_socket_write_f(dap_events_socket_t *sc, const char * format,...) -{ - log_it(L_DEBUG,"dap_events_socket_write_f %u sock", sc->socket ); - - size_t max_data_size = sizeof(sc->buf_out)-sc->buf_out_size; - va_list ap; - va_start(ap,format); - int ret=vsnprintf((char*) sc->buf_out+sc->buf_out_size,max_data_size,format,ap); - va_end(ap); - if(ret>0){ - sc->buf_out_size+=ret; - return ret; - }else{ - log_it(L_ERROR,"Can't write out formatted data '%s'",format); - return 0; - } -} - -/** - * @brief dap_events_socket_read Read data from input buffer - * @param sc Conn instasnce - * @param data Pointer to memory where to store the data - * @param data_size Size of data to read - * @return Actual bytes number that were read - */ -size_t dap_events_socket_read(dap_events_socket_t *sc, void *data, size_t data_size) -{ - log_it(L_DEBUG,"dap_events_socket_read %u sock data %X size %u", sc->socket, data, data_size ); - - if(data_size<sc->buf_in_size){ - memcpy(data,sc->buf_in,data_size); - memmove(data,sc->buf_in+data_size,sc->buf_in_size-data_size); - }else{ - if(data_size>sc->buf_in_size) - data_size=sc->buf_in_size; - memcpy(data,sc->buf_in,data_size); - } - sc->buf_in_size-=data_size; - return data_size; -} - - -/** - * @brief dap_events_socket_shrink_client_buf_in Shrink input buffer (shift it left) - * @param cl Client instance - * @param shrink_size Size on wich we shrink the buffer with shifting it left - */ -void dap_events_socket_shrink_buf_in(dap_events_socket_t * cl, size_t shrink_size) -{ - if((shrink_size==0)||(cl->buf_in_size==0) ){ - return; - }else if(cl->buf_in_size>shrink_size){ - size_t buf_size=cl->buf_in_size-shrink_size; - void * buf = malloc(buf_size); - memcpy(buf,cl->buf_in+ shrink_size,buf_size ); - memcpy(cl->buf_in,buf,buf_size); - cl->buf_in_size=buf_size; - if (buf) - free(buf); - }else{ - //log_it(WARNING,"Shrinking size of input buffer on amount bigger than actual buffer's size"); - cl->buf_in_size=0; - } - -} +/* + * Authors: + * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net> + * DeM Labs Inc. https://demlabs.net + * Kelvin Project https://github.com/kelvinblockchain + * Copyright (c) 2017-2019 + * 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 <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <assert.h> + +#ifndef _WIN32 +#include <sys/epoll.h> +#include <unistd.h> +#include <fcntl.h> +#else +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0600 +#include <winsock2.h> +#include <windows.h> +#include <mswsock.h> +#include <ws2tcpip.h> +#include <io.h> +#include "wrappers.h" +#include <wepoll.h> +#include <pthread.h> +#endif + +#include "dap_common.h" +#include "dap_events.h" + +#include "dap_events_socket.h" + +#define LOG_TAG "dap_events_socket" + +/** + * @brief dap_events_socket_init Init clients module + * @return Zero if ok others if no + */ +int dap_events_socket_init( ) +{ + log_it(L_NOTICE,"Initialized socket client module"); + return 0; +} + +/** + * @brief dap_events_socket_deinit Deinit clients module + */ +void dap_events_socket_deinit( ) +{ + +} + + +/** + * @brief dap_events_socket_wrap + * @param a_events + * @param w + * @param s + * @param a_callbacks + * @return + */ +dap_events_socket_t *dap_events_socket_wrap_no_add( dap_events_t *a_events, + int a_sock, dap_events_socket_callbacks_t *a_callbacks ) +{ +// assert(a_events); + assert(a_callbacks); + + log_it( L_DEBUG,"Dap event socket wrapped around %d sock a_events = %X", a_sock, a_events ); + + dap_events_socket_t *ret = DAP_NEW_Z( dap_events_socket_t ); + + ret->socket = a_sock; + ret->events = a_events; + ret->callbacks = a_callbacks; + ret->flags = DAP_SOCK_READY_TO_READ; + ret->no_close = true; + + log_it( L_DEBUG,"Dap event socket wrapped around %d sock a_events = %X", a_sock, a_events ); + + return ret; +} + +/** + * @brief dap_events_socket_create_after + * @param a_es + */ +void dap_events_socket_create_after( dap_events_socket_t *a_es ) +{ + if ( a_es->callbacks->new_callback ) + a_es->callbacks->new_callback( a_es, NULL ); // Init internal structure + + a_es->last_time_active = a_es->last_ping_request = time( NULL ); + + dap_worker_add_events_socket( a_es ); + + pthread_mutex_lock( &a_es->dap_worker->locker_on_count ); + + a_es->dap_worker->event_sockets_count ++; + DL_APPEND( a_es->events->dlsockets, a_es ); + + pthread_rwlock_wrlock( &a_es->events->sockets_rwlock ); + HASH_ADD_INT( a_es->events->sockets, socket, a_es ); + pthread_rwlock_unlock( &a_es->events->sockets_rwlock ); + + a_es->ev.events = EPOLLIN | EPOLLERR | EPOLLOUT; + a_es->ev.data.ptr = a_es; + + if ( epoll_ctl( a_es->dap_worker->epoll_fd, EPOLL_CTL_ADD, a_es->socket, &a_es->ev ) == 1 ) + log_it( L_CRITICAL, "Can't add event socket's handler to epoll_fd" ); + + pthread_mutex_unlock( &a_es->dap_worker->locker_on_count ); +} + +/** + * @brief dap_events_socket_wrap + * @param a_events + * @param w + * @param s + * @param a_callbacks + * @return + */ +dap_events_socket_t * dap_events_socket_wrap2( dap_server_t *a_server, struct dap_events *a_events, + int a_sock, dap_events_socket_callbacks_t *a_callbacks ) +{ + assert( a_events ); + assert( a_callbacks ); + assert( a_server ); + + log_it( L_DEBUG,"Sap event socket wrapped around %d sock", a_sock ); + dap_events_socket_t * ret = DAP_NEW_Z( dap_events_socket_t ); + + ret->socket = a_sock; + ret->events = a_events; + ret->callbacks = a_callbacks; + + ret->flags = DAP_SOCK_READY_TO_READ; + ret->is_pingable = true; + ret->last_time_active = ret->last_ping_request = time( NULL ); + + pthread_rwlock_wrlock( &a_events->sockets_rwlock ); + HASH_ADD_INT( a_events->sockets, socket, ret ); + pthread_rwlock_unlock( &a_events->sockets_rwlock ); + + if( a_callbacks->new_callback ) + a_callbacks->new_callback( ret, NULL ); // Init internal structure + + return ret; +} + +/** + * @brief dap_events_socket_find + * @param sock + * @param sh + * @return + */ +dap_events_socket_t *dap_events_socket_find( int sock, struct dap_events *a_events ) +{ + dap_events_socket_t *ret = NULL; + + pthread_rwlock_rdlock( &a_events->sockets_rwlock ); + HASH_FIND_INT( a_events->sockets, &sock, ret ); + pthread_rwlock_unlock( &a_events->sockets_rwlock ); + + return ret; +} + +/** + * @brief dap_events_socket_ready_to_read + * @param sc + * @param isReady + */ +void dap_events_socket_set_readable( dap_events_socket_t *sc, bool is_ready ) +{ + if( is_ready == (bool)(sc->flags & DAP_SOCK_READY_TO_READ) ) + return; + + sc->ev.events = EPOLLERR; + + if ( is_ready ) + sc->flags |= DAP_SOCK_READY_TO_READ; + else + sc->flags ^= DAP_SOCK_READY_TO_READ; + + int events = EPOLLERR; + + if( sc->flags & DAP_SOCK_READY_TO_READ ) + events |= EPOLLIN; + + if( sc->flags & DAP_SOCK_READY_TO_WRITE ) + events |= EPOLLOUT; + + sc->ev.events = events; + + if ( epoll_ctl(sc->dap_worker->epoll_fd, EPOLL_CTL_MOD, sc->socket, &sc->ev) == -1 ) + log_it( L_ERROR,"Can't update read client socket state in the epoll_fd" ); + else + dap_events_thread_wake_up( &sc->events->proc_thread ); +} + +/** + * @brief dap_events_socket_ready_to_write + * @param sc + * @param isReady + */ +void dap_events_socket_set_writable( dap_events_socket_t *sc, bool is_ready ) +{ + if ( is_ready == (bool)(sc->flags & DAP_SOCK_READY_TO_WRITE) ) + return; + + if ( is_ready ) + sc->flags |= DAP_SOCK_READY_TO_WRITE; + else + sc->flags ^= DAP_SOCK_READY_TO_WRITE; + + int events = EPOLLERR; + + if( sc->flags & DAP_SOCK_READY_TO_READ ) + events |= EPOLLIN; + + if( sc->flags & DAP_SOCK_READY_TO_WRITE ) + events |= EPOLLOUT; + + sc->ev.events = events; + + if ( epoll_ctl(sc->dap_worker->epoll_fd, EPOLL_CTL_MOD, sc->socket, &sc->ev) == -1 ) + log_it(L_ERROR,"Can't update write client socket state in the epoll_fd"); + else + dap_events_thread_wake_up( &sc->events->proc_thread ); +} + + +/** + * @brief dap_events_socket_remove Removes the client from the list + * @param sc Connection instance + */ +void dap_events_socket_delete( dap_events_socket_t *a_es, bool preserve_inheritor ) +{ + if ( !a_es ) return; + + log_it( L_DEBUG, "es is going to be removed from the lists and free the memory (0x%016X)", a_es ); + + pthread_rwlock_wrlock( &a_es->events->sockets_rwlock ); + HASH_DEL( a_es->events->sockets, a_es ); + pthread_rwlock_unlock( &a_es->events->sockets_rwlock ); + + log_it( L_DEBUG, "dap_events_socket wrapped around %d socket is removed", a_es->socket ); + + if( a_es->callbacks->delete_callback ) + a_es->callbacks->delete_callback( a_es, NULL ); // Init internal structure + + if ( a_es->_inheritor && !preserve_inheritor ) + free( a_es->_inheritor ); + + if ( a_es->socket ) + close( a_es->socket ); + + free( a_es ); +} + +/** + * @brief dap_events_socket_write Write data to the client + * @param sc Conn instance + * @param data Pointer to data + * @param data_size Size of data to write + * @return Number of bytes that were placed into the buffer + */ +size_t dap_events_socket_write(dap_events_socket_t *sc, const void * data, size_t data_size) +{ + log_it(L_DEBUG,"dap_events_socket_write %u sock data %X size %u", sc->socket, data, data_size ); + + data_size = ((sc->buf_out_size+data_size)<(sizeof(sc->buf_out)))?data_size:(sizeof(sc->buf_out)-sc->buf_out_size ); + memcpy(sc->buf_out+sc->buf_out_size,data,data_size); + sc->buf_out_size+=data_size; + return data_size; +} + +/** + * @brief dap_events_socket_write_f Write formatted text to the client + * @param sc Conn instance + * @param format Format + * @return Number of bytes that were placed into the buffer + */ +size_t dap_events_socket_write_f(dap_events_socket_t *sc, const char * format,...) +{ + log_it(L_DEBUG,"dap_events_socket_write_f %u sock", sc->socket ); + + size_t max_data_size = sizeof(sc->buf_out)-sc->buf_out_size; + va_list ap; + va_start(ap,format); + int ret=vsnprintf((char*) sc->buf_out+sc->buf_out_size,max_data_size,format,ap); + va_end(ap); + if(ret>0){ + sc->buf_out_size+=ret; + return ret; + }else{ + log_it(L_ERROR,"Can't write out formatted data '%s'",format); + return 0; + } +} + +/** + * @brief dap_events_socket_read Read data from input buffer + * @param sc Conn instasnce + * @param data Pointer to memory where to store the data + * @param data_size Size of data to read + * @return Actual bytes number that were read + */ +size_t dap_events_socket_read(dap_events_socket_t *sc, void *data, size_t data_size) +{ + log_it(L_DEBUG,"dap_events_socket_read %u sock data %X size %u", sc->socket, data, data_size ); + + if(data_size<sc->buf_in_size){ + memcpy(data,sc->buf_in,data_size); + memmove(data,sc->buf_in+data_size,sc->buf_in_size-data_size); + }else{ + if(data_size>sc->buf_in_size) + data_size=sc->buf_in_size; + memcpy(data,sc->buf_in,data_size); + } + sc->buf_in_size-=data_size; + return data_size; +} + + +/** + * @brief dap_events_socket_shrink_client_buf_in Shrink input buffer (shift it left) + * @param cl Client instance + * @param shrink_size Size on wich we shrink the buffer with shifting it left + */ +void dap_events_socket_shrink_buf_in(dap_events_socket_t * cl, size_t shrink_size) +{ + if((shrink_size==0)||(cl->buf_in_size==0) ){ + return; + }else if(cl->buf_in_size>shrink_size){ + size_t buf_size=cl->buf_in_size-shrink_size; + void * buf = malloc(buf_size); + memcpy(buf,cl->buf_in+ shrink_size,buf_size ); + memcpy(cl->buf_in,buf,buf_size); + cl->buf_in_size=buf_size; + if (buf) + free(buf); + }else{ + //log_it(WARNING,"Shrinking size of input buffer on amount bigger than actual buffer's size"); + cl->buf_in_size=0; + } + +} diff --git a/src/dap_memcached.c b/src/dap_memcached.c index 0b4c441147c3dcae92e30d956b5bb57111067168..924cf41e15f6472629e5dd9d03a35b16f7c7b7ff 100755 --- a/src/dap_memcached.c +++ b/src/dap_memcached.c @@ -1,71 +1,71 @@ - -#include "dap_memcached.h" - -#include <libmemcached/memcached.h> - -#define LOG_TAG "dap_memcached" - -static memcached_st *_memc; -static bool _is_module_enable = false; - -int dap_memcached_init(const char *server_host, uint16_t port) -{ - memcached_return rc; - memcached_server_st *servers = NULL; - - char *test_key = "test_key"; - char *test_value = "test_value"; - - _memc = memcached_create(NULL); - - servers= memcached_server_list_append(servers, server_host, port, &rc); - rc= memcached_server_push(_memc, servers); - - if (rc != MEMCACHED_SUCCESS) { - log_it(L_ERROR, "Couldn't add server: %s", memcached_strerror(_memc, rc)); - return -1; - } - - if(dap_memcache_put(test_key, test_value, strlen(test_value), 0) != true) { - return -2; - } - - _is_module_enable = true; - return 0; -} - -bool dap_memcache_is_enable() -{ - return _is_module_enable; -} - -bool dap_memcache_put(const char* key, void *value, size_t value_size, time_t expiration) -{ - memcached_return rc; - rc = memcached_set(_memc, key, strlen(key), value, value_size, expiration, (uint32_t)0); - if (rc != MEMCACHED_SUCCESS) { - log_it(L_ERROR, "%s", memcached_strerror(_memc, rc)); - return false; - } - return true; -} - -bool dap_memcache_get(const char* key, size_t * value_size, void ** result) -{ - memcached_return rc; - *result = memcached_get(_memc, key, strlen(key), value_size, NULL, &rc); - return rc == MEMCACHED_SUCCESS; -} - -bool dap_memcache_delete(const char* key) -{ - return memcached_delete(_memc, key, strlen(key), 0) == MEMCACHED_SUCCESS; -} - -/** - * @brief dap_memcached_deinit - */ -void dap_memcached_deinit() -{ - _is_module_enable = false; -} + +#include "dap_memcached.h" + +#include <libmemcached/memcached.h> + +#define LOG_TAG "dap_memcached" + +static memcached_st *_memc; +static bool _is_module_enable = false; + +int dap_memcached_init(const char *server_host, uint16_t port) +{ + memcached_return rc; + memcached_server_st *servers = NULL; + + char *test_key = "test_key"; + char *test_value = "test_value"; + + _memc = memcached_create(NULL); + + servers= memcached_server_list_append(servers, server_host, port, &rc); + rc= memcached_server_push(_memc, servers); + + if (rc != MEMCACHED_SUCCESS) { + log_it(L_ERROR, "Couldn't add server: %s", memcached_strerror(_memc, rc)); + return -1; + } + + if(dap_memcache_put(test_key, test_value, strlen(test_value), 0) != true) { + return -2; + } + + _is_module_enable = true; + return 0; +} + +bool dap_memcache_is_enable() +{ + return _is_module_enable; +} + +bool dap_memcache_put(const char* key, void *value, size_t value_size, time_t expiration) +{ + memcached_return rc; + rc = memcached_set(_memc, key, strlen(key), value, value_size, expiration, (uint32_t)0); + if (rc != MEMCACHED_SUCCESS) { + log_it(L_ERROR, "%s", memcached_strerror(_memc, rc)); + return false; + } + return true; +} + +bool dap_memcache_get(const char* key, size_t * value_size, void ** result) +{ + memcached_return rc; + *result = memcached_get(_memc, key, strlen(key), value_size, NULL, &rc); + return rc == MEMCACHED_SUCCESS; +} + +bool dap_memcache_delete(const char* key) +{ + return memcached_delete(_memc, key, strlen(key), 0) == MEMCACHED_SUCCESS; +} + +/** + * @brief dap_memcached_deinit + */ +void dap_memcached_deinit() +{ + _is_module_enable = false; +} diff --git a/src/dap_server.c b/src/dap_server.c index c5f52862bd01596ca87e86cfd5dc75ddb779ae68..cf0f38abb3dd787756755b58e3cb152a99d3672b 100755 --- a/src/dap_server.c +++ b/src/dap_server.c @@ -1,817 +1,824 @@ -/* - Copyright (c) 2017-2018 (c) Project "DeM Labs Inc" https://github.com/demlabsinc - 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 Lesser 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with any DAP based project. If not, see <http://www.gnu.org/licenses/>. -*/ - -#define __USE_GNU - -#include <string.h> -#include <time.h> -#include <stdio.h> -#include <stdlib.h> -#include <stddef.h> -#include <stdint.h> - -//#include <errno.h> -#include <signal.h> -#include <stdint.h> -#include <stdatomic.h> - -#ifndef _WIN32 -#include <arpa/inet.h> -#include <netinet/in.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/select.h> -#include <errno.h> -#include <netdb.h> -#include <unistd.h> -#include <fcntl.h> -#include <sys/epoll.h> -#include <sys/timerfd.h> -#else -#undef _WIN32_WINNT -#define _WIN32_WINNT 0x0600 -#include <winsock2.h> -#include <windows.h> -#include <mswsock.h> -#include <ws2tcpip.h> -#include <io.h> -#include "wrappers.h" -#include <wepoll.h> -#include <pthread.h> -#endif - -#include <sched.h> - -#if 0 -#define NI_NUMERICHOST 1 /* Don't try to look up hostname. */ -#define NI_NUMERICSERV 2 /* Don't convert port number to name. */ -#define NI_NOFQDN 4 /* Only return nodename portion. */ -#define NI_NAMEREQD 8 /* Don't return numeric addresses. */ -#define NI_DGRAM 16 /* Look up UDP service rather than TCP. */ -#endif - -#include "dap_common.h" -#include "dap_server.h" - -#define LOG_TAG "server" - -#define DAP_MAX_THREAD_EVENTS 8192 -#define DAP_MAX_THREADS 16 - -#define SOCKET_TIMEOUT_TIME 30 -#define SOCKETS_TIMEOUT_CHECK_PERIOD 15 - -static uint32_t _count_threads = 0; -static uint32_t epoll_max_events = 0; -static bool bQuitSignal = false; - -static struct epoll_event *threads_epoll_events = NULL; -static dap_server_t *_current_run_server = NULL; - -static void read_write_cb( dap_client_remote_t *dap_cur, int32_t revents ); - -dap_server_thread_t dap_server_threads[ DAP_MAX_THREADS ]; - -/* -=============================================== - get_epoll_max_user_watches( ) - - return max epoll() event watches -=============================================== -*/ -static uint32_t get_epoll_max_user_watches( void ) -{ - static const char *maxepollpath = "/proc/sys/fs/epoll/max_user_watches"; - uint32_t v = 0, len; - char str[32]; - - FILE *fp = fopen( maxepollpath, "r" ); - if ( !fp ) { - printf("can't open %s\n", maxepollpath ); - return v; - } - - len = fread( &str[0], 1, 31, fp ); - if ( !len ) { - return v; - } - - str[ len ] = 0; - v = atoi( str ); - - return v; -} - -/* -=============================================== - dap_server_init( ) - - Init server module - return Zero if ok others if no -=============================================== -*/ -int32_t dap_server_init( uint32_t count_threads ) -{ - dap_server_thread_t *dap_thread; - - #ifndef _WIN32 - signal( SIGPIPE, SIG_IGN ); - #endif - - if ( count_threads > DAP_MAX_THREADS ) - count_threads = DAP_MAX_THREADS; - - _count_threads = count_threads; - log_it( L_NOTICE, "dap_server_init() threads %u", count_threads ); - - epoll_max_events = get_epoll_max_user_watches( ); - if ( epoll_max_events > DAP_MAX_THREAD_EVENTS ) - epoll_max_events = DAP_MAX_THREAD_EVENTS; - - threads_epoll_events = (struct epoll_event *)malloc( sizeof(struct epoll_event) * _count_threads * epoll_max_events ); - if ( !threads_epoll_events ) - goto err; - - memset( threads_epoll_events, 0, sizeof(struct epoll_event) * _count_threads * epoll_max_events ); - - dap_thread = &dap_server_threads[0]; - memset( dap_thread, 0, sizeof(dap_server_thread_t) * DAP_MAX_THREADS ); - - for ( uint32_t i = 0; i < _count_threads; ++i, ++dap_thread ) { - #ifndef _WIN32 - dap_thread->epoll_fd = -1; - #else - dap_thread->epoll_fd = (void*)-1; - #endif - dap_thread->thread_num = i; - dap_thread->epoll_events = &threads_epoll_events[ i * epoll_max_events ]; - - pthread_mutex_init( &dap_thread->mutex_dlist_add_remove, NULL ); - } - - log_it( L_NOTICE, "Initialized socket server module" ); - - dap_client_remote_init( ); - return 0; - -err:; - - dap_server_deinit( ); - return 1; -} - -/* -========================================================= - dap_server_deinit( ) - - Deinit server module -========================================================= -*/ -void dap_server_deinit( void ) -{ - dap_client_remote_deinit( ); - - if ( threads_epoll_events ) { - free( threads_epoll_events ); - - for ( uint32_t i = 0; i < _count_threads; ++i ) { - pthread_mutex_destroy( &dap_server_threads[i].mutex_dlist_add_remove ); - } - } -} - -/* -========================================================= - dap_server_new( ) - - Creates new empty instance of dap_server_t -========================================================= -*/ -dap_server_t *dap_server_new( void ) -{ - return (dap_server_t *)calloc( 1, sizeof(dap_server_t) ); -} - -/* -========================================================= - dap_server_new( ) - - Delete server instance -========================================================= -*/ -void dap_server_delete( dap_server_t *sh ) -{ - dap_client_remote_t *dap_cur, *tmp; - - if ( !sh ) return; - - if( sh->address ) - free( sh->address ); - - HASH_ITER( hh, sh->clients, dap_cur, tmp ) - dap_client_remote_remove( dap_cur, sh ); - - if( sh->server_delete_callback ) - sh->server_delete_callback( sh, NULL ); - - if ( sh->_inheritor ) - free( sh->_inheritor ); - - pthread_mutex_destroy( &sh->mutex_on_hash ); - - free( sh ); -} - -/* -========================================================= - set_nonblock_socket( ) -========================================================= -*/ -int32_t set_nonblock_socket( int32_t fd ) -{ -#ifdef _WIN32 - unsigned long arg = 1; - return ioctlsocket( fd, FIONBIO, &arg ); -#else - int32_t flags; - - flags = fcntl( fd, F_GETFL ); - flags |= O_NONBLOCK; - - return fcntl( fd, F_SETFL, flags ); -#endif -} - - -/* -========================================================= - get_thread_min_connections( ) - - return number thread which has minimum open connections -========================================================= -*/ -static inline uint32_t get_thread_index_min_connections( ) -{ - uint32_t min = 0; - - for( uint32_t i = 1; i < _count_threads; i ++ ) { - if ( dap_server_threads[min].connections_count > dap_server_threads[i].connections_count ) { - min = i; - } - } - - return min; -} - -/* -========================================================= - print_online( ) - -========================================================= -*/ -static inline void print_online() -{ -// for( uint32_t i = 0; i < _count_threads; i ++ ) { -// log_it(L_INFO, "Thread number: %d, count: %d", -// thread_inform[i].thread_number, atomic_load(&thread_inform[i].count_open_connections) ); -// } -} - -void dap_server_kill_socket( dap_client_remote_t *dcr ) -{ - if ( !dcr ) { - log_it( L_ERROR, "dap_server_kill_socket( NULL )" ); - return; - } - - dap_server_thread_t *dsth = &dap_server_threads[ dcr->tn ]; - - pthread_mutex_lock( &dsth->mutex_dlist_add_remove ); - - if ( dcr->kill_signal ) { - pthread_mutex_unlock( &dsth->mutex_dlist_add_remove ); - return; - } - - log_it( L_DEBUG, "KILL %u socket! [ thread %u ]", dcr->socket, dcr->tn ); - - dcr->kill_signal = true; - - DL_LIST_ADD_NODE_HEAD( dsth->dap_clients_to_kill, dcr, kprev, knext, dsth->to_kill_count ); - pthread_mutex_unlock( &dsth->mutex_dlist_add_remove ); - - return; -} - -/* -========================================================= - dap_server_add_socket( ) - -========================================================= -*/ -dap_client_remote_t *dap_server_add_socket( int32_t fd, int32_t forced_thread_n ) -{ - uint32_t tn = (forced_thread_n == -1) ? get_thread_index_min_connections( ) : forced_thread_n; - dap_server_thread_t *dsth = &dap_server_threads[ tn ]; - dap_client_remote_t *dcr = dap_client_remote_create( _current_run_server, fd, dsth ); - - if ( !dcr ) { - log_it( L_ERROR, "accept %d dap_client_remote_create() == NULL", fd ); -// pthread_mutex_unlock( &dsth->mutex_dlist_add_remove ); - return dcr; - } - - log_it( L_DEBUG, "accept %d Client, thread %d", fd, tn ); - - pthread_mutex_lock( &dsth->mutex_dlist_add_remove ); - - DL_APPEND( dsth->dap_remote_clients, dcr ); - dsth->connections_count ++; - if ( epoll_ctl( dsth->epoll_fd, EPOLL_CTL_ADD, fd, &dcr->pevent) != 0 ) { - log_it( L_ERROR, "epoll_ctl failed 005" ); - } - pthread_mutex_unlock( &dsth->mutex_dlist_add_remove ); - - return dcr; -} - -/* -========================================================= - dap_server_remove_socket( ) - -========================================================= -*/ -void dap_server_remove_socket( dap_client_remote_t *dcr ) -{ - if ( !dcr ) { - log_it( L_ERROR, "dap_server_remove_socket( NULL )" ); - return; - } - - uint32_t tn = dcr->tn; - log_it( L_DEBUG, "dap_server_remove_socket %u thread %u", dcr->socket, tn ); - - dap_server_thread_t *dsth = &dap_server_threads[ tn ]; - - if ( epoll_ctl( dcr->efd, EPOLL_CTL_DEL, dcr->socket, &dcr->pevent ) == -1 ) - log_it( L_ERROR,"Can't remove event socket's handler from the epoll_fd" ); - -// pthread_mutex_lock( &dsth->mutex_dlist_add_remove ); - DL_DELETE( dsth->dap_remote_clients, dcr ); - dsth->connections_count --; - -// pthread_mutex_unlock( &dsth->mutex_dlist_add_remove ); - - log_it( L_DEBUG, "dcr = %X", dcr ); -} - -static void s_socket_all_check_activity( uint32_t tn, time_t cur_time ) -{ - dap_client_remote_t *dcr, *tmp; - dap_server_thread_t *dsth = &dap_server_threads[ tn ]; - -// log_it( L_INFO,"s_socket_info_all_check_activity() on thread %u", tn ); - - pthread_mutex_lock( &dsth->mutex_dlist_add_remove ); - - DL_FOREACH_SAFE( dsth->dap_remote_clients, dcr, tmp ) { - - if ( !dcr->kill_signal && cur_time >= dcr->last_time_active + SOCKET_TIMEOUT_TIME && !dcr->close_denied ) { - - log_it( L_INFO, "Socket %u timeout, closing...", dcr->socket ); - - if ( epoll_ctl( dcr->efd, EPOLL_CTL_DEL, dcr->socket, &dcr->pevent ) == -1 ) - log_it( L_ERROR,"Can't remove event socket's handler from the epoll_fd" ); - - DL_DELETE( dsth->dap_remote_clients, dcr ); - dsth->connections_count --; - - dap_client_remote_remove( dcr, _current_run_server ); - } - } - pthread_mutex_unlock( &dsth->mutex_dlist_add_remove ); -} - -/* -========================================================= - read_write_cb( ) - -========================================================= -*/ -static void read_write_cb( dap_client_remote_t *dap_cur, int32_t revents ) -{ -// log_it( L_NOTICE, "[THREAD %u] read_write_cb fd %u revents %u", dap_cur->tn, dap_cur->socket, revents ); -// sleep( 5 ); // ????????? - - if( !dap_cur ) { - - log_it( L_ERROR, "read_write_cb: dap_client_remote NULL" ); - return; - } - - if ( revents & EPOLLIN ) { - -// log_it( L_DEBUG, "[THREAD %u] socket read %d ", dap_cur->tn, dap_cur->socket ); - - int32_t bytes_read = recv( dap_cur->socket, - dap_cur->buf_in + dap_cur->buf_in_size, - sizeof(dap_cur->buf_in) - dap_cur->buf_in_size, - 0 ); - if ( bytes_read > 0 ) { -// log_it( L_DEBUG, "[THREAD %u] read %u socket client said: %s", dap_cur->tn, bytes_read, dap_cur->buf_in + dap_cur->buf_in_size ); - - dap_cur->buf_in_size += (size_t)bytes_read; - dap_cur->upload_stat.buf_size_total += (size_t)bytes_read; - -// log_it( L_DEBUG, "[THREAD %u] read %u socket read callback()", dap_cur->tn, bytes_read ); - _current_run_server->client_read_callback( dap_cur ,NULL ); - } - else if ( bytes_read < 0 ) { - log_it( L_ERROR,"Bytes read Error %s",strerror(errno) ); - if ( strcmp(strerror(errno),"Resource temporarily unavailable") != 0 ) - dap_cur->flags |= DAP_SOCK_SIGNAL_CLOSE; - } - else { // bytes_read == 0 - dap_cur->flags |= DAP_SOCK_SIGNAL_CLOSE; - log_it( L_DEBUG, "0 bytes read" ); - } - } - - if( ( (revents & EPOLLOUT) || (dap_cur->flags & DAP_SOCK_READY_TO_WRITE) ) && !(dap_cur->flags & DAP_SOCK_SIGNAL_CLOSE) ) { - -// log_it(L_DEBUG, "[THREAD %u] socket write %d ", dap_cur->tn, dap_cur->socket ); - _current_run_server->client_write_callback( dap_cur, NULL ); // Call callback to process write event - - if( dap_cur->buf_out_size == 0 ) { - log_it(L_DEBUG, "dap_cur->buf_out_size = 0, set ev_read watcher " ); - - dap_cur->pevent.events = EPOLLIN | EPOLLERR; - if( epoll_ctl(dap_cur->efd, EPOLL_CTL_MOD, dap_cur->socket, &dap_cur->pevent) != 0 ) { - log_it( L_ERROR, "epoll_ctl failed 003" ); - } - } - else { -// log_it(L_DEBUG, "[THREAD %u] send dap_cur->buf_out_size = %u , %s", dap_cur->tn, dap_cur->buf_out_size, dap_cur->buf_out ); - - size_t total_sent = dap_cur->buf_out_offset; - - while ( total_sent < dap_cur->buf_out_size ) { - //log_it(DEBUG, "Output: %u from %u bytes are sent ", total_sent, dap_cur->buf_out_size); - ssize_t bytes_sent = send( dap_cur->socket, - dap_cur->buf_out + total_sent, - dap_cur->buf_out_size - total_sent, - MSG_DONTWAIT | MSG_NOSIGNAL ); - if( bytes_sent < 0 ) { - log_it(L_ERROR,"[THREAD %u] Error occured in send() function %s", dap_cur->tn, strerror(errno) ); - dap_cur->flags |= DAP_SOCK_SIGNAL_CLOSE; - break; - } - - total_sent += (size_t)bytes_sent; - dap_cur->download_stat.buf_size_total += (size_t)bytes_sent; - } - -// log_it( L_ERROR, "check !" ); - - if( total_sent == dap_cur->buf_out_size ) { - dap_cur->buf_out_offset = dap_cur->buf_out_size = 0; - } - else { - dap_cur->buf_out_offset = total_sent; - } - } // else - } // write - - -// log_it(L_ERROR,"OPA !") ; -// Sleep(200); - -// if ( (dap_cur->flags & DAP_SOCK_SIGNAL_CLOSE) && !dap_cur->close_denied ) { -// log_it(L_ERROR,"Close signal" ); - -// dap_server_remove_socket( dap_cur ); -// dap_client_remote_remove( dap_cur, _current_run_server ); -// } - -} - - -/* -========================================================= - dap_server_listen( ) - - Create server_t instance and start to listen tcp port with selected address - -========================================================= -*/ -dap_server_t *dap_server_listen( const char *addr, uint16_t port, dap_server_type_t type ) -{ - dap_server_t* sh = dap_server_new( ); - - sh->socket_listener = -111; - - if( type == DAP_SERVER_TCP ) - sh->socket_listener = socket( AF_INET, SOCK_STREAM, 0 ); - else { - dap_server_delete( sh ); - return NULL; - } - - if ( set_nonblock_socket(sh->socket_listener) == -1 ) { - log_it( L_WARNING, "error server socket nonblock" ); - dap_server_delete( sh ); - return NULL; - } - - if ( sh->socket_listener < 0 ) { - log_it ( L_ERROR,"Socket error %s", strerror(errno) ); - dap_server_delete( sh ); - return NULL; - } - - log_it( L_NOTICE," Socket created..." ); - - int32_t reuse = 1; - - if ( reuse ) - if ( setsockopt( sh->socket_listener, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0 ) - log_it( L_WARNING, "Can't set up REUSEADDR flag to the socket" ); - - sh->listener_addr.sin_family = AF_INET; - sh->listener_addr.sin_port = htons( port ); - inet_pton( AF_INET, addr, &(sh->listener_addr.sin_addr) ); - - if( bind(sh->socket_listener, (struct sockaddr *)&(sh->listener_addr), sizeof(sh->listener_addr)) < 0 ) { - log_it( L_ERROR,"Bind error: %s",strerror(errno) ); - dap_server_delete( sh ); - return NULL; - } - - log_it( L_INFO,"Binded %s:%u", addr, port ); - listen( sh->socket_listener, DAP_MAX_THREAD_EVENTS * _count_threads ); - - log_it( L_INFO,"pthread_mutex_init" ); - pthread_mutex_init( &sh->mutex_on_hash, NULL ); - - return sh; -} - - -/* -========================================================= - thread_loop( ) - - Server listener thread loop -========================================================= -*/ -void *thread_loop( void *arg ) -{ - dap_client_remote_t *dap_cur, *tmp; - dap_server_thread_t *dsth = (dap_server_thread_t *)arg; - uint32_t tn = dsth->thread_num; - EPOLL_HANDLE efd = dsth->epoll_fd; - struct epoll_event *events = dsth->epoll_events; - time_t next_time_timeout_check = time( NULL ) + SOCKETS_TIMEOUT_CHECK_PERIOD; - - log_it(L_NOTICE, "Start loop listener socket thread %u efd %u", tn, efd ); - - #ifndef _WIN32 - cpu_set_t mask; - CPU_ZERO( &mask ); - CPU_SET( tn, &mask ); - - if ( pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &mask) != 0 ) { - log_it( L_CRITICAL, "Error pthread_setaffinity_np() You really have %d or more core in CPU?", tn ); - abort(); - } - #else - - if ( !SetThreadAffinityMask( GetCurrentThread(), (DWORD_PTR)(1 << tn) ) ) { - log_it( L_CRITICAL, "Error pthread_setaffinity_np() You really have %d or more core in CPU?", tn ); - abort(); - } - - #endif - - do { - - int32_t n = epoll_wait( efd, events, DAP_MAX_THREAD_EVENTS, 1000 ); - -// log_it(L_WARNING,"[THREAD %u] epoll events %u", tn, n ); -// Sleep(300); - - if ( n == -1 || bQuitSignal ) - break; - - time_t cur_time = time( NULL ); - - for ( int32_t i = 0; i < n; ++ i ) { - -// log_it(L_ERROR,"[THREAD %u] process epoll event %u", tn, i ); - dap_cur = (dap_client_remote_t *)events[i].data.ptr; - - if ( !dap_cur ) { - log_it( L_ERROR,"dap_client_remote_t NULL" ); - continue; - } - - dap_cur->last_time_active = cur_time; - - if( events[i].events & EPOLLERR ) { - log_it( L_ERROR,"Socket error: %u, remove it" , dap_cur->socket ); - dap_cur->flags |= DAP_SOCK_SIGNAL_CLOSE; - } - - if ( !(dap_cur->flags & DAP_SOCK_SIGNAL_CLOSE) || dap_cur->close_denied ) - read_write_cb( dap_cur, events[i].events ); - - if ( (dap_cur->flags & DAP_SOCK_SIGNAL_CLOSE) && !dap_cur->close_denied ) { - - pthread_mutex_lock( &dsth->mutex_dlist_add_remove ); - - if ( dap_cur->kill_signal ) { - pthread_mutex_unlock( &dsth->mutex_dlist_add_remove ); - continue; - } - -// pthread_mutex_unlock( &dsth->mutex_dlist_add_remove ); -// dap_server_kill_socket( dap_cur ); -// continue; - - log_it( L_INFO, "Got signal to close %u socket, closing...[ %u ]", dap_cur->socket, tn ); - - dap_server_remove_socket( dap_cur ); - dap_client_remote_remove( dap_cur, _current_run_server ); - - log_it( L_INFO, "[ Thread %u ] coneections: %u, to kill: %u", tn, dsth->connections_count, dsth->to_kill_count ); - pthread_mutex_unlock( &dsth->mutex_dlist_add_remove ); - } - - } // for - - if ( cur_time >= next_time_timeout_check ) { - - s_socket_all_check_activity( tn, cur_time ); - next_time_timeout_check = cur_time + SOCKETS_TIMEOUT_CHECK_PERIOD; - } - - pthread_mutex_lock( &dsth->mutex_dlist_add_remove ); - if ( !dsth->to_kill_count ) { - - pthread_mutex_unlock( &dsth->mutex_dlist_add_remove ); - continue; - } - - dap_cur = dsth->dap_clients_to_kill; - - do { - - if ( dap_cur->close_denied ) { - dap_cur = dap_cur->knext; - continue; - } - - log_it( L_INFO, "Kill %u socket ...............[ thread %u ]", dap_cur->socket, tn ); - - tmp = dap_cur->knext; - DL_LIST_REMOVE_NODE( dsth->dap_clients_to_kill, dap_cur, kprev, knext, dsth->to_kill_count ); - - dap_server_remove_socket( dap_cur ); - dap_client_remote_remove( dap_cur, _current_run_server ); - dap_cur = tmp; - - } while ( dap_cur ); - - log_it( L_INFO, "[ Thread %u ] coneections: %u, to kill: %u", tn, dsth->connections_count, dsth->to_kill_count ); - pthread_mutex_unlock( &dsth->mutex_dlist_add_remove ); - - } while( !bQuitSignal ); - - return NULL; -} - -/* -========================================================= - dap_server_loop( ) - - Main server loop - - @param a_server Server instance - @return Zero if ok others if not -========================================================= -*/ -int32_t dap_server_loop( dap_server_t *d_server ) -{ - static uint32_t pickthread = 0; // just for test - pthread_t thread_listener[ DAP_MAX_THREADS ]; - - if ( !d_server ) return 1; - - for( uint32_t i = 0; i < _count_threads; ++i ) { - - EPOLL_HANDLE efd = epoll_create1( 0 ); -// log_it( L_ERROR, "EPOLL_HANDLE efd %u for thread %u created", efd, i ); - if ( (intptr_t)efd == -1 ) { - log_it( L_ERROR, "Server wakeup no events / error" ); - goto error; - } - dap_server_threads[ i ].epoll_fd = efd; - dap_server_threads[ i ].thread_num = i; - } - - for( uint32_t i = 0; i < _count_threads; ++i ) { - pthread_create( &thread_listener[i], NULL, thread_loop, &dap_server_threads[i] ); - } - - _current_run_server = d_server; - - EPOLL_HANDLE efd = epoll_create1( 0 ); - if ( (intptr_t)efd == -1 ) - goto error; - - struct epoll_event pev; - struct epoll_event events[ 16 ]; - - memset(&pev, 0, sizeof(struct epoll_event)); - pev.events = EPOLLIN | EPOLLERR; - pev.data.fd = d_server->socket_listener; - - if( epoll_ctl( efd, EPOLL_CTL_ADD, d_server->socket_listener, &pev) != 0 ) { - log_it( L_ERROR, "epoll_ctl failed 004" ); - goto error; - } - - while( 1 ) { - - int32_t n = epoll_wait( efd, &events[0], 16, -1 ); - - if ( n <= 0 ) { - if(errno == EINTR) - continue; - log_it( L_ERROR, "Server wakeup no events / error" ); - break; - } - for( int32_t i = 0; i < n; ++ i ) { - - if ( events[i].events & EPOLLIN ) { - - int client_fd = accept( events[i].data.fd, 0, 0 ); - - if ( client_fd < 0 ) { - log_it( L_ERROR, "accept_cb: error accept socket"); - continue; - } - - set_nonblock_socket( client_fd ); - dap_server_add_socket( client_fd, -1 ); - } - else if( events[i].events & EPOLLERR ) { - log_it( L_ERROR, "Server socket error event" ); - goto exit; - } - - } // for - - } // while - -exit:; - - #ifndef _WIN32 - close( efd ); - #else - epoll_close( efd ); - #endif -error:; - - bQuitSignal = true; - - for( uint32_t i = 0; i < _count_threads; ++i ) { - if ( (intptr_t)dap_server_threads[ i ].epoll_fd != -1 ) { - #ifndef _WIN32 - close( dap_server_threads[ i ].epoll_fd ); - #else - epoll_close( dap_server_threads[ i ].epoll_fd ); - #endif - } - } - - return 0; -} +/* + Copyright (c) 2017-2018 (c) Project "DeM Labs Inc" https://github.com/demlabsinc + 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 Lesser 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with any DAP based project. If not, see <http://www.gnu.org/licenses/>. +*/ + +#define __USE_GNU + +#include <string.h> +#include <time.h> +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <stdint.h> + +//#include <errno.h> +#include <signal.h> +#include <stdint.h> +#include <stdatomic.h> + +#ifndef _WIN32 +#include <arpa/inet.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/select.h> +#include <errno.h> +#include <netdb.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/epoll.h> +#include <sys/timerfd.h> +#else +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0600 +#include <winsock2.h> +#include <windows.h> +#include <mswsock.h> +#include <ws2tcpip.h> +#include <io.h> +#include "wrappers.h" +#include <wepoll.h> +#include <pthread.h> +#endif + +#include <sched.h> + +#if 0 +#define NI_NUMERICHOST 1 /* Don't try to look up hostname. */ +#define NI_NUMERICSERV 2 /* Don't convert port number to name. */ +#define NI_NOFQDN 4 /* Only return nodename portion. */ +#define NI_NAMEREQD 8 /* Don't return numeric addresses. */ +#define NI_DGRAM 16 /* Look up UDP service rather than TCP. */ +#endif + +#include "dap_common.h" +#include "dap_server.h" + +#define LOG_TAG "server" + +#define DAP_MAX_THREAD_EVENTS 8192 +#define DAP_MAX_THREADS 16 + +#define SOCKET_TIMEOUT_TIME 30 +#define SOCKETS_TIMEOUT_CHECK_PERIOD 15 + +static uint32_t _count_threads = 0; +static uint32_t epoll_max_events = 0; +static bool bQuitSignal = false; + +static struct epoll_event *threads_epoll_events = NULL; +static dap_server_t *_current_run_server = NULL; + +static void read_write_cb( dap_client_remote_t *dap_cur, int32_t revents ); + +dap_server_thread_t dap_server_threads[ DAP_MAX_THREADS ]; + +/* +=============================================== + get_epoll_max_user_watches( ) + + return max epoll() event watches +=============================================== +*/ +static uint32_t get_epoll_max_user_watches( void ) +{ + static const char *maxepollpath = "/proc/sys/fs/epoll/max_user_watches"; + uint32_t v = 0, len; + char str[32]; + + FILE *fp = fopen( maxepollpath, "r" ); + if ( !fp ) { + printf("can't open %s\n", maxepollpath ); + return v; + } + + len = fread( &str[0], 1, 31, fp ); + if ( !len ) { + return v; + } + + str[ len ] = 0; + v = atoi( str ); + + return v; +} + +/* +=============================================== + dap_server_init( ) + + Init server module + return Zero if ok others if no +=============================================== +*/ +int32_t dap_server_init( uint32_t count_threads ) +{ + dap_server_thread_t *dap_thread; + + #ifndef _WIN32 + signal( SIGPIPE, SIG_IGN ); + #endif + + if ( count_threads > DAP_MAX_THREADS ) + count_threads = DAP_MAX_THREADS; + + _count_threads = count_threads; + log_it( L_NOTICE, "dap_server_init() threads %u", count_threads ); + + epoll_max_events = get_epoll_max_user_watches( ); + if ( epoll_max_events > DAP_MAX_THREAD_EVENTS ) + epoll_max_events = DAP_MAX_THREAD_EVENTS; + + threads_epoll_events = (struct epoll_event *)malloc( sizeof(struct epoll_event) * _count_threads * epoll_max_events ); + if ( !threads_epoll_events ) + goto err; + + memset( threads_epoll_events, 0, sizeof(struct epoll_event) * _count_threads * epoll_max_events ); + + dap_thread = &dap_server_threads[0]; + memset( dap_thread, 0, sizeof(dap_server_thread_t) * DAP_MAX_THREADS ); + + for ( uint32_t i = 0; i < _count_threads; ++i, ++dap_thread ) { + #ifndef _WIN32 + dap_thread->epoll_fd = -1; + #else + dap_thread->epoll_fd = (void*)-1; + #endif + dap_thread->thread_num = i; + dap_thread->epoll_events = &threads_epoll_events[ i * epoll_max_events ]; + + pthread_mutex_init( &dap_thread->mutex_dlist_add_remove, NULL ); + pthread_mutex_init( &dap_thread->mutex_on_hash, NULL ); + } + + log_it( L_NOTICE, "Initialized socket server module" ); + + dap_client_remote_init( ); + return 0; + +err:; + + dap_server_deinit( ); + return 1; +} + +/* +========================================================= + dap_server_deinit( ) + + Deinit server module +========================================================= +*/ +void dap_server_deinit( void ) +{ + dap_client_remote_t *dap_cur, *tmp; + dap_server_thread_t *t = &dap_server_threads[0]; + + dap_client_remote_deinit( ); + + if ( threads_epoll_events ) { + free( threads_epoll_events ); + + for ( uint32_t i = 0; i < _count_threads; ++i, ++t ) { + + HASH_ITER( hh, t->hclients, dap_cur, tmp ) + dap_client_remote_remove( dap_cur ); + + pthread_mutex_destroy( &dap_server_threads[i].mutex_on_hash ); + pthread_mutex_destroy( &dap_server_threads[i].mutex_dlist_add_remove ); + } + } +} + +/* +========================================================= + dap_server_new( ) + + Creates new empty instance of dap_server_t +========================================================= +*/ +dap_server_t *dap_server_new( void ) +{ + return (dap_server_t *)calloc( 1, sizeof(dap_server_t) ); +} + +/* +========================================================= + dap_server_new( ) + + Delete server instance +========================================================= +*/ +void dap_server_delete( dap_server_t *sh ) +{ + if ( !sh ) return; + + if( sh->address ) + free( sh->address ); + + if( sh->server_delete_callback ) + sh->server_delete_callback( sh, NULL ); + + if ( sh->_inheritor ) + free( sh->_inheritor ); + + free( sh ); +} + +/* +========================================================= + set_nonblock_socket( ) +========================================================= +*/ +int32_t set_nonblock_socket( int32_t fd ) +{ +#ifdef _WIN32 + unsigned long arg = 1; + return ioctlsocket( fd, FIONBIO, &arg ); +#else + int32_t flags; + + flags = fcntl( fd, F_GETFL ); + flags |= O_NONBLOCK; + + return fcntl( fd, F_SETFL, flags ); +#endif +} + + +/* +========================================================= + get_thread_min_connections( ) + + return number thread which has minimum open connections +========================================================= +*/ +static inline uint32_t get_thread_index_min_connections( ) +{ + uint32_t min = 0; + + for( uint32_t i = 1; i < _count_threads; i ++ ) { + if ( dap_server_threads[min].connections_count > dap_server_threads[i].connections_count ) { + min = i; + } + } + + return min; +} + +/* +========================================================= + print_online( ) + +========================================================= +*/ +static inline void print_online() +{ + for( uint32_t i = 0; i < _count_threads; i ++ ) { + log_it( L_INFO, "Thread number: %u, count: %u", i, dap_server_threads[i].connections_count ); + } +} + +void dap_server_kill_socket( dap_client_remote_t *dcr ) +{ + if ( !dcr ) { + log_it( L_ERROR, "dap_server_kill_socket( NULL )" ); + return; + } + + dap_server_thread_t *dsth = &dap_server_threads[ dcr->tn ]; + + pthread_mutex_lock( &dsth->mutex_dlist_add_remove ); + + if ( dcr->kill_signal ) { + pthread_mutex_unlock( &dsth->mutex_dlist_add_remove ); + return; + } + + log_it( L_DEBUG, "KILL %u socket! [ thread %u ]", dcr->socket, dcr->tn ); + + dcr->kill_signal = true; + + DL_LIST_ADD_NODE_HEAD( dsth->dap_clients_to_kill, dcr, kprev, knext, dsth->to_kill_count ); + pthread_mutex_unlock( &dsth->mutex_dlist_add_remove ); + + return; +} + +/* +========================================================= + dap_server_add_socket( ) + +========================================================= +*/ +dap_client_remote_t *dap_server_add_socket( int32_t fd, int32_t forced_thread_n ) +{ + uint32_t tn = (forced_thread_n == -1) ? get_thread_index_min_connections( ) : forced_thread_n; + dap_server_thread_t *dsth = &dap_server_threads[ tn ]; + dap_client_remote_t *dcr = dap_client_remote_create( _current_run_server, fd, dsth ); + + if ( !dcr ) { + log_it( L_ERROR, "accept %d dap_client_remote_create() == NULL", fd ); +// pthread_mutex_unlock( &dsth->mutex_dlist_add_remove ); + return dcr; + } + + log_it( L_DEBUG, "accept %d Client, thread %d", fd, tn ); + + pthread_mutex_lock( &dsth->mutex_dlist_add_remove ); + + DL_APPEND( dsth->dap_remote_clients, dcr ); + dsth->connections_count ++; + if ( epoll_ctl( dsth->epoll_fd, EPOLL_CTL_ADD, fd, &dcr->pevent) != 0 ) { + log_it( L_ERROR, "epoll_ctl failed 005" ); + } + pthread_mutex_unlock( &dsth->mutex_dlist_add_remove ); + + return dcr; +} + +/* +========================================================= + dap_server_remove_socket( ) + +========================================================= +*/ +void dap_server_remove_socket( dap_client_remote_t *dcr ) +{ + if ( !dcr ) { + log_it( L_ERROR, "dap_server_remove_socket( NULL )" ); + return; + } + + uint32_t tn = dcr->tn; + log_it( L_DEBUG, "dap_server_remove_socket %u thread %u", dcr->socket, tn ); + + dap_server_thread_t *dsth = &dap_server_threads[ tn ]; + + if ( epoll_ctl( dcr->efd, EPOLL_CTL_DEL, dcr->socket, &dcr->pevent ) == -1 ) + log_it( L_ERROR,"Can't remove event socket's handler from the epoll_fd" ); + +// pthread_mutex_lock( &dsth->mutex_dlist_add_remove ); + DL_DELETE( dsth->dap_remote_clients, dcr ); + dsth->connections_count --; + +// pthread_mutex_unlock( &dsth->mutex_dlist_add_remove ); + + log_it( L_DEBUG, "dcr = %X", dcr ); +} + +static void s_socket_all_check_activity( uint32_t tn, time_t cur_time ) +{ + dap_client_remote_t *dcr, *tmp; + dap_server_thread_t *dsth = &dap_server_threads[ tn ]; + +// log_it( L_INFO,"s_socket_info_all_check_activity() on thread %u", tn ); + + pthread_mutex_lock( &dsth->mutex_dlist_add_remove ); + + DL_FOREACH_SAFE( dsth->dap_remote_clients, dcr, tmp ) { + + if ( !dcr->kill_signal && cur_time >= dcr->last_time_active + SOCKET_TIMEOUT_TIME && !dcr->no_close ) { + + log_it( L_INFO, "Socket %u timeout, closing...", dcr->socket ); + + if ( epoll_ctl( dcr->efd, EPOLL_CTL_DEL, dcr->socket, &dcr->pevent ) == -1 ) + log_it( L_ERROR,"Can't remove event socket's handler from the epoll_fd" ); + + DL_DELETE( dsth->dap_remote_clients, dcr ); + dsth->connections_count --; + + dap_client_remote_remove( dcr ); + } + } + pthread_mutex_unlock( &dsth->mutex_dlist_add_remove ); +} + +/* +========================================================= + read_write_cb( ) + +========================================================= +*/ +static void read_write_cb( dap_client_remote_t *dap_cur, int32_t revents ) +{ +// log_it( L_NOTICE, "[THREAD %u] read_write_cb fd %u revents %u", dap_cur->tn, dap_cur->socket, revents ); +// sleep( 5 ); // ????????? + + if( !dap_cur ) { + + log_it( L_ERROR, "read_write_cb: dap_client_remote NULL" ); + return; + } + + if ( revents & EPOLLIN ) { + +// log_it( L_DEBUG, "[THREAD %u] socket read %d ", dap_cur->tn, dap_cur->socket ); + + int32_t bytes_read = recv( dap_cur->socket, + dap_cur->buf_in + dap_cur->buf_in_size, + sizeof(dap_cur->buf_in) - dap_cur->buf_in_size, + 0 ); + if ( bytes_read > 0 ) { +// log_it( L_DEBUG, "[THREAD %u] read %u socket client said: %s", dap_cur->tn, bytes_read, dap_cur->buf_in + dap_cur->buf_in_size ); + + dap_cur->buf_in_size += (size_t)bytes_read; + dap_cur->upload_stat.buf_size_total += (size_t)bytes_read; + +// log_it( L_DEBUG, "[THREAD %u] read %u socket read callback()", dap_cur->tn, bytes_read ); + _current_run_server->client_read_callback( dap_cur ,NULL ); + } + else if ( bytes_read < 0 ) { + log_it( L_ERROR,"Bytes read Error %s",strerror(errno) ); + if ( strcmp(strerror(errno),"Resource temporarily unavailable") != 0 ) + dap_cur->flags |= DAP_SOCK_SIGNAL_CLOSE; + } + else { // bytes_read == 0 + dap_cur->flags |= DAP_SOCK_SIGNAL_CLOSE; + log_it( L_DEBUG, "0 bytes read" ); + } + } + + if( ( (revents & EPOLLOUT) || (dap_cur->flags & DAP_SOCK_READY_TO_WRITE) ) && !(dap_cur->flags & DAP_SOCK_SIGNAL_CLOSE) ) { + +// log_it(L_DEBUG, "[THREAD %u] socket write %d ", dap_cur->tn, dap_cur->socket ); + _current_run_server->client_write_callback( dap_cur, NULL ); // Call callback to process write event + + if( dap_cur->buf_out_size == 0 ) { + log_it(L_DEBUG, "dap_cur->buf_out_size = 0, set ev_read watcher " ); + + dap_cur->pevent.events = EPOLLIN | EPOLLERR; + if( epoll_ctl(dap_cur->efd, EPOLL_CTL_MOD, dap_cur->socket, &dap_cur->pevent) != 0 ) { + log_it( L_ERROR, "epoll_ctl failed 003" ); + } + } + else { +// log_it(L_DEBUG, "[THREAD %u] send dap_cur->buf_out_size = %u , %s", dap_cur->tn, dap_cur->buf_out_size, dap_cur->buf_out ); + + size_t total_sent = dap_cur->buf_out_offset; + + while ( total_sent < dap_cur->buf_out_size ) { + //log_it(DEBUG, "Output: %u from %u bytes are sent ", total_sent, dap_cur->buf_out_size); + ssize_t bytes_sent = send( dap_cur->socket, + dap_cur->buf_out + total_sent, + dap_cur->buf_out_size - total_sent, + MSG_DONTWAIT | MSG_NOSIGNAL ); + if( bytes_sent < 0 ) { + log_it(L_ERROR,"[THREAD %u] Error occured in send() function %s", dap_cur->tn, strerror(errno) ); + dap_cur->flags |= DAP_SOCK_SIGNAL_CLOSE; + break; + } + + total_sent += (size_t)bytes_sent; + dap_cur->download_stat.buf_size_total += (size_t)bytes_sent; + } + +// log_it( L_ERROR, "check !" ); + + if( total_sent == dap_cur->buf_out_size ) { + dap_cur->buf_out_offset = dap_cur->buf_out_size = 0; + } + else { + dap_cur->buf_out_offset = total_sent; + } + } // else + } // write + + +// log_it(L_ERROR,"OPA !") ; +// Sleep(200); + +// if ( (dap_cur->flags & DAP_SOCK_SIGNAL_CLOSE) && !dap_cur->no_close ) { +// log_it(L_ERROR,"Close signal" ); + +// dap_server_remove_socket( dap_cur ); +// dap_client_remote_remove( dap_cur, _current_run_server ); +// } + +} + + +/* +========================================================= + dap_server_listen( ) + + Create server_t instance and start to listen tcp port with selected address + +========================================================= +*/ +dap_server_t *dap_server_listen( const char *addr, uint16_t port, dap_server_type_t type ) +{ + dap_server_t* sh = dap_server_new( ); + + sh->socket_listener = -111; + + if( type == DAP_SERVER_TCP ) + sh->socket_listener = socket( AF_INET, SOCK_STREAM, 0 ); + else { + dap_server_delete( sh ); + return NULL; + } + + if ( set_nonblock_socket(sh->socket_listener) == -1 ) { + log_it( L_WARNING, "error server socket nonblock" ); + dap_server_delete( sh ); + return NULL; + } + + if ( sh->socket_listener < 0 ) { + log_it ( L_ERROR,"Socket error %s", strerror(errno) ); + dap_server_delete( sh ); + return NULL; + } + + log_it( L_NOTICE," Socket created..." ); + + int32_t reuse = 1; + + if ( reuse ) + if ( setsockopt( sh->socket_listener, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0 ) + log_it( L_WARNING, "Can't set up REUSEADDR flag to the socket" ); + + sh->listener_addr.sin_family = AF_INET; + sh->listener_addr.sin_port = htons( port ); + inet_pton( AF_INET, addr, &(sh->listener_addr.sin_addr) ); + + if( bind(sh->socket_listener, (struct sockaddr *)&(sh->listener_addr), sizeof(sh->listener_addr)) < 0 ) { + log_it( L_ERROR,"Bind error: %s",strerror(errno) ); + dap_server_delete( sh ); + return NULL; + } + + log_it( L_INFO,"Binded %s:%u", addr, port ); + listen( sh->socket_listener, DAP_MAX_THREAD_EVENTS * _count_threads ); + + return sh; +} + + +/* +========================================================= + thread_loop( ) + + Server listener thread loop +========================================================= +*/ +void *thread_loop( void *arg ) +{ + dap_client_remote_t *dap_cur, *tmp; + dap_server_thread_t *dsth = (dap_server_thread_t *)arg; + uint32_t tn = dsth->thread_num; + EPOLL_HANDLE efd = dsth->epoll_fd; + struct epoll_event *events = dsth->epoll_events; + time_t next_time_timeout_check = time( NULL ) + SOCKETS_TIMEOUT_CHECK_PERIOD; + + log_it(L_NOTICE, "Start loop listener socket thread %u efd %u", tn, efd ); + + #ifndef _WIN32 + cpu_set_t mask; + CPU_ZERO( &mask ); + CPU_SET( tn, &mask ); + + if ( pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &mask) != 0 ) { + log_it( L_CRITICAL, "Error pthread_setaffinity_np() You really have %d or more core in CPU?", tn ); + abort(); + } + #else + + if ( !SetThreadAffinityMask( GetCurrentThread(), (DWORD_PTR)(1 << tn) ) ) { + log_it( L_CRITICAL, "Error pthread_setaffinity_np() You really have %d or more core in CPU?", tn ); + abort(); + } + + #endif + + do { + + int32_t n = epoll_wait( efd, events, DAP_MAX_THREAD_EVENTS, 1000 ); + +// log_it(L_WARNING,"[THREAD %u] epoll events %u", tn, n ); +// Sleep(300); + + if ( bQuitSignal ) + break; + + if ( n < 0 ) { + if ( errno == EINTR ) + continue; + break; + } + + time_t cur_time = time( NULL ); + + for ( int32_t i = 0; i < n; ++ i ) { + +// log_it(L_ERROR,"[THREAD %u] process epoll event %u", tn, i ); + dap_cur = (dap_client_remote_t *)events[i].data.ptr; + + if ( !dap_cur ) { + log_it( L_ERROR,"dap_client_remote_t NULL" ); + continue; + } + + dap_cur->last_time_active = cur_time; + + if( events[i].events & EPOLLERR ) { + log_it( L_ERROR,"Socket error: %u, remove it" , dap_cur->socket ); + dap_cur->flags |= DAP_SOCK_SIGNAL_CLOSE; + } + + if ( !(dap_cur->flags & DAP_SOCK_SIGNAL_CLOSE) || dap_cur->no_close ) + read_write_cb( dap_cur, events[i].events ); + + if ( (dap_cur->flags & DAP_SOCK_SIGNAL_CLOSE) && !dap_cur->no_close ) { + + pthread_mutex_lock( &dsth->mutex_dlist_add_remove ); + + if ( dap_cur->kill_signal ) { + pthread_mutex_unlock( &dsth->mutex_dlist_add_remove ); + continue; + } + +// pthread_mutex_unlock( &dsth->mutex_dlist_add_remove ); +// dap_server_kill_socket( dap_cur ); +// continue; + + log_it( L_INFO, "Got signal to close %u socket, closing...[ %u ]", dap_cur->socket, tn ); + + dap_server_remove_socket( dap_cur ); + dap_client_remote_remove( dap_cur ); + + log_it( L_INFO, "[ Thread %u ] coneections: %u, to kill: %u", tn, dsth->connections_count, dsth->to_kill_count ); + pthread_mutex_unlock( &dsth->mutex_dlist_add_remove ); + } + + } // for + + if ( cur_time >= next_time_timeout_check ) { + + s_socket_all_check_activity( tn, cur_time ); + next_time_timeout_check = cur_time + SOCKETS_TIMEOUT_CHECK_PERIOD; + } + + pthread_mutex_lock( &dsth->mutex_dlist_add_remove ); + if ( !dsth->to_kill_count ) { + + pthread_mutex_unlock( &dsth->mutex_dlist_add_remove ); + continue; + } + + dap_cur = dsth->dap_clients_to_kill; + + do { + + if ( dap_cur->no_close ) { + dap_cur = dap_cur->knext; + continue; + } + + log_it( L_INFO, "Kill %u socket ...............[ thread %u ]", dap_cur->socket, tn ); + + tmp = dap_cur->knext; + DL_LIST_REMOVE_NODE( dsth->dap_clients_to_kill, dap_cur, kprev, knext, dsth->to_kill_count ); + + dap_server_remove_socket( dap_cur ); + dap_client_remote_remove( dap_cur ); + dap_cur = tmp; + + } while ( dap_cur ); + + log_it( L_INFO, "[ Thread %u ] coneections: %u, to kill: %u", tn, dsth->connections_count, dsth->to_kill_count ); + pthread_mutex_unlock( &dsth->mutex_dlist_add_remove ); + + } while( !bQuitSignal ); + + return NULL; +} + +/* +========================================================= + dap_server_loop( ) + + Main server loop + + @param a_server Server instance + @return Zero if ok others if not +========================================================= +*/ +int32_t dap_server_loop( dap_server_t *d_server ) +{ + static uint32_t pickthread = 0; // just for test + pthread_t thread_listener[ DAP_MAX_THREADS ]; + + if ( !d_server ) return 1; + + for( uint32_t i = 0; i < _count_threads; ++i ) { + + EPOLL_HANDLE efd = epoll_create1( 0 ); +// log_it( L_ERROR, "EPOLL_HANDLE efd %u for thread %u created", efd, i ); + if ( (intptr_t)efd == -1 ) { + log_it( L_ERROR, "Server wakeup no events / error" ); + goto error; + } + dap_server_threads[ i ].epoll_fd = efd; + dap_server_threads[ i ].thread_num = i; + } + + for( uint32_t i = 0; i < _count_threads; ++i ) { + pthread_create( &thread_listener[i], NULL, thread_loop, &dap_server_threads[i] ); + } + + _current_run_server = d_server; + + EPOLL_HANDLE efd = epoll_create1( 0 ); + if ( (intptr_t)efd == -1 ) + goto error; + + struct epoll_event pev; + struct epoll_event events[ 16 ]; + + pev.events = EPOLLIN | EPOLLERR; + pev.data.fd = d_server->socket_listener; + + if( epoll_ctl( efd, EPOLL_CTL_ADD, d_server->socket_listener, &pev) != 0 ) { + log_it( L_ERROR, "epoll_ctl failed 004" ); + goto error; + } + + while( !bQuitSignal ) { + + int32_t n = epoll_wait( efd, &events[0], 16, -1 ); + + if ( bQuitSignal ) + break; + + if ( n <= 0 ) { + if ( errno == EINTR ) + continue; + log_it( L_ERROR, "Server wakeup no events / error" ); + break; + } + + for( int32_t i = 0; i < n; ++ i ) { + + if ( events[i].events & EPOLLIN ) { + + int client_fd = accept( events[i].data.fd, 0, 0 ); + + if ( client_fd < 0 ) { + log_it( L_ERROR, "accept_cb: error accept socket"); + continue; + } + + set_nonblock_socket( client_fd ); + dap_server_add_socket( client_fd, -1 ); + } + else if( events[i].events & EPOLLERR ) { + log_it( L_ERROR, "Server socket error event" ); + goto exit; + } + + } // for + + } // while + +exit:; + + #ifndef _WIN32 + close( efd ); + #else + epoll_close( efd ); + #endif +error:; + + bQuitSignal = true; + + for( uint32_t i = 0; i < _count_threads; ++i ) { + if ( (intptr_t)dap_server_threads[ i ].epoll_fd != -1 ) { + #ifndef _WIN32 + close( dap_server_threads[ i ].epoll_fd ); + #else + epoll_close( dap_server_threads[ i ].epoll_fd ); + #endif + } + } + + return 0; +} diff --git a/src/dap_traffic_track.c b/src/dap_traffic_track.c index 6024833c3552dece12d5cfeac8c8aa738c878c4b..60e7822ab3ff1d1742745dcdf691827a047aabbf 100755 --- a/src/dap_traffic_track.c +++ b/src/dap_traffic_track.c @@ -1,230 +1,232 @@ -/* - * Authors: - * Anatoliy Kurotich <anatoliy.kurotich@demlabs.net> - * DeM Labs Inc. https://demlabs.net - * Kelvin Project https://github.com/kelvinblockchain - * Copyright (c) 2017-2018 - * 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 <string.h> -#include <time.h> -#include <stdio.h> -#include <stdlib.h> -#include <stddef.h> - -#ifndef _WIN32 -#include <pthread.h> -#include <ev.h> -#else -#undef _WIN32_WINNT -#define _WIN32_WINNT 0x0600 -#include <winsock2.h> -#include <windows.h> -#include <mswsock.h> -#include <ws2tcpip.h> -#include <io.h> -#include "wrappers.h" -#include <wepoll.h> -#include <pthread.h> -#endif - -#include "dap_traffic_track.h" -#include "dap_common.h" -#include "dap_cpu_monitor.h" - -#define LOG_TAG "dap_traffic_track" - -#define BITS_IN_BYTE 8 -#define ALLOC_STEP 100 - -static dap_traffic_callback_t _callback = NULL; -static dap_server_t *_dap_server; - -#ifndef _WIN32 -static ev_timer _timeout_watcher; -static struct ev_loop *loop; -#else -static HANDLE _timeout_watcher; -#endif -static size_t timertimeout = 1; - -static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t _cond = PTHREAD_COND_INITIALIZER; -static pthread_t worker_thread; -static bool _stop_worker_signal = false; - - -/** - * @brief calculate_mbits_speed - * @param count_bytes - * @details timeout we gots from _timeout_watcher.repeat - * @return mbit/second speed - */ -static double _calculate_mbits_speed( size_t count_bytes ) -{ - size_t bits_per_second = (count_bytes / timertimeout) * BITS_IN_BYTE; - // log_it(L_DEBUG, "TIMEOUT: %d, bits_per_second: %d mbits: %f", - // (size_t)_timeout_watcher.repeat, bits_per_second, bits_per_second / 1000000.0); - return (double)bits_per_second / 1000000.0; // convert to mbits -} - -void *_worker_run( void *a ) -{ - (void)a; - - pthread_mutex_lock( &_mutex ); - - while( true ) { - pthread_cond_wait( &_cond, &_mutex ); - if ( _stop_worker_signal ) { - log_it(L_INFO, "Dap traffic track worker stopped"); - _stop_worker_signal = false; - break; - } - _callback( _dap_server ); - } - - pthread_mutex_unlock( &_mutex ); - pthread_exit( NULL ); - - return NULL; -} - -void _worker_start( ) -{ - pthread_mutex_init( &_mutex, NULL ); - pthread_cond_init( &_cond, NULL ); - pthread_create( &worker_thread, NULL, _worker_run, NULL ); -} - -void _worker_stop() -{ - pthread_mutex_lock( &_mutex ); - _stop_worker_signal = true; - pthread_cond_signal( &_cond ); - pthread_mutex_unlock( &_mutex ); - - // wait for exit worker_thread - pthread_join( worker_thread, NULL ); - - pthread_mutex_destroy( &_mutex ); - pthread_cond_destroy( &_cond ); - _callback = NULL; -} - -#ifndef _WIN32 -static void _timeout_cb( ) -#else -VOID CALLBACK _timeout_cb( void *lpParameter, BOOL TimerOrWaitFired ) -#endif -{ - pthread_mutex_lock( &_dap_server->mutex_on_hash ); - - size_t count_users = HASH_COUNT(_dap_server->clients ); - - if ( count_users ) { -// size_t idx = 0; - dap_client_remote_t *dap_cur, *tmp; - HASH_ITER( hh, _dap_server->clients, dap_cur, tmp ) { - - dap_cur->upload_stat.speed_mbs = _calculate_mbits_speed( dap_cur->upload_stat.buf_size_total - - dap_cur->upload_stat.buf_size_total_old ); - - dap_cur->upload_stat.buf_size_total_old = dap_cur->upload_stat.buf_size_total; - - dap_cur->download_stat.speed_mbs = _calculate_mbits_speed( dap_cur->download_stat.buf_size_total - - dap_cur->download_stat.buf_size_total_old ); - - dap_cur->download_stat.buf_size_total_old = dap_cur->download_stat.buf_size_total; - -// idx ++; - } - } - - /* TODO find some better solution and place for this line */ - _dap_server->cpu_stats = dap_cpu_get_stats( ); - - pthread_mutex_unlock( &_dap_server->mutex_on_hash ); - - if ( _callback != NULL ) { - pthread_mutex_lock( &_mutex ); - pthread_cond_signal( &_cond ); - pthread_mutex_unlock( &_mutex ); - } -} - -void dap_traffic_track_init( dap_server_t * server, - time_t timeout ) -{ - dap_cpu_monitor_init( ); - - _dap_server = server; -#ifndef _WIN32 - _timeout_watcher.repeat = timeout; - - loop = EV_DEFAULT; - - ev_init( &_timeout_watcher, _timeout_cb ); - ev_timer_again( loop, &_timeout_watcher ); -#else - - timertimeout = timeout; - - CreateTimerQueueTimer( &_timeout_watcher, NULL, (WAITORTIMERCALLBACK)_timeout_cb, NULL, timertimeout, timertimeout, 0 ); - -#endif - - log_it(L_NOTICE, "Initialized traffic track module"); -} - -void dap_traffic_track_deinit() -{ - if ( _callback != NULL ) - _worker_stop(); - -#ifndef _WIN32 - ev_timer_stop( loop, &_timeout_watcher ); - ev_loop_destroy( loop ); -#else - DeleteTimerQueueTimer( NULL, _timeout_watcher, NULL ); -#endif - - log_it( L_NOTICE, "Deinitialized traffic track module" ); - dap_cpu_monitor_deinit( ); -} - -void dap_traffic_callback_stop() { - - if ( _callback == NULL ) { - log_it( L_WARNING, "worker not running" ); - return; - } - _worker_stop(); -} - -void dap_traffic_callback_set(dap_traffic_callback_t cb) -{ - if( _callback == NULL ) { - _callback = cb; - _worker_start(); - return; - } - - log_it( L_WARNING, "Callback already setted" ); -} +/* + * Authors: + * Anatoliy Kurotich <anatoliy.kurotich@demlabs.net> + * DeM Labs Inc. https://demlabs.net + * Kelvin Project https://github.com/kelvinblockchain + * Copyright (c) 2017-2018 + * 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 <string.h> +#include <time.h> +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> + +#ifndef _WIN32 +#include <pthread.h> +#include <ev.h> +#else +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0600 +#include <winsock2.h> +#include <windows.h> +#include <mswsock.h> +#include <ws2tcpip.h> +#include <io.h> +#include "wrappers.h" +#include <wepoll.h> +#include <pthread.h> +#endif + +#include "dap_traffic_track.h" +#include "dap_common.h" +#include "dap_cpu_monitor.h" + +#define LOG_TAG "dap_traffic_track" + +#define BITS_IN_BYTE 8 +#define ALLOC_STEP 100 + +static dap_traffic_callback_t _callback = NULL; +static dap_server_t *_dap_server; + +#ifndef _WIN32 +static ev_timer _timeout_watcher; +static struct ev_loop *loop; +#else +static HANDLE _timeout_watcher; +#endif +static size_t timertimeout = 1; + +static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t _cond = PTHREAD_COND_INITIALIZER; +static pthread_t worker_thread; +static bool _stop_worker_signal = false; + + +/** + * @brief calculate_mbits_speed + * @param count_bytes + * @details timeout we gots from _timeout_watcher.repeat + * @return mbit/second speed + */ +static double _calculate_mbits_speed( size_t count_bytes ) +{ + size_t bits_per_second = (count_bytes / timertimeout) * BITS_IN_BYTE; + // log_it(L_DEBUG, "TIMEOUT: %d, bits_per_second: %d mbits: %f", + // (size_t)_timeout_watcher.repeat, bits_per_second, bits_per_second / 1000000.0); + return (double)bits_per_second / 1000000.0; // convert to mbits +} + +void *_worker_run( void *a ) +{ + (void)a; + + pthread_mutex_lock( &_mutex ); + + while( true ) { + pthread_cond_wait( &_cond, &_mutex ); + if ( _stop_worker_signal ) { + log_it(L_INFO, "Dap traffic track worker stopped"); + _stop_worker_signal = false; + break; + } + _callback( _dap_server ); + } + + pthread_mutex_unlock( &_mutex ); + pthread_exit( NULL ); + + return NULL; +} + +void _worker_start( ) +{ + pthread_mutex_init( &_mutex, NULL ); + pthread_cond_init( &_cond, NULL ); + pthread_create( &worker_thread, NULL, _worker_run, NULL ); +} + +void _worker_stop() +{ + pthread_mutex_lock( &_mutex ); + _stop_worker_signal = true; + pthread_cond_signal( &_cond ); + pthread_mutex_unlock( &_mutex ); + + // wait for exit worker_thread + pthread_join( worker_thread, NULL ); + + pthread_mutex_destroy( &_mutex ); + pthread_cond_destroy( &_cond ); + _callback = NULL; +} + +#ifndef _WIN32 +static void _timeout_cb( ) +#else +VOID CALLBACK _timeout_cb( void *lpParameter, BOOL TimerOrWaitFired ) +#endif +{ +#if 0 + pthread_mutex_lock( &_dap_server->mutex_on_hash ); + + size_t count_users = HASH_COUNT(_dap_server->clients ); + + if ( count_users ) { +// size_t idx = 0; + dap_client_remote_t *dap_cur, *tmp; + HASH_ITER( hh, _dap_server->clients, dap_cur, tmp ) { + + dap_cur->upload_stat.speed_mbs = _calculate_mbits_speed( dap_cur->upload_stat.buf_size_total - + dap_cur->upload_stat.buf_size_total_old ); + + dap_cur->upload_stat.buf_size_total_old = dap_cur->upload_stat.buf_size_total; + + dap_cur->download_stat.speed_mbs = _calculate_mbits_speed( dap_cur->download_stat.buf_size_total - + dap_cur->download_stat.buf_size_total_old ); + + dap_cur->download_stat.buf_size_total_old = dap_cur->download_stat.buf_size_total; + +// idx ++; + } + } + + /* TODO find some better solution and place for this line */ + _dap_server->cpu_stats = dap_cpu_get_stats( ); + + pthread_mutex_unlock( &_dap_server->mutex_on_hash ); +#endif + + if ( _callback != NULL ) { + pthread_mutex_lock( &_mutex ); + pthread_cond_signal( &_cond ); + pthread_mutex_unlock( &_mutex ); + } +} + +void dap_traffic_track_init( dap_server_t * server, + time_t timeout ) +{ + dap_cpu_monitor_init( ); + + _dap_server = server; +#ifndef _WIN32 + _timeout_watcher.repeat = timeout; + + loop = EV_DEFAULT; + + ev_init( &_timeout_watcher, _timeout_cb ); + ev_timer_again( loop, &_timeout_watcher ); +#else + + timertimeout = timeout; + + CreateTimerQueueTimer( &_timeout_watcher, NULL, (WAITORTIMERCALLBACK)_timeout_cb, NULL, timertimeout, timertimeout, 0 ); + +#endif + + log_it(L_NOTICE, "Initialized traffic track module"); +} + +void dap_traffic_track_deinit() +{ + if ( _callback != NULL ) + _worker_stop(); + +#ifndef _WIN32 + ev_timer_stop( loop, &_timeout_watcher ); + ev_loop_destroy( loop ); +#else + DeleteTimerQueueTimer( NULL, _timeout_watcher, NULL ); +#endif + + log_it( L_NOTICE, "Deinitialized traffic track module" ); + dap_cpu_monitor_deinit( ); +} + +void dap_traffic_callback_stop() { + + if ( _callback == NULL ) { + log_it( L_WARNING, "worker not running" ); + return; + } + _worker_stop(); +} + +void dap_traffic_callback_set(dap_traffic_callback_t cb) +{ + if( _callback == NULL ) { + _callback = cb; + _worker_start(); + return; + } + + log_it( L_WARNING, "Callback already setted" ); +} diff --git a/test/dap_traffic_track_test.c b/test/dap_traffic_track_test.c index 9a0cdfc9e2d6e65e4c76e429754b87dd1cb22d64..a7f70ddcf478f7f2ab9aa6d961381a8aed5c051d 100755 --- a/test/dap_traffic_track_test.c +++ b/test/dap_traffic_track_test.c @@ -2,11 +2,12 @@ #include <unistd.h> #include <ev.h> #include <math.h> +#if 0 static struct ev_loop *loop; static struct moc_dap_clients_remote { - dap_client_remote_t ** clients; + dap_client_remote_t ** clients; size_t count; } moc_dap_clients_remote; @@ -46,13 +47,13 @@ void init_test_case() { sizeof(dap_client_remote_t *)); for(size_t i = 0, j = 0; (i < moc_dap_clients_remote.count) && (j = i + 1); i++) { moc_dap_clients_remote.clients[i] = - dap_client_remote_create(_dap_server, j, NULL); + dap_client_remote_create(_dap_server, j, NULL); } } void cleanup_test_case() { for(size_t i = 0; i < moc_dap_clients_remote.count; i++) - dap_client_remote_remove(moc_dap_clients_remote.clients[i], _dap_server); + dap_client_remote_remove(moc_dap_clients_remote.clients[i], _dap_server); ev_loop_destroy(loop); DAP_DELETE(moc_dap_clients_remote.clients); DAP_DELETE(_dap_server); @@ -65,3 +66,4 @@ void dap_traffic_track_tests_run(void) { test_callback(); cleanup_test_case(); } +#endif