From a85fd11715d9260b06e8581dc57f146fbf44c1b3 Mon Sep 17 00:00:00 2001 From: "Dmitriy A. Gerasimov" <dmitriy.gerasimov@demlabs.net> Date: Sun, 23 Aug 2020 15:34:51 +0700 Subject: [PATCH] [*] Fixed mt accept behaviour [-] Rmoved win CRLF symbols from some sources [*] Other bugfixes --- CMakeLists.txt | 2 +- dap-sdk/net/core/dap_events_socket.c | 9 +- dap-sdk/net/core/dap_server.c | 520 ++++++++------- dap-sdk/net/core/dap_worker.c | 44 +- dap-sdk/net/core/include/dap_events_socket.h | 5 +- dap-sdk/net/core/include/dap_server.h | 3 + .../net/server/http_server/dap_http_folder.c | 626 +++++++++--------- 7 files changed, 622 insertions(+), 587 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index feaedcd5f6..33f78043a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ project(cellframe-sdk C) cmake_minimum_required(VERSION 2.8) set(CMAKE_C_STANDARD 11) -set(CELLFRAME_SDK_NATIVE_VERSION "2.4-0") +set(CELLFRAME_SDK_NATIVE_VERSION "2.4-1") add_definitions ("-DCELLFRAME_SDK_VERSION=\"${CELLFRAME_SDK_NATIVE_VERSION}\"") set(DAPSDK_MODULES "") diff --git a/dap-sdk/net/core/dap_events_socket.c b/dap-sdk/net/core/dap_events_socket.c index ec4fe3cdc2..8d71bd973d 100644 --- a/dap-sdk/net/core/dap_events_socket.c +++ b/dap-sdk/net/core/dap_events_socket.c @@ -133,12 +133,11 @@ dap_events_socket_t * dap_events_socket_create_type_event(dap_worker_t * a_w, da return NULL; }else log_it(L_DEBUG, "Created one-way unnamed pipe %d->%d", l_pipe[0], l_pipe[1]); - l_es->fd = l_pipe[1]; - l_es->fd2 = l_pipe[0]; + l_es->fd = l_pipe[0]; + l_es->fd2 = l_pipe[1]; #endif #if defined(DAP_EVENTS_CAPS_EPOLL) - struct epoll_event l_ev={0}; int l_event_fd = l_es->fd; //log_it( L_INFO, "Create event descriptor with queue %d (%p) and add it on epoll fd %d", l_event_fd, l_es, a_w->epoll_fd); l_es->ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP | EPOLLHUP; @@ -219,6 +218,7 @@ dap_events_socket_t * dap_events_socket_wrap2( dap_server_t *a_server, struct da ret->socket = a_sock; ret->events = a_events; + ret->server = a_server; memcpy(&ret->callbacks,a_callbacks, sizeof ( ret->callbacks) ); ret->flags = DAP_SOCK_READY_TO_READ; @@ -229,9 +229,6 @@ dap_events_socket_t * dap_events_socket_wrap2( dap_server_t *a_server, struct da 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; } diff --git a/dap-sdk/net/core/dap_server.c b/dap-sdk/net/core/dap_server.c index 45f89872c1..5f5f5e417b 100644 --- a/dap-sdk/net/core/dap_server.c +++ b/dap-sdk/net/core/dap_server.c @@ -1,255 +1,265 @@ -/* - * Authors: - * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net> - * DeM Labs Ltd. https://demlabs.net - * Copyright (c) 2017 - * All rights reserved. - - This file is part of DAP SDK the open source project - - DAP SDK 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 SDK 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 SDK based project. If not, see <http://www.gnu.org/licenses/>. -*/ - -#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 <string.h> -#include <time.h> - -#include <stdio.h> -#include <stdio.h> -#include <stdlib.h> -#include <stddef.h> -#include <errno.h> -#include <signal.h> -#include <sys/timerfd.h> -#include <utlist.h> -#if ! defined(_GNU_SOURCE) -#define _GNU_SOURCE -#endif -#if ! defined (__USE_GNU) -#define __USE_GNU -#endif -#include <sched.h> -#include "dap_common.h" -#include "dap_config.h" -#include "dap_server.h" -#include "dap_worker.h" -#include "dap_events.h" - -#define LOG_TAG "dap_server" - -static void s_es_server_read(dap_events_socket_t *a_events, void * a_arg); -static void s_es_server_error(dap_events_socket_t *a_events, void * a_arg); - -static void s_server_delete(dap_server_t * a_server); -/** - * @brief dap_server_init - * @return - */ -int dap_server_init() -{ - log_it(L_NOTICE,"Server module init"); - return 0; -} - -/** - * @brief dap_server_deinit - */ -void dap_server_deinit() -{ -} - -/** - * @brief dap_server_delete - * @param a_server - */ -void s_server_delete(dap_server_t * a_server) -{ - if(a_server->delete_callback) - a_server->delete_callback(a_server,NULL); - if( a_server->address ) - DAP_DELETE(a_server->address ); - if( a_server->_inheritor ) - DAP_DELETE( a_server->_inheritor ); - DAP_DELETE(a_server); -} - -/** - * @brief dap_server_new - * @param a_events - * @param a_addr - * @param a_port - * @param a_type - * @return - */ -dap_server_t* dap_server_new(dap_events_t *a_events, const char * a_addr, uint16_t a_port, dap_server_type_t a_type) -{ - assert(a_events); - dap_server_t *l_server = DAP_NEW_Z(dap_server_t); - - l_server->socket_listener=-1; // To diff it from 0 fd - l_server->address = a_addr? strdup( a_addr) : strdup("0.0.0.0"); // If NULL we listen everything - l_server->port = a_port; - l_server->type = a_type; - - if(l_server->type == DAP_SERVER_TCP) - l_server->socket_listener = socket(AF_INET, SOCK_STREAM, 0); - - if (l_server->socket_listener < 0) { - int l_errno = errno; - log_it (L_ERROR,"Socket error %s (%d)",strerror(l_errno), l_errno); - DAP_DELETE(l_server); - return NULL; - } - - log_it(L_NOTICE,"Listen socket created..."); - int reuse=1; - - if (setsockopt(l_server->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"); -#ifdef SO_REUSEPORT - if (setsockopt(l_server->socket_listener, SOL_SOCKET, SO_REUSEPORT, (const char*)&reuse, sizeof(reuse)) < 0) - log_it(L_WARNING, "Can't set up REUSEPORT flag to the socket"); -#endif - -//create socket - l_server->listener_addr.sin_family = AF_INET; - l_server->listener_addr.sin_port = htons(l_server->port); - inet_pton(AF_INET, l_server->address, &(l_server->listener_addr.sin_addr)); - - if(bind (l_server->socket_listener, (struct sockaddr *) &(l_server->listener_addr), sizeof(l_server->listener_addr)) < 0){ - log_it(L_ERROR,"Bind error: %s",strerror(errno)); - return NULL; - }else{ - log_it(L_INFO,"Binded %s:%u",l_server->address,l_server->port); - listen(l_server->socket_listener, SOMAXCONN); - } - - fcntl( l_server->socket_listener, F_SETFL, O_NONBLOCK); - - dap_events_socket_callbacks_t l_callbacks = {{ 0 }}; - l_callbacks.read_callback = s_es_server_read; - l_callbacks.error_callback = s_es_server_error; - - for(size_t l_worker_id = 0; l_worker_id < dap_events_worker_get_count() ; l_worker_id++){ - dap_events_socket_t * l_es = dap_events_socket_wrap_no_add( a_events, l_server->socket_listener, &l_callbacks); - dap_worker_t *l_w = dap_events_worker_get(l_worker_id); - assert(l_w); - - if ( l_es){ - log_it(L_DEBUG, "Wrapped server socket %p on worker %u", l_es, l_worker_id); - l_es->_inheritor = l_server; - l_es->server = l_server; - l_es->type = DESCRIPTOR_TYPE_SOCKET_LISTENING; -#ifdef DAP_EVENTS_CAPS_EPOLL - // Prepare for multi thread listening - l_es->ev_base_flags = EPOLLET| EPOLLIN | EPOLLEXCLUSIVE; -#endif - dap_worker_add_events_socket( l_es, l_w ); - } else{ - log_it(L_WARNING, "Can't wrap event socket for %s:%u server", a_addr, a_port); - return NULL; - } - } - return l_server; -} - - -/** - * @brief s_es_server_error - * @param a_es - * @param a_arg - */ -static void s_es_server_error(dap_events_socket_t *a_es, void * a_arg) -{ - (void) a_arg; - (void) a_es; - char l_buf[128]; - strerror_r(errno, l_buf, sizeof (l_buf)); - log_it(L_WARNING, "Listening socket error: %s, ", l_buf); -} - -/** - * @brief s_es_server_read - * @param a_es - * @param a_arg - */ -static void s_es_server_read(dap_events_socket_t *a_es,void * a_arg) -{ - (void) a_arg; - a_es->buf_in_size = 0; // It should be 1 so we reset it to 0 - //log_it(L_DEBUG, "Server socket %d is active",i); - dap_server_t * l_server = (dap_server_t*) a_es->_inheritor; - if( l_server ){ - dap_events_socket_t * l_es_new = NULL; - log_it(L_DEBUG, "Listening socket (binded on %s:%u) got new incomming connection",l_server->address,l_server->port); - struct sockaddr client_addr = {0}; - socklen_t client_addr_size = sizeof(struct sockaddr); - int l_es_new_socket; - while ( (l_es_new_socket = accept(a_es->socket ,&client_addr,&client_addr_size)) > 0){ - log_it(L_DEBUG, "Accepted new connection (sock %d from %d)", l_es_new_socket, a_es->socket); - l_es_new = dap_server_events_socket_new(a_es->events,l_es_new_socket,&l_server->client_callbacks,l_server); - - getnameinfo(&client_addr,client_addr_size, l_es_new->hostaddr - , sizeof(l_es_new->hostaddr),l_es_new->service,sizeof(l_es_new->service), - NI_NUMERICHOST | NI_NUMERICSERV); - log_it(L_INFO,"Connection accepted from %s (%s)", l_es_new->hostaddr, l_es_new->service ); - dap_worker_add_events_socket_auto(l_es_new); - } - if ( l_es_new_socket == -1 && errno == EAGAIN){ - // Everything is good, we'll receive ACCEPT on next poll - return; - }else{ - log_it(L_WARNING,"accept() returned %d",l_es_new_socket); - } - - }else - log_it(L_ERROR, "No sap_server object related with socket %d in the select loop",a_es->socket); -} - - -/** - * @brief dap_server_events_socket_new - * @param a_events - * @param a_sock - * @param a_callbacks - * @param a_server - * @return - */ -dap_events_socket_t * dap_server_events_socket_new(dap_events_t * a_events, int a_sock, - dap_events_socket_callbacks_t * a_callbacks, dap_server_t * a_server) -{ - dap_events_socket_t * ret = NULL; - if (a_sock > 0) { - // set it nonblock - //fcntl(a_sock, F_SETFL, O_NONBLOCK); - - ret = dap_events_socket_wrap_no_add(a_events, a_sock, a_callbacks); - ret->type = DESCRIPTOR_TYPE_SOCKET; - ret->server = a_server; - - } else { - log_it(L_CRITICAL,"Accept error: %s",strerror(errno)); - } - return ret; -} +/* + * Authors: + * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net> + * DeM Labs Ltd. https://demlabs.net + * Copyright (c) 2017 + * All rights reserved. + + This file is part of DAP SDK the open source project + + DAP SDK 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 SDK 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 SDK based project. If not, see <http://www.gnu.org/licenses/>. +*/ + +#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 <string.h> +#include <time.h> + +#include <stdio.h> +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <errno.h> +#include <signal.h> +#include <sys/timerfd.h> +#include <utlist.h> +#if ! defined(_GNU_SOURCE) +#define _GNU_SOURCE +#endif +#if ! defined (__USE_GNU) +#define __USE_GNU +#endif +#include <sched.h> +#include "dap_common.h" +#include "dap_config.h" +#include "dap_server.h" +#include "dap_worker.h" +#include "dap_events.h" + +#define LOG_TAG "dap_server" + +static void s_es_server_accept(dap_events_socket_t *a_es, int a_remote_socket, struct sockaddr* a_remote_addr); +static void s_es_server_error(dap_events_socket_t *a_es, void * a_arg); +static void s_es_server_new(dap_events_socket_t *a_es, void * a_arg); + +static void s_server_delete(dap_server_t * a_server); +/** + * @brief dap_server_init + * @return + */ +int dap_server_init() +{ + log_it(L_NOTICE,"Server module init"); + return 0; +} + +/** + * @brief dap_server_deinit + */ +void dap_server_deinit() +{ +} + +/** + * @brief dap_server_delete + * @param a_server + */ +void s_server_delete(dap_server_t * a_server) +{ + if(a_server->delete_callback) + a_server->delete_callback(a_server,NULL); + if( a_server->address ) + DAP_DELETE(a_server->address ); + if( a_server->_inheritor ) + DAP_DELETE( a_server->_inheritor ); + DAP_DELETE(a_server); +} + +/** + * @brief dap_server_new + * @param a_events + * @param a_addr + * @param a_port + * @param a_type + * @return + */ +dap_server_t* dap_server_new(dap_events_t *a_events, const char * a_addr, uint16_t a_port, dap_server_type_t a_type) +{ + assert(a_events); + dap_server_t *l_server = DAP_NEW_Z(dap_server_t); + + l_server->socket_listener=-1; // To diff it from 0 fd + l_server->address = a_addr? strdup( a_addr) : strdup("0.0.0.0"); // If NULL we listen everything + l_server->port = a_port; + l_server->type = a_type; + + if(l_server->type == DAP_SERVER_TCP) + l_server->socket_listener = socket(AF_INET, SOCK_STREAM, 0); + + if (l_server->socket_listener < 0) { + int l_errno = errno; + log_it (L_ERROR,"Socket error %s (%d)",strerror(l_errno), l_errno); + DAP_DELETE(l_server); + return NULL; + } + + log_it(L_NOTICE,"Listen socket %d created...", l_server->socket_listener); + int reuse=1; + + if (setsockopt(l_server->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"); +#ifdef SO_REUSEPORT + if (setsockopt(l_server->socket_listener, SOL_SOCKET, SO_REUSEPORT, (const char*)&reuse, sizeof(reuse)) < 0) + log_it(L_WARNING, "Can't set up REUSEPORT flag to the socket"); +#endif + +//create socket + l_server->listener_addr.sin_family = AF_INET; + l_server->listener_addr.sin_port = htons(l_server->port); + inet_pton(AF_INET, l_server->address, &(l_server->listener_addr.sin_addr)); + + if(bind (l_server->socket_listener, (struct sockaddr *) &(l_server->listener_addr), sizeof(l_server->listener_addr)) < 0){ + log_it(L_ERROR,"Bind error: %s",strerror(errno)); + close(l_server->socket_listener); + DAP_DELETE(l_server); + return NULL; + }else{ + log_it(L_INFO,"Binded %s:%u",l_server->address,l_server->port); + listen(l_server->socket_listener, SOMAXCONN); + } + + fcntl( l_server->socket_listener, F_SETFL, O_NONBLOCK); + pthread_mutex_init(&l_server->started_mutex,NULL); + pthread_cond_init(&l_server->started_cond,NULL); + + + + dap_events_socket_callbacks_t l_callbacks; + memset(&l_callbacks,0,sizeof (l_callbacks)); + l_callbacks.new_callback = s_es_server_new; + l_callbacks.accept_callback = s_es_server_accept; + l_callbacks.error_callback = s_es_server_error; + + for(size_t l_worker_id = 0; l_worker_id < dap_events_worker_get_count() ; l_worker_id++){ + dap_worker_t *l_w = dap_events_worker_get(l_worker_id); + assert(l_w); + dap_events_socket_t * l_es = dap_events_socket_wrap2( l_server, a_events, l_server->socket_listener, &l_callbacks); + + if ( l_es){ + l_es->type = DESCRIPTOR_TYPE_SOCKET_LISTENING; +#ifdef DAP_EVENTS_CAPS_EPOLL + // Prepare for multi thread listening + l_es->ev_base_flags = EPOLLET| EPOLLIN | EPOLLEXCLUSIVE; +#endif + l_es->_inheritor = l_server; + pthread_mutex_lock(&l_server->started_mutex); + dap_worker_add_events_socket( l_es, l_w ); + pthread_cond_wait(&l_server->started_cond, &l_server->started_mutex); + pthread_mutex_unlock(&l_server->started_mutex); + } else{ + log_it(L_WARNING, "Can't wrap event socket for %s:%u server", a_addr, a_port); + return NULL; + } + } + return l_server; +} + +/** + * @brief s_es_server_new + * @param a_es + * @param a_arg + */ +static void s_es_server_new(dap_events_socket_t *a_es, void * a_arg) +{ + log_it(L_DEBUG, "Created server socket %p on worker %u", a_es, a_es->worker->id); + dap_server_t *l_server = (dap_server_t*) a_es->_inheritor; + pthread_cond_broadcast( &l_server->started_cond); +} + +/** + * @brief s_es_server_error + * @param a_es + * @param a_arg + */ +static void s_es_server_error(dap_events_socket_t *a_es, void * a_arg) +{ + (void) a_arg; + (void) a_es; + char l_buf[128]; + strerror_r(errno, l_buf, sizeof (l_buf)); + log_it(L_WARNING, "Listening socket error: %s, ", l_buf); +} + +/** + * @brief s_es_server_accept + * @param a_events + * @param a_remote_socket + * @param a_remote_addr + */ +static void s_es_server_accept(dap_events_socket_t *a_es, int a_remote_socket, struct sockaddr *a_remote_addr) +{ + socklen_t a_remote_addr_size = sizeof(*a_remote_addr); + a_es->buf_in_size = 0; // It should be 1 so we reset it to 0 + //log_it(L_DEBUG, "Server socket %d is active",i); + dap_server_t * l_server = (dap_server_t*) a_es->_inheritor; + assert(l_server); + + dap_events_socket_t * l_es_new = NULL; + log_it(L_DEBUG, "Listening socket (binded on %s:%u) got new incomming connection",l_server->address,l_server->port); + log_it(L_DEBUG, "Accepted new connection (sock %d from %d)", a_remote_socket, a_es->socket); + l_es_new = dap_server_events_socket_new(a_es->events,a_remote_socket,&l_server->client_callbacks,l_server); + + getnameinfo(a_remote_addr,a_remote_addr_size, l_es_new->hostaddr + , sizeof(l_es_new->hostaddr),l_es_new->service,sizeof(l_es_new->service), + NI_NUMERICHOST | NI_NUMERICSERV); + + log_it(L_INFO,"Connection accepted from %s (%s)", l_es_new->hostaddr, l_es_new->service ); + dap_worker_add_events_socket_auto(l_es_new); +} + + +/** + * @brief dap_server_events_socket_new + * @param a_events + * @param a_sock + * @param a_callbacks + * @param a_server + * @return + */ +dap_events_socket_t * dap_server_events_socket_new(dap_events_t * a_events, int a_sock, + dap_events_socket_callbacks_t * a_callbacks, dap_server_t * a_server) +{ + dap_events_socket_t * ret = NULL; + if (a_sock > 0) { + // set it nonblock + //fcntl(a_sock, F_SETFL, O_NONBLOCK); + + ret = dap_events_socket_wrap_no_add(a_events, a_sock, a_callbacks); + ret->type = DESCRIPTOR_TYPE_SOCKET; + ret->server = a_server; + + } else { + log_it(L_CRITICAL,"Accept error: %s",strerror(errno)); + } + return ret; +} diff --git a/dap-sdk/net/core/dap_worker.c b/dap-sdk/net/core/dap_worker.c index 534ab5671a..b6d519bf26 100644 --- a/dap-sdk/net/core/dap_worker.c +++ b/dap-sdk/net/core/dap_worker.c @@ -138,7 +138,8 @@ void *dap_worker_thread(void *arg) } l_cur->last_time_active = l_cur_time; - //log_it(L_DEBUG, "Worker=%d fd=%d socket=%d event=0x%x(%d)", w->number_thread, w->epoll_fd,cur->socket, events[n].events,events[n].events); + log_it(L_DEBUG, "Worker=%d fd=%d socket=%d event=0x%x(%d)", l_worker->id, + l_worker->epoll_fd,l_cur->socket, l_epoll_events[n].events,l_epoll_events[n].events); int l_sock_err = 0, l_sock_err_size = sizeof(l_sock_err); //connection already closed (EPOLLHUP - shutdown has been made in both directions) if(l_epoll_events[n].events & EPOLLHUP) { // && events[n].events & EPOLLERR) { @@ -195,6 +196,24 @@ void *dap_worker_thread(void *arg) break; case DESCRIPTOR_TYPE_SOCKET_LISTENING: // Accept connection + if ( l_cur->callbacks.accept_callback){ + struct sockaddr l_remote_addr; + socklen_t l_remote_addr_size= sizeof (l_remote_addr); + int l_remote_socket= accept(l_cur->socket ,&l_remote_addr,&l_remote_addr_size); + int l_errno = errno; + if ( l_remote_socket == -1 ){ + if( l_errno == EAGAIN || l_errno == EWOULDBLOCK){// Everything is good, we'll receive ACCEPT on next poll + continue; + }else{ + char l_errbuf[128]; + strerror_r(l_errno, l_errbuf, sizeof (l_errbuf)); + log_it(L_WARNING,"accept() on socket %d error:\"%s\"(%d)",l_cur->socket, l_errbuf,l_errno); + } + } + + l_cur->callbacks.accept_callback(l_cur,l_remote_socket,&l_remote_addr); + }else + log_it(L_ERROR,"No accept_callback on listening socket"); break; case DESCRIPTOR_TYPE_TIMER:{ uint64_t val; @@ -224,7 +243,12 @@ void *dap_worker_thread(void *arg) if(l_bytes_read > 0) { l_cur->buf_in_size += l_bytes_read; //log_it(DEBUG, "Received %d bytes", bytes_read); - l_cur->callbacks.read_callback(l_cur, NULL); // Call callback to process read event. At the end of callback buf_in_size should be zero if everything was read well + if(l_cur->callbacks.read_callback) + l_cur->callbacks.read_callback(l_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{ + log_it(L_WARNING, "We have incomming %u data but no read callback on socket %d, removing from read set", l_cur->socket); + dap_events_socket_set_readable_unsafe(l_cur,false); + } } else if(l_bytes_read < 0) { if (l_errno != EAGAIN && l_errno != EWOULDBLOCK){ // Socket is blocked @@ -287,19 +311,17 @@ void *dap_worker_thread(void *arg) break; } }else{ - l_bytes_sent += l_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: %u from %u bytes are sent ", l_bytes_sent,l_cur->buf_out_size); //} //log_it(L_DEBUG,"Output: sent %u bytes",total_sent); if (l_bytes_sent) { - pthread_mutex_lock(&l_cur->mutex); l_cur->buf_out_size -= l_bytes_sent; + //log_it(L_DEBUG,"Output: left %u bytes in buffer",l_cur->buf_out_size); if (l_cur->buf_out_size) { memmove(l_cur->buf_out, &l_cur->buf_out[l_bytes_sent], l_cur->buf_out_size); } else { l_cur->flags &= ~DAP_SOCK_READY_TO_WRITE; } - pthread_mutex_unlock(&l_cur->mutex); } } } @@ -358,14 +380,14 @@ static void s_new_es_callback( dap_events_socket_t * a_es, void * a_arg) pthread_rwlock_unlock(&w->events->sockets_rwlock); struct epoll_event l_ev={0}; - l_ev.events = l_es_new->flags ; + l_es_new->ev.events = l_es_new->ev_base_flags ; if(l_es_new->flags & DAP_SOCK_READY_TO_READ ) - l_ev.events |= EPOLLIN; + l_es_new->ev.events |= EPOLLIN; if(l_es_new->flags & DAP_SOCK_READY_TO_WRITE ) - l_ev.events |= EPOLLOUT; - l_ev.data.ptr = l_es_new; + l_es_new->ev.events |= EPOLLOUT; + l_es_new->ev.data.ptr = l_es_new; - if ( epoll_ctl(w->epoll_fd, EPOLL_CTL_ADD, l_es_new->socket, &l_ev) == 1 ) + if ( epoll_ctl(w->epoll_fd, EPOLL_CTL_ADD, l_es_new->socket, &l_es_new->ev) == 1 ) log_it(L_CRITICAL,"Can't add event socket's handler to epoll_fd"); else{ log_it(L_DEBUG, "Added socket %d on worker %u", l_es_new->socket, w->id); diff --git a/dap-sdk/net/core/include/dap_events_socket.h b/dap-sdk/net/core/include/dap_events_socket.h index e2fffd4c8b..895e822b7a 100644 --- a/dap-sdk/net/core/include/dap_events_socket.h +++ b/dap-sdk/net/core/include/dap_events_socket.h @@ -59,11 +59,12 @@ typedef struct dap_worker dap_worker_t; typedef struct dap_server dap_server_t; typedef void (*dap_events_socket_callback_t) (dap_events_socket_t *,void * ); // Callback for specific client operations typedef void (*dap_events_socket_callback_timer_t) (dap_events_socket_t * ); // Callback for specific client operations +typedef void (*dap_events_socket_callback_accept_t) (dap_events_socket_t * , int, struct sockaddr* ); // Callback for accept of new connection typedef void (*dap_events_socket_worker_callback_t) (dap_events_socket_t *,dap_worker_t * ); // Callback for specific client operations typedef struct dap_events_socket_callbacks { union{ - dap_events_socket_callback_t accept_callback; // Accept callback for listening socket + dap_events_socket_callback_accept_t accept_callback; // Accept callback for listening socket dap_events_socket_callback_timer_t timer_callback; // Timer callback for listening socket dap_events_socket_callback_t event_callback; // Timer callback for listening socket dap_events_socket_callback_t action_callback; // Callback for action with socket @@ -160,6 +161,8 @@ dap_events_socket_t * dap_events_socket_create_type_event(dap_worker_t * a_w, da void dap_events_socket_send_event( dap_events_socket_t * a_es, void* a_arg); 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_wrap2( dap_server_t *a_server, struct dap_events *a_events, + int a_sock, dap_events_socket_callbacks_t *a_callbacks ); dap_events_socket_t * dap_events_socket_find(int sock, struct dap_events * sh); // Find client by socket diff --git a/dap-sdk/net/core/include/dap_server.h b/dap-sdk/net/core/include/dap_server.h index 88e0d157ee..e43e1bbe19 100644 --- a/dap-sdk/net/core/include/dap_server.h +++ b/dap-sdk/net/core/include/dap_server.h @@ -75,6 +75,9 @@ typedef struct dap_server { dap_server_callback_t delete_callback; dap_events_socket_callbacks_t client_callbacks; // Callbacks for the new clients + + pthread_cond_t started_cond; // Condition for initialized socket + pthread_mutex_t started_mutex; // Mutex for shared operation between mirrored sockets } dap_server_t; int dap_server_init( ); // Init server module diff --git a/dap-sdk/net/server/http_server/dap_http_folder.c b/dap-sdk/net/server/http_server/dap_http_folder.c index fc293a487c..d16e8a0d4a 100644 --- a/dap-sdk/net/server/http_server/dap_http_folder.c +++ b/dap-sdk/net/server/http_server/dap_http_folder.c @@ -1,313 +1,313 @@ -/* - * Authors: - * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net> - * DeM Labs Ltd. https://demlabs.net - * Copyright (c) 2017 - * All rights reserved. - - This file is part of DAP SDK the open source project - - DAP SDK 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 SDK 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 SDK based project. If not, see <http://www.gnu.org/licenses/>. -*/ -#include <stdio.h> -#include <unistd.h> -#include <dirent.h> -#include <errno.h> - -#ifndef _WIN32 -#include <sys/types.h> -#include <sys/stat.h> -#else -#include <winsock2.h> -#include <windows.h> -#include <mswsock.h> -#include <ws2tcpip.h> -#include <io.h> -#endif - -#include <pthread.h> -#include <magic.h> - -#include "dap_common.h" -#include "dap_events_socket.h" -#include "dap_http.h" -#include "dap_http_client.h" -#include "dap_http_folder.h" -#include "http_status_code.h" - -typedef struct dap_http_url_proc_folder { - char local_path[4096]; - magic_t mime_detector; -} dap_http_url_proc_folder_t; - -#define URL_PROC_FOLDER(a) ((dap_http_url_proc_folder_t*) (a)->_inhertior ) - -typedef struct dap_http_file{ - FILE * fd; - size_t position; - char local_path[4096+2048+1]; - dap_http_client_t *client; -} dap_http_file_t; - -#define DAP_HTTP_FILE(a) ((dap_http_file_t*) (a)->_inheritor ) - -void dap_http_folder_headers_read( dap_http_client_t *cl_ht, void *arg ); -void dap_http_folder_headers_write( dap_http_client_t *cl_ht, void *arg ); -void dap_http_folder_data_read( dap_http_client_t *cl_ht, void *arg ); -void dap_http_folder_data_write( dap_http_client_t *cl_ht, void *arg ); - -#define LOG_TAG "dap_http_folder" - -int dap_http_folder_init( ) -{ - return 0; -} - -void dap_http_folder_deinit( ) -{ - -} - - -/** - * @brief dap_http_folder_add Add folder for reading to the HTTP server - * @param sh Server instance - * @param url_path Beginning part of the URL - * @param local_path Local path that will be read for - */ -int dap_http_folder_add( dap_http_t *sh, const char *url_path, const char *local_path ) -{ - if ( !local_path ) { - log_it( L_ERROR, "Directory Path parameter is empty!" ); - return -11; - } - - log_it( L_DEBUG, "Checking url path %s", local_path ); - -#ifndef _WIN32 - DIR *dirptr = opendir( local_path ); - if ( dirptr == NULL ) { - log_it( L_ERROR, "Directory Not Found!" ); - return -11; - } - else { - closedir( dirptr ); - } -#else // WIN32 - - DWORD attr = GetFileAttributesA( local_path ); - if ( attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY) ) { - log_it( L_ERROR, "Directory Not Found!" ); - return -11; - } - -#endif - - log_it( L_NOTICE, "File service for %s => %s ", url_path, local_path ); - - dap_http_url_proc_folder_t *up_folder = (dap_http_url_proc_folder_t *)calloc( 1, sizeof(dap_http_url_proc_folder_t) ); - strncpy( up_folder->local_path, local_path, sizeof(up_folder->local_path)-1 ); - - up_folder->mime_detector = magic_open( MAGIC_SYMLINK | MAGIC_MIME | MAGIC_PRESERVE_ATIME ); - - if ( up_folder->mime_detector == NULL) { - log_it( L_CRITICAL,"Can't init MIME detection library" ); - free( up_folder ); - return -1; - } - -#ifndef _WIN32 - if( 0 != magic_load( up_folder->mime_detector, NULL) ) { -#else - if( 0 != magic_load( up_folder->mime_detector, "data.mag" ) ) { -#endif - - log_it( L_CRITICAL, "Can't load MIME magic detection database" ); - magic_close( up_folder->mime_detector ); - free( up_folder ); - return -2; - } - - dap_http_add_proc( sh, - url_path, - up_folder, - NULL, - NULL, - dap_http_folder_headers_read, - dap_http_folder_headers_write, - dap_http_folder_data_read, - dap_http_folder_data_write, - NULL ); - return 0; -} - -/** - * @brief dap_http_folder_headers_read Signal thats HTTP client is now going to output the data - * @param cl_ht HTTP client instance - * @param arg Not used - */ -void dap_http_folder_headers_read(dap_http_client_t * cl_ht, void * arg) -{ - (void) arg; - cl_ht->state_write=DAP_HTTP_CLIENT_STATE_START; - cl_ht->state_read=cl_ht->keep_alive?DAP_HTTP_CLIENT_STATE_START:DAP_HTTP_CLIENT_STATE_NONE; - - dap_events_socket_set_writable_unsafe(cl_ht->esocket,true); - dap_events_socket_set_readable_unsafe(cl_ht->esocket, cl_ht->keep_alive); -} - -#ifdef _WIN32 -time_t FileTimeToUnixTime( FILETIME ft ) -{ - ULARGE_INTEGER ull; - - ull.LowPart = ft.dwLowDateTime; - ull.HighPart = ft.dwHighDateTime; - - return ull.QuadPart / 10000000ULL - 11644473600ULL; -} -#endif - -/** - * @brief dap_http_folder_headers Prepare response HTTP headers for file folder request - * @param cl_ht HTTP client instane - * @param arg Not used - */ -void dap_http_folder_headers_write( dap_http_client_t *cl_ht, void * arg) -{ - (void) arg; - // Get specific data for folder URL processor - dap_http_url_proc_folder_t * up_folder=(dap_http_url_proc_folder_t*) cl_ht->proc->_inheritor; - - // Init specific file response data for HTTP client instance - cl_ht->_inheritor=DAP_NEW_Z(dap_http_file_t); - - dap_http_file_t* cl_ht_file=DAP_HTTP_FILE(cl_ht); - cl_ht_file->client=cl_ht; - - // Produce local path for file to open - dap_snprintf(cl_ht_file->local_path,sizeof(cl_ht_file->local_path),"%s/%s", up_folder->local_path, cl_ht->url_path ); - log_it(L_DEBUG, "Check %s file", cl_ht_file->local_path); - -#ifndef _WIN32 - - struct stat file_stat; - - if ( stat(cl_ht_file->local_path, &file_stat) != 0 ) - goto err; - - cl_ht->out_last_modified = file_stat.st_mtime; - cl_ht->out_content_length = file_stat.st_size; - -#else - - FILETIME CreationTime; - FILETIME LastAccessTime; - FILETIME LastWriteTime; - - HANDLE fileh = CreateFileA( cl_ht_file->local_path, - GENERIC_READ, - FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_ARCHIVE, - NULL - ); - - if ( fileh == INVALID_HANDLE_VALUE ) - goto err; - - GetFileTime( fileh, - &CreationTime, - &LastAccessTime, - &LastWriteTime ); - - cl_ht->out_last_modified = FileTimeToUnixTime( LastWriteTime ); - cl_ht->out_content_length = GetFileSize( fileh, NULL ); - - CloseHandle( fileh ); - -#endif - - cl_ht_file->fd = fopen( cl_ht_file->local_path, "rb" ); - - if ( cl_ht_file->fd == NULL ) { - log_it(L_ERROR, "Can't open %s: %s",cl_ht_file->local_path,strerror(errno)); - cl_ht->reply_status_code = Http_Status_NotFound; - strncpy( cl_ht->reply_reason_phrase, "Not Found", sizeof(cl_ht->reply_reason_phrase)-1 ); - } - else { - cl_ht->reply_status_code = Http_Status_OK; - strncpy( cl_ht->reply_reason_phrase,"OK",sizeof(cl_ht->reply_reason_phrase)-1 ); - - const char *mime_type = magic_file( up_folder->mime_detector, cl_ht_file->local_path ); - if( mime_type ) { - strncpy(cl_ht->out_content_type,mime_type,sizeof(cl_ht->out_content_type)-1); - log_it( L_DEBUG, "MIME type detected: '%s'", mime_type ); - } - else { - cl_ht->reply_status_code=Http_Status_NotFound; - cl_ht->esocket->flags |= DAP_SOCK_SIGNAL_CLOSE; - log_it(L_WARNING,"Can't detect MIME type of %s file: %s",cl_ht_file->local_path,magic_error(up_folder->mime_detector)); - } - } - - return; - -err: - - log_it( L_WARNING, "Can't get file info: %s", strerror(errno) ); - cl_ht->reply_status_code = 404; - strncpy( cl_ht->reply_reason_phrase, "Not Found", sizeof(cl_ht->reply_reason_phrase)-1 ); - - return; -} - -/** - * @brief dap_http_folder_read HTTP client callback for reading function for the folder processing - * @param cl_ht HTTP client instance - * @param arg Pointer to int with return bytes number - */ -void dap_http_folder_data_read(dap_http_client_t * cl_ht, void * arg) -{ - int * bytes_return = (int*) arg; // Return number of read bytes - //Do nothing - *bytes_return=cl_ht->esocket->buf_in_size; -} - -/** - * @brief dap_http_folder_write HTTP client callback for writting function for the folder processing - * @param cl_ht HTTP client instance - * @param arg - */ -void dap_http_folder_data_write(dap_http_client_t * cl_ht, void * arg) -{ - (void) arg; - dap_http_file_t * cl_ht_file= DAP_HTTP_FILE(cl_ht); - cl_ht->esocket->buf_out_size=fread(cl_ht->esocket->buf_out,1,sizeof(cl_ht->esocket->buf_out),cl_ht_file->fd); - cl_ht_file->position+=cl_ht->esocket->buf_out_size; - - if(feof(cl_ht_file->fd)!=0){ - log_it(L_INFO, "All the file %s is sent out",cl_ht_file->local_path); - //strncat(cl_ht->client->buf_out+cl_ht->client->buf_out_size,"\r\n",sizeof(cl_ht->client->buf_out)); - fclose(cl_ht_file->fd); - dap_events_socket_set_writable_unsafe(cl_ht->esocket,false); - - if ( !cl_ht->keep_alive ) - cl_ht->esocket->flags |= DAP_SOCK_SIGNAL_CLOSE; - - cl_ht->state_write=DAP_HTTP_CLIENT_STATE_NONE; - } -} - +/* + * Authors: + * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net> + * DeM Labs Ltd. https://demlabs.net + * Copyright (c) 2017 + * All rights reserved. + + This file is part of DAP SDK the open source project + + DAP SDK 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 SDK 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 SDK based project. If not, see <http://www.gnu.org/licenses/>. +*/ +#include <stdio.h> +#include <unistd.h> +#include <dirent.h> +#include <errno.h> + +#ifndef _WIN32 +#include <sys/types.h> +#include <sys/stat.h> +#else +#include <winsock2.h> +#include <windows.h> +#include <mswsock.h> +#include <ws2tcpip.h> +#include <io.h> +#endif + +#include <pthread.h> +#include <magic.h> + +#include "dap_common.h" +#include "dap_events_socket.h" +#include "dap_http.h" +#include "dap_http_client.h" +#include "dap_http_folder.h" +#include "http_status_code.h" + +typedef struct dap_http_url_proc_folder { + char local_path[4096]; + magic_t mime_detector; +} dap_http_url_proc_folder_t; + +#define URL_PROC_FOLDER(a) ((dap_http_url_proc_folder_t*) (a)->_inhertior ) + +typedef struct dap_http_file{ + FILE * fd; + size_t position; + char local_path[4096+2048+1]; + dap_http_client_t *client; +} dap_http_file_t; + +#define DAP_HTTP_FILE(a) ((dap_http_file_t*) (a)->_inheritor ) + +void dap_http_folder_headers_read( dap_http_client_t *cl_ht, void *arg ); +void dap_http_folder_headers_write( dap_http_client_t *cl_ht, void *arg ); +void dap_http_folder_data_read( dap_http_client_t *cl_ht, void *arg ); +void dap_http_folder_data_write( dap_http_client_t *cl_ht, void *arg ); + +#define LOG_TAG "dap_http_folder" + +int dap_http_folder_init( ) +{ + return 0; +} + +void dap_http_folder_deinit( ) +{ + +} + + +/** + * @brief dap_http_folder_add Add folder for reading to the HTTP server + * @param sh Server instance + * @param url_path Beginning part of the URL + * @param local_path Local path that will be read for + */ +int dap_http_folder_add( dap_http_t *sh, const char *url_path, const char *local_path ) +{ + if ( !local_path ) { + log_it( L_ERROR, "Directory Path parameter is empty!" ); + return -11; + } + + log_it( L_DEBUG, "Checking url path %s", local_path ); + +#ifndef _WIN32 + DIR *dirptr = opendir( local_path ); + if ( dirptr == NULL ) { + log_it( L_ERROR, "Directory Not Found!" ); + return -11; + } + else { + closedir( dirptr ); + } +#else // WIN32 + + DWORD attr = GetFileAttributesA( local_path ); + if ( attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY) ) { + log_it( L_ERROR, "Directory Not Found!" ); + return -11; + } + +#endif + + log_it( L_NOTICE, "File service for %s => %s ", url_path, local_path ); + + dap_http_url_proc_folder_t *up_folder = (dap_http_url_proc_folder_t *)calloc( 1, sizeof(dap_http_url_proc_folder_t) ); + strncpy( up_folder->local_path, local_path, sizeof(up_folder->local_path)-1 ); + + up_folder->mime_detector = magic_open( MAGIC_SYMLINK | MAGIC_MIME | MAGIC_PRESERVE_ATIME ); + + if ( up_folder->mime_detector == NULL) { + log_it( L_CRITICAL,"Can't init MIME detection library" ); + free( up_folder ); + return -1; + } + +#ifndef _WIN32 + if( 0 != magic_load( up_folder->mime_detector, NULL) ) { +#else + if( 0 != magic_load( up_folder->mime_detector, "data.mag" ) ) { +#endif + + log_it( L_CRITICAL, "Can't load MIME magic detection database" ); + magic_close( up_folder->mime_detector ); + free( up_folder ); + return -2; + } + + dap_http_add_proc( sh, + url_path, + up_folder, + NULL, + NULL, + dap_http_folder_headers_read, + dap_http_folder_headers_write, + dap_http_folder_data_read, + dap_http_folder_data_write, + NULL ); + return 0; +} + +/** + * @brief dap_http_folder_headers_read Signal thats HTTP client is now going to output the data + * @param cl_ht HTTP client instance + * @param arg Not used + */ +void dap_http_folder_headers_read(dap_http_client_t * cl_ht, void * arg) +{ + (void) arg; + cl_ht->state_write=DAP_HTTP_CLIENT_STATE_START; + cl_ht->state_read=cl_ht->keep_alive?DAP_HTTP_CLIENT_STATE_START:DAP_HTTP_CLIENT_STATE_NONE; + + dap_events_socket_set_writable_unsafe(cl_ht->esocket,true); + dap_events_socket_set_readable_unsafe(cl_ht->esocket, cl_ht->keep_alive); +} + +#ifdef _WIN32 +time_t FileTimeToUnixTime( FILETIME ft ) +{ + ULARGE_INTEGER ull; + + ull.LowPart = ft.dwLowDateTime; + ull.HighPart = ft.dwHighDateTime; + + return ull.QuadPart / 10000000ULL - 11644473600ULL; +} +#endif + +/** + * @brief dap_http_folder_headers Prepare response HTTP headers for file folder request + * @param cl_ht HTTP client instane + * @param arg Not used + */ +void dap_http_folder_headers_write( dap_http_client_t *cl_ht, void * arg) +{ + (void) arg; + // Get specific data for folder URL processor + dap_http_url_proc_folder_t * up_folder=(dap_http_url_proc_folder_t*) cl_ht->proc->_inheritor; + + // Init specific file response data for HTTP client instance + cl_ht->_inheritor=DAP_NEW_Z(dap_http_file_t); + + dap_http_file_t* cl_ht_file=DAP_HTTP_FILE(cl_ht); + cl_ht_file->client=cl_ht; + + // Produce local path for file to open + dap_snprintf(cl_ht_file->local_path,sizeof(cl_ht_file->local_path),"%s/%s", up_folder->local_path, cl_ht->url_path ); + log_it(L_DEBUG, "Check %s file", cl_ht_file->local_path); + +#ifndef _WIN32 + + struct stat file_stat; + + if ( stat(cl_ht_file->local_path, &file_stat) != 0 ) + goto err; + + cl_ht->out_last_modified = file_stat.st_mtime; + cl_ht->out_content_length = file_stat.st_size; + +#else + + FILETIME CreationTime; + FILETIME LastAccessTime; + FILETIME LastWriteTime; + + HANDLE fileh = CreateFileA( cl_ht_file->local_path, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_ARCHIVE, + NULL + ); + + if ( fileh == INVALID_HANDLE_VALUE ) + goto err; + + GetFileTime( fileh, + &CreationTime, + &LastAccessTime, + &LastWriteTime ); + + cl_ht->out_last_modified = FileTimeToUnixTime( LastWriteTime ); + cl_ht->out_content_length = GetFileSize( fileh, NULL ); + + CloseHandle( fileh ); + +#endif + + cl_ht_file->fd = fopen( cl_ht_file->local_path, "rb" ); + + if ( cl_ht_file->fd == NULL ) { + log_it(L_ERROR, "Can't open %s: %s",cl_ht_file->local_path,strerror(errno)); + cl_ht->reply_status_code = Http_Status_NotFound; + strncpy( cl_ht->reply_reason_phrase, "Not Found", sizeof(cl_ht->reply_reason_phrase)-1 ); + } + else { + cl_ht->reply_status_code = Http_Status_OK; + strncpy( cl_ht->reply_reason_phrase,"OK",sizeof(cl_ht->reply_reason_phrase)-1 ); + + const char *mime_type = magic_file( up_folder->mime_detector, cl_ht_file->local_path ); + if( mime_type ) { + strncpy(cl_ht->out_content_type,mime_type,sizeof(cl_ht->out_content_type)-1); + log_it( L_DEBUG, "MIME type detected: '%s'", mime_type ); + } + else { + cl_ht->reply_status_code=Http_Status_NotFound; + cl_ht->esocket->flags |= DAP_SOCK_SIGNAL_CLOSE; + log_it(L_WARNING,"Can't detect MIME type of %s file: %s",cl_ht_file->local_path,magic_error(up_folder->mime_detector)); + } + } + + return; + +err: + + log_it( L_WARNING, "Can't get file info: %s", strerror(errno) ); + cl_ht->reply_status_code = 404; + strncpy( cl_ht->reply_reason_phrase, "Not Found", sizeof(cl_ht->reply_reason_phrase)-1 ); + + return; +} + +/** + * @brief dap_http_folder_read HTTP client callback for reading function for the folder processing + * @param cl_ht HTTP client instance + * @param arg Pointer to int with return bytes number + */ +void dap_http_folder_data_read(dap_http_client_t * cl_ht, void * arg) +{ + int * bytes_return = (int*) arg; // Return number of read bytes + //Do nothing + *bytes_return=cl_ht->esocket->buf_in_size; +} + +/** + * @brief dap_http_folder_write HTTP client callback for writting function for the folder processing + * @param cl_ht HTTP client instance + * @param arg + */ +void dap_http_folder_data_write(dap_http_client_t * cl_ht, void * arg) +{ + (void) arg; + dap_http_file_t * cl_ht_file= DAP_HTTP_FILE(cl_ht); + cl_ht->esocket->buf_out_size=fread(cl_ht->esocket->buf_out,1,sizeof(cl_ht->esocket->buf_out),cl_ht_file->fd); + cl_ht_file->position+=cl_ht->esocket->buf_out_size; + + if(feof(cl_ht_file->fd)!=0){ + log_it(L_INFO, "All the file %s is sent out",cl_ht_file->local_path); + //strncat(cl_ht->client->buf_out+cl_ht->client->buf_out_size,"\r\n",sizeof(cl_ht->client->buf_out)); + fclose(cl_ht_file->fd); + dap_events_socket_set_writable_unsafe(cl_ht->esocket,false); + + if ( !cl_ht->keep_alive ) + cl_ht->esocket->flags |= DAP_SOCK_SIGNAL_CLOSE; + + cl_ht->state_write=DAP_HTTP_CLIENT_STATE_NONE; + } +} + -- GitLab