diff --git a/CMakeLists.txt b/CMakeLists.txt index 6de87bba9ddb0b42997f6ecd3b82b13ec3697435..186815417b360a71e84f45a30e09225b0c71f5e3 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,7 +19,8 @@ if(NOT (${SUBMODULES_NO_BUILD} MATCHES ON)) add_subdirectory(test) endif() -set(DAP_UDP_SERVER_SRCS dap_udp_server.c dap_udp_client.h dap_udp_client.c ) +set(DAP_UDP_SERVER_SRCS dap_udp_server.c dap_udp_client.c dap_dns_server.c) +set(DAP_UDP_SERVER_HEADERS dap_udp_server.h dap_udp_client.h dap_dns_server.h) if(WIN32) include_directories(../libdap/src/win32/) @@ -32,6 +33,6 @@ endif() add_library(${PROJECT_NAME} STATIC ${DAP_UDP_SERVER_SRCS}) -target_link_libraries(${PROJECT_NAME} dap_core dap_server_core ) +target_link_libraries(${PROJECT_NAME} dap_core dap_server_core dap_chain_net) target_include_directories(${PROJECT_NAME} INTERFACE .) diff --git a/dap_dns_server.c b/dap_dns_server.c new file mode 100755 index 0000000000000000000000000000000000000000..99bb525ce5f3167ab1d1d9ed7519e81d4466372a --- /dev/null +++ b/dap_dns_server.c @@ -0,0 +1,330 @@ +/* + * Authors: + * Roman Khlopkov <roman.khlopkov@demlabs.net> + * DeM Labs Inc. https://demlabs.net + * DeM Labs Open source community https://gitlab.demlabs.net + * Copyright (c) 2017-2020 + * All rights reserved. + + This file is part of DAP (Deus Applications Prototypes) the open source project + + DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + DAP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with any DAP based project. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "dap_dns_server.h" +#include "dap_udp_server.h" +#include "dap_udp_client.h" +#include "dap_client_remote.h" +#include "dap_common.h" +#include "dap_chain_net.h" +#include "dap_chain_node.h" +#include "dap_string.h" +#include "dap_chain_global_db.h" +#include "dap_chain_global_db_remote.h" + +#define UNUSED(x) (void)(x) +#define LOG_TAG "dap_dns_server" + +static dap_dns_server_t *s_dns_server; +static char s_root_alias[] = "dnsroot"; + +/** + * @brief dap_dns_buf_init Initialize DNS parser buffer + * @param buf DNS buffer structure + * @param msg DNS message + * @return none + */ +void dap_dns_buf_init(dap_dns_buf_t *buf, char *msg) { + buf->data = msg; + buf->ptr = 0; +} + +/** + * @brief dap_dns_buf_get_uint16 Get uint16 from network order + * @param buf DNS buffer structure + * @return uint16 in host order + */ +uint16_t dap_dns_buf_get_uint16(dap_dns_buf_t *buf) { + char c; + c = buf->data[buf->ptr++]; + return c << 8 | buf->data[buf->ptr++]; +} + +/** + * @brief dap_dns_buf_put_uint16 Put uint16 to network order + * @param buf DNS buffer structure + * @param val uint16 in host order + * @return none + */ +void dap_dns_buf_put_uint16(dap_dns_buf_t *buf, uint16_t val) { + buf->data[buf->ptr++] = val >> 8; + buf->data[buf->ptr++] = val; +} + +/** + * @brief dap_dns_buf_put_uint32 Put uint32 to network order + * @param buf DNS buffer structure + * @param val uint32 in host order + * @return none + */ +void dap_dns_buf_put_uint32(dap_dns_buf_t *buf, uint32_t val) { + dap_dns_buf_put_uint16(buf, val >> 16); + dap_dns_buf_put_uint16(buf, val); +} + +uint32_t dap_dns_resolve_hostname(char *str) { + log_it(L_DEBUG, "DNS parser retrieve hostname %s", str); + dap_chain_net_t *l_net = dap_chain_net_by_name("kelvin-testnet"); + // get nodes list from global_db + dap_global_db_obj_t *l_objs = NULL; + size_t l_nodes_count = 0; + // read all node + l_objs = dap_chain_global_db_gr_load(l_net->pub.gdb_nodes, &l_nodes_count); + if(!l_nodes_count || !l_objs) + return 0; + size_t l_node_num = rand() % l_nodes_count; + dap_chain_node_info_t *l_node_info = (dap_chain_node_info_t *) l_objs[l_node_num].value; + uint32_t addr = l_node_info->hdr.ext_addr_v4.s_addr; + dap_chain_global_db_objs_delete(l_objs, l_nodes_count); + log_it(L_DEBUG, "DNS resolver find ip %d.%d.%d.%d", addr & 0xFF, (addr >> 8) & 0xFF, (addr >> 16) & 0xFF, (addr >> 24) & 0xFF); + return addr; +} + +/** + * @brief dap_dns_zone_register Register DNS zone and set callback to handle it + * @param zone Name of zone to register + * @param callback Callback to handle DNS zone + * @return 0 if success, else return error code + */ +int dap_dns_zone_register(char *zone, dap_dns_zone_callback_t callback) { + dap_dns_zone_hash_t *new_zone; + HASH_FIND_STR(s_dns_server->hash_table, zone, new_zone); + if (new_zone == NULL) { // zone is not present + new_zone = DAP_NEW(dap_dns_zone_hash_t); + new_zone->zone = dap_strdup(zone); + HASH_ADD_KEYPTR(hh, s_dns_server->hash_table, new_zone->zone, strlen(new_zone->zone), new_zone); + } // if zone present, just reassign callback + new_zone->callback = callback; + return DNS_ERROR_NONE; +} + +/** + * @brief dap_dns_zone_unregister Unregister DNS zone + * @param zone Name of zone to unregister + * @return 0 if success, else return error code + */ +int dap_dns_zone_unregister(char *zone) { + dap_dns_zone_hash_t *asked_zone; + HASH_FIND_STR(s_dns_server->hash_table, zone, asked_zone); + if (asked_zone == NULL) { + return DNS_ERROR_NAME; + } + HASH_DEL(s_dns_server->hash_table, asked_zone); + DAP_DELETE(asked_zone->zone); + DAP_DELETE(asked_zone); + return DNS_ERROR_NONE; +} + +/** + * @brief dap_dns_zone_find Find callback to registered DNS zone + * @param hostname Name of host for which the zone callback being searched + * @return Callback for registered DNS zone, else return NULL + */ +dap_dns_zone_callback_t dap_dns_zone_find(char *hostname) { + dap_dns_zone_hash_t *asked_zone; + HASH_FIND_STR(s_dns_server->hash_table, hostname, asked_zone); + if (asked_zone == NULL) { + if (!strcmp(hostname, &s_root_alias[0])) { + return NULL; + } + char *zone_up = strchr(hostname, '.') + 1; + if (zone_up == 1) { + zone_up = &s_root_alias[0]; + } + return dap_dns_zone_find(zone_up); + } else { + return asked_zone->callback; + } + return NULL; +} + +/** + * @brief dap_dns_client_read Read and parse incoming DNS message, send reply to it + * @param client DAP client remote structure + * @param arg Unused + * @return none + */ +void dap_dns_client_read(dap_client_remote_t *client, void * arg) { + UNUSED(arg); + if (client->buf_in_size < DNS_HEADER_SIZE) { // Bad request + return; + } + dap_dns_buf_t *dns_message = DAP_NEW(dap_dns_buf_t); + dap_dns_buf_t *dns_reply = DAP_NEW(dap_dns_buf_t); + dns_message->data = DAP_NEW_SIZE(char, client->buf_in_size + 1); + dns_message->data[client->buf_in_size] = 0; + dap_client_remote_read(client, dns_message->data, client->buf_in_size); + dns_message->ptr = 0; + + // Parse incoming DNS message + int block_len = DNS_HEADER_SIZE; + dns_reply->data = DAP_NEW_SIZE(char, block_len); + dns_reply->ptr = 0; + uint16_t val = dap_dns_buf_get_uint16(dns_message); // ID + dap_dns_buf_put_uint16(dns_reply, val); + val = dap_dns_buf_get_uint16(dns_message); // Flags + dns_reply->ptr += sizeof(uint16_t); // Put flags later + dap_dns_message_flags_t msg_flags; + msg_flags.val = val; + dap_dns_message_flags_bits_t *flags = &msg_flags.flags; + if (flags->qr) { // It's not request + goto cleanup; + } + flags->rcode = DNS_ERROR_NONE; + flags->qr = 1; // Response bit set + if (flags->tc) { // Truncated messages not supported yet + flags->rcode = DNS_ERROR_NOT_SUPPORTED; + } + flags->ra = 0; // Recursion not supported yet + flags->aa = 1; // Authoritative answer + uint16_t qdcount = dap_dns_buf_get_uint16(dns_message); + dap_dns_buf_put_uint16(dns_reply, qdcount); + val = dap_dns_buf_get_uint16(dns_message); // AN count + if (val) { // No other sections should present + goto cleanup; + } + dap_dns_buf_put_uint16(dns_reply, 1); // 1 answer section + val = dap_dns_buf_get_uint16(dns_message); // NS count + if (val) { // No other sections should present + goto cleanup; + } + dap_dns_buf_put_uint16(dns_reply, val); + val = dap_dns_buf_get_uint16(dns_message); // AR count + if (val) { // No other sections should present + goto cleanup; + } + dap_dns_buf_put_uint16(dns_reply, val); + int dot_count = 0; + dap_string_t *dns_hostname = dap_string_new(""); + for (int i = 0; i < qdcount; i++) { + block_len = strlen(&dns_message->data[dns_message->ptr]) + 1 + 2 * sizeof(uint16_t); + dns_reply->data = DAP_REALLOC(dns_reply->data, dns_reply->ptr + block_len); + memcpy(&dns_reply->data[dns_reply->ptr], &dns_message->data[dns_message->ptr], block_len); + dns_reply->ptr += block_len; + if (flags->rcode) + break; + while (dns_message->ptr < dns_reply->ptr - 2 * sizeof(uint16_t)) { + uint8_t len = dns_message->data[dns_message->ptr++]; + if (len > DNS_MAX_DOMAIN_NAME_LEN) { + flags->rcode = DNS_ERROR_NAME; + break; + } + if (!len) { + break; + } + if (dot_count) { + if (dot_count > 3) { // Max three dots allowed + flags->rcode = DNS_ERROR_NAME; + break; + } + dap_string_append(dns_hostname, "."); + } + dap_string_append_len(dns_hostname, &dns_message->data[dns_message->ptr], len); + dns_message->ptr += len; + dot_count++; + if (dns_hostname->len >= DNS_MAX_HOSTNAME_LEN) { + flags->rcode = DNS_ERROR_NAME; + break; + } + } + val = dap_dns_buf_get_uint16(dns_message); // DNS record type + if (val != DNS_RECORD_TYPE_A) { // Only host address ipv4 + flags->rcode = DNS_ERROR_NOT_SUPPORTED; + break; + } + val = dap_dns_buf_get_uint16(dns_message); // DNS class type + if (val != DNS_CLASS_TYPE_IN) { // Internet only + flags->rcode = DNS_ERROR_NOT_SUPPORTED; + break; + } + if (dns_message->ptr != dns_reply->ptr) { + log_it(L_ERROR, "DNS parser pointer unequal, mptr = %u, rptr = %u", dns_message->ptr, dns_reply->ptr); + } + } + // Find ip addr + uint32_t ip_addr = 0; + if (flags->rcode == DNS_ERROR_NONE) { + dap_dns_zone_callback_t callback = dap_dns_zone_find(dns_hostname->str); + if (callback) { + ip_addr = callback(dns_hostname->str); + } + } + if (ip_addr) { + // Compose DNS answer + block_len = DNS_ANSWER_SIZE; + dns_reply->data = DAP_REALLOC(dns_reply->data, dns_reply->ptr + block_len); + val = 0xc000 || DNS_HEADER_SIZE; // Link to host name + dap_dns_buf_put_uint16(dns_reply, val); + val = DNS_RECORD_TYPE_A; + dap_dns_buf_put_uint16(dns_reply, val); + val = DNS_CLASS_TYPE_IN; + dap_dns_buf_put_uint16(dns_reply, val); + uint32_t ttl = DNS_TIME_TO_LIVE; + dap_dns_buf_put_uint32(dns_reply, ttl); + val = 4; // RD len for ipv4 + dap_dns_buf_put_uint16(dns_reply, val); + dap_dns_buf_put_uint32(dns_reply, ip_addr); + } else if (flags->rcode == DNS_ERROR_NONE) { + flags->rcode = DNS_ERROR_NAME; + } + if (flags->rcode) { + dns_reply->data[7] = 0; // No answer section + } + // Set reply flags + dns_reply->data[2] = msg_flags.val >> 8; + dns_reply->data[3] = msg_flags.val; + // Send DNS reply + dap_udp_client_write(client, dns_reply->data, dns_reply->ptr); + dap_udp_client_ready_to_write(client, true); + dap_string_free(dns_hostname, true); +cleanup: + DAP_DELETE(dns_reply->data); + DAP_DELETE(dns_message->data); + DAP_DELETE(dns_reply); + DAP_DELETE(dns_message); + return; +} + +void dap_dns_server_start() { + s_dns_server = DAP_NEW(dap_dns_server_t); + s_dns_server->hash_table = NULL; + s_dns_server->instance = dap_udp_server_listen(DNS_LISTEN_PORT); + s_dns_server->instance->client_read_callback = *dap_dns_client_read; + s_dns_server->instance->client_write_callback = NULL; + s_dns_server->instance->client_new_callback = NULL; + s_dns_server->instance->client_delete_callback = NULL; + dap_dns_zone_register(&s_root_alias[0], dap_dns_resolve_hostname); // root resolver + pthread_create(&s_dns_server->udp_thread, NULL, (void *)dap_udp_server_loop, s_dns_server->instance); +} + +void dap_dns_server_stop() { + dap_dns_zone_hash_t *current_zone, *tmp; + HASH_ITER(hh, s_dns_server->hash_table, current_zone, tmp) { + HASH_DEL(s_dns_server->hash_table, current_zone); + DAP_DELETE(current_zone->zone); + DAP_DELETE(current_zone); + } + // TODO add code to stop udp_thread + dap_udp_server_delete(s_dns_server->instance); +} diff --git a/dap_dns_server.h b/dap_dns_server.h new file mode 100755 index 0000000000000000000000000000000000000000..6743732de06df3cd20c9a62f5d8fa8846ed45352 --- /dev/null +++ b/dap_dns_server.h @@ -0,0 +1,125 @@ +/* + * Authors: + * Roman Khlopkov <roman.khlopkov@demlabs.net> + * DeM Labs Inc. https://demlabs.net + * DeM Labs Open source community https://gitlab.demlabs.net + * Copyright (c) 2017-2020 + * All rights reserved. + + This file is part of DAP (Deus Applications Prototypes) the open source project + + DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + DAP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with any DAP based project. If not, see <http://www.gnu.org/licenses/>. +*/ + +#pragma once + +#ifdef _WIN32 +#include <pthread.h> +#endif +#include "dap_server.h" +#include "uthash.h" + +#define DNS_LISTEN_PORT 53 // UDP +#define DNS_TIME_TO_LIVE 600 // Seconds +#define DNS_HEADER_SIZE 12 +#define DNS_ANSWER_SIZE 16 +#define DNS_MAX_HOSTNAME_LEN 255 +#define DNS_MAX_DOMAIN_NAME_LEN 63 + +typedef enum _dap_dns_query_type_t { + DNS_QUERY_TYPE_STANDARD, + DNS_QUERY_TYPE_INVERSE, + DNS_QUERY_TYPE_STATUS +} dap_dns_query_type_t; + +typedef enum _dap_dns_error_t { + DNS_ERROR_NONE, // No error + DNS_ERROR_FORMAT, // DNS message parsing error + DNS_ERROR_FAILURE, // Internal server error + DNS_ERROR_NAME, // Only for authoritative servers. Name does not exist + DNS_ERROR_NOT_SUPPORTED,// This kind of query not implemented + DNS_ERROR_REFUSED // Operation refused +} dap_dns_error_t; + +typedef enum _dap_dns_record_type_t { + DNS_RECORD_TYPE_A = 1, // Host address + DNS_RECORD_TYPE_NS, // Authoritative name server + DNS_RECORD_TYPE_MD, // Mail destination (obsolete, use MX) + DNS_RECORD_TYPE_MF, // Mail forwarder (obsolete, use MX) + DNS_RECORD_TYPE_CNAME, // Canonical name of alias + DNS_RECORD_TYPE_SOA, // Marks a start of a zone of authority + DNS_RECORD_TYPE_MB, // Mailbox domain name (experimental) + DNS_RECORD_TYPE_MG, // Mail group member (experimental) + DNS_RECORD_TYPE_MR, // Mail rename domain name (experimental) + DNS_RECORD_TYPE_NULL, // NULL resource record (experimental) + DNS_RECORD_TYPE_WKS, // Well known server description + DNS_RECORD_TYPE_PTR, // Domain name pointer + DNS_RECORD_TYPE_HINFO, // Host information + DNS_RECORD_TYPE_MINFO, // Mail box or list information + DNS_RECORD_TYPE_MX, // Mail exchange + DNS_RECORD_TYPE_TXT, // Text strings + DNS_RECORD_TYPE_RP, // Responsible person + DNS_RECORD_TYPE_AXFR = 252, // A request for a transfer of an entire zone - QTYPE only + DNS_RECORD_TYPE_MAILB, // A request for mailbox-related records (MB, MG or MR) - QTYPE only + DNS_RECORD_TYPE_MAILA, // A request for mail agent RRs (obsolete - see MX) - QTYPE only + DNS_RECORD_TYPE_ANY // A request for all records - QTYPE only +} dap_dns_record_type_t; + +typedef enum _dap_dns_class_type_t { + DNS_CLASS_TYPE_IN = 1, // Internet + DNS_CLASS_TYPE_CS, // CSNET (obsolete) + DNS_CLASS_TYPE_CH, // CHAOS + DNS_CLASS_TYPE_HS, // Hesiod [Dyer 87] + DNS_CLASS_TYPE_ANY = 255 // Any class +} dap_dns_class_type_t; + +typedef struct _dap_dns_message_flags_bits_t { + int rcode : 4; // response code, answer only: 0 - no error, 1 - format error, 2 - server failure, 3 - name error, 4 - not supported, 5 - refused + int z : 3; // reserved, must be zero + int ra : 1; // 1 - recursion available (answer only) + int rd : 1; // 1 - recursion desired (query set, copied to answer) + int tc : 1; // 1 - message truncated + int aa : 1; // 1 - authoritative answer (answer only) + int opcode : 4; // type of query, copied to answer: 0 - standard, 1 - inverse, 2 - status, 3-15 - reserved + int qr : 1; // 0 - query, 1 - response +} dap_dns_message_flags_bits_t; + +typedef uint32_t (*dap_dns_zone_callback_t) (char *hostname); // Callback for DNS zone operations + +typedef union _dap_dns_message_flags_t { + dap_dns_message_flags_bits_t flags; + int val; +} dap_dns_message_flags_t; + +typedef struct _dap_dns_buf_t { + char *data; + uint32_t ptr; +} dap_dns_buf_t; + +typedef struct _dap_dns_zone_hash_t { + char *zone; + dap_dns_zone_callback_t callback; + UT_hash_handle hh; +} dap_dns_zone_hash_t; + +typedef struct _dap_dns_server_t { + dap_server_t *instance; + pthread_t udp_thread; + dap_dns_zone_hash_t *hash_table; +} dap_dns_server_t; + +void dap_dns_server_start(); +void dap_dns_server_stop(); +int dap_dns_zone_register(char *zone, dap_dns_zone_callback_t callback); +int dap_dns_zone_unregister(char *zone); diff --git a/dap_udp_client.c b/dap_udp_client.c index 8e72f5682d0a6902a41f2a7c758d7f3119fd0c78..ab13f7de654ba89a6184c4c38eb71a4e7a3c9d28 100755 --- a/dap_udp_client.c +++ b/dap_udp_client.c @@ -60,6 +60,7 @@ * @return 64 bit Key */ #define get_key( host, key ) (((uint64_t)host << 32) + (uint64_t)port) +extern bool sb_payload_ready; /** * @brief udp_client_create Create new client and add it to hashmap @@ -72,7 +73,7 @@ dap_client_remote_t *dap_udp_client_create( dap_server_t *dap_srv, EPOLL_HANDLE efd, unsigned long host, unsigned short port ) { dap_udp_server_t *udp_server = DAP_UDP_SERVER( dap_srv ); - log_it( L_DEBUG, "Client structure create" ); + log_it( L_DEBUG, "Client structure create with host = %x, port = %d", host, port ); dap_udp_client_t *inh = DAP_NEW_Z( dap_udp_client_t ); inh->host_key = get_key( host, port ); @@ -112,11 +113,11 @@ dap_client_remote_t *dap_udp_client_create( dap_server_t *dap_srv, EPOLL_HANDLE * @param host Variable for host address * @param host Variable for port */ -void dap_udp_client_get_address( dap_client_remote_t *client, unsigned int* host, unsigned short* port ) +void dap_udp_client_get_address( dap_client_remote_t *client, unsigned int* host, unsigned short* port ) { dap_udp_client_t* udp_client = DAP_UDP_CLIENT( client ); *host = udp_client->host_key >> 32; - *port = (udp_client->host_key <<32) - *host; + *port = udp_client->host_key; } /** @@ -134,7 +135,7 @@ dap_client_remote_t *dap_udp_client_find( dap_server_t *dap_srv, unsigned long h uint64_t token = get_key( host, port ); pthread_mutex_lock( &udp_server->mutex_on_list ); - HASH_FIND_INT( udp_server->hclients, &token, inh ); + HASH_FIND_INT( udp_server->hclients, &token, inh ); pthread_mutex_unlock( &udp_server->mutex_on_list ); if( inh == NULL ) @@ -187,14 +188,18 @@ void dap_udp_client_ready_to_write( dap_client_remote_t *sc, bool 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; + { + dap_udp_server_t *udp_server = DAP_UDP_SERVER(sc->server); + pthread_mutex_lock(&udp_server->mutex_on_list); + sb_payload_ready = true; + pthread_mutex_unlock(&udp_server->mutex_on_list ); + } sc->pevent.events = events; diff --git a/dap_udp_server.c b/dap_udp_server.c index 49ed82a21b40fac069a22b8fa448f9ec65c2024e..f6f8e02bd5b06160a32ac85690b7dabd5a9945f8 100755 --- a/dap_udp_server.c +++ b/dap_udp_server.c @@ -59,12 +59,11 @@ #define BUFSIZE 1024 char buf[ BUFSIZE ]; /* message buf */ - +bool sb_payload_ready; //struct ev_io w_read; //struct ev_io w_write; EPOLL_HANDLE efd_read = (EPOLL_HANDLE)-1; -EPOLL_HANDLE efd_write = (EPOLL_HANDLE)-1; //static void write_cb( EPOLL_HANDLE efd, int revents ); @@ -72,7 +71,7 @@ int check_close( dap_client_remote_t *client ); /** */ -void error( char *msg ) { +static void error( char *msg ) { perror( msg ); exit( 1 ); @@ -126,7 +125,7 @@ void dap_udp_server_delete( dap_server_t *sh ) /** * @brief dap_udp_server_listen Create and bind server structure * @param port Binding port - * @return Server instance + * @return Server instance */ dap_server_t *dap_udp_server_listen( uint16_t port ) { @@ -155,7 +154,7 @@ dap_server_t *dap_udp_server_listen( uint16_t port ) { dap_udp_server_delete( sh ); return NULL; } - + log_it(L_INFO, "UDP server listening port 0.0.0.0:%d", port); pthread_mutex_init( &DAP_UDP_SERVER(sh)->mutex_on_list, NULL ); pthread_mutex_init( &DAP_UDP_SERVER(sh)->mutex_on_hash, NULL ); @@ -188,14 +187,15 @@ static void write_cb( EPOLL_HANDLE efd, int revents, dap_server_t *sh ) if ( client->buf_out_size > 0 ) { - //log_it(L_INFO,"write_cb_client"); + + struct sockaddr_in addr; + addr.sin_family = AF_INET; + dap_udp_client_get_address( client, (unsigned int *)&addr.sin_addr.s_addr, &addr.sin_port ); + //log_it(L_INFO,"write_cb_client host = %x, port = %d, socket = %x", addr.sin_addr.s_addr, addr.sin_port, sh->socket_listener); for( size_t total_sent = 0; total_sent < client->buf_out_size; ) { - struct sockaddr_in addr; - addr.sin_family = AF_INET; - dap_udp_client_get_address( client, (unsigned int *)&addr.sin_addr.s_addr, &addr.sin_port ); - int bytes_sent = sendto( sh->socket_listener, client->buf_out + total_sent, + int bytes_sent = sendto( sh->socket_listener, client->buf_out + total_sent, client->buf_out_size - total_sent, 0, (struct sockaddr*) &addr, sizeof(addr) ); if ( bytes_sent < 0 ) { @@ -206,6 +206,8 @@ static void write_cb( EPOLL_HANDLE efd, int revents, dap_server_t *sh ) } client->buf_out_size = 0; memset( client->buf_out, 0, DAP_CLIENT_REMOTE_BUF + 1 ); + client->flags &= ~DAP_SOCK_READY_TO_WRITE; + sb_payload_ready = false; } LL_DELETE( udp->waiting_clients, udp_client ); } @@ -302,7 +304,7 @@ static void read_cb( EPOLL_HANDLE efd, int revents, dap_server_t *sh ) if ( sh->client_read_callback ) sh->client_read_callback( client, NULL ); - + bytes_processed += bytes_to_transfer; bytes_recieved -= bytes_to_transfer; } @@ -325,66 +327,21 @@ static void read_cb( EPOLL_HANDLE efd, int revents, dap_server_t *sh ) } } -/** - * @brief dap_udp_client_loop Create client listening event loop - */ -void *dap_udp_client_loop( void *arg ) -{ - dap_server_t *d_server = (dap_server_t *)arg; - struct epoll_event pev; - struct epoll_event events[ 16 ]; - - pev.events = EPOLLOUT | EPOLLERR; - pev.data.fd = d_server->socket_listener; - - if ( epoll_ctl( efd_write, EPOLL_CTL_ADD, d_server->socket_listener, &pev) != 0 ) { - log_it( L_ERROR, "epoll_ctl failed 001" ); - return NULL; - } - - log_it( L_NOTICE, "Start client write thread" ); - - do { - - int32_t n = epoll_wait( efd_write, events, 16, -1 ); - - if ( n == -1 ) - break; - - for ( int32_t i = 0; i < n; ++ i ) { - - if ( events[i].events & EPOLLOUT ) { - write_cb( efd_write, events[i].events, d_server ); - } - else if( events[i].events & EPOLLERR ) { - log_it( L_ERROR, "Server socket error event" ); - break; - } - } - - } while( 1 ); - - return NULL; -} - - /** * @brief dap_udp_server_loop Start server event loop * @param sh Server instance */ void dap_udp_server_loop( dap_server_t *d_server ) { - EPOLL_HANDLE efd_read = epoll_create1( 0 ); - EPOLL_HANDLE efd_write = epoll_create1( 0 ); - pthread_t thread; + efd_read = epoll_create1( 0 ); - if ( (intptr_t)efd_read == -1 || (intptr_t)efd_write == -1 ) { + if ( (intptr_t)efd_read == -1 ) { log_it( L_ERROR, "epoll_create1 failed" ); - goto error; + goto udp_error; } - pthread_create( &thread, NULL, dap_udp_client_loop, d_server ); + sb_payload_ready = false; struct epoll_event pev; struct epoll_event events[ 16 ]; @@ -394,7 +351,7 @@ void dap_udp_server_loop( dap_server_t *d_server ) if ( epoll_ctl( efd_read, EPOLL_CTL_ADD, d_server->socket_listener, &pev) != 0 ) { log_it( L_ERROR, "epoll_ctl failed 000" ); - goto error; + goto udp_error; } while( 1 ) { @@ -415,21 +372,25 @@ void dap_udp_server_loop( dap_server_t *d_server ) if ( events[i].events & EPOLLIN ) { read_cb( efd_read, events[i].events, d_server ); } - else if( events[i].events & EPOLLERR ) { + if ( events[i].events & EPOLLOUT) { + // Do nothing. It always true until socket eturn EAGAIN + } + if (sb_payload_ready) { + write_cb( efd_read, events[i].events, d_server ); + } + if( events[i].events & EPOLLERR ) { log_it( L_ERROR, "Server socket error event" ); - goto error; + goto udp_error; } } } -error: +udp_error: #ifndef _WIN32 if ( efd_read != -1 ) close( efd_read ); - if ( efd_write != -1 ) - close( efd_write ); #else if ( efd_read != INVALID_HANDLE_VALUE ) epoll_close( efd_read );