diff --git a/libdap-server-udp b/libdap-server-udp deleted file mode 160000 index fddad31ed0785452ab0aad35a0746533e6713653..0000000000000000000000000000000000000000 --- a/libdap-server-udp +++ /dev/null @@ -1 +0,0 @@ -Subproject commit fddad31ed0785452ab0aad35a0746533e6713653 diff --git a/libdap-server-udp/.gitignore b/libdap-server-udp/.gitignore new file mode 100755 index 0000000000000000000000000000000000000000..e8451f4157a6dbae7124d7380a2ebf1a0119f53f --- /dev/null +++ b/libdap-server-udp/.gitignore @@ -0,0 +1,2 @@ +CMakeLists.txt.user +test/build diff --git a/libdap-server-udp/.gitmodules b/libdap-server-udp/.gitmodules new file mode 100755 index 0000000000000000000000000000000000000000..c6856fada453ee5dc89ecf69e8c157ccdba96757 --- /dev/null +++ b/libdap-server-udp/.gitmodules @@ -0,0 +1,12 @@ +[submodule "test/libdap-test"] + path = test/libdap-test + url = https://gitlab.demlabs.net/cellframe/libdap-test + branch = master +[submodule "libdap"] + path = libdap + url = https://gitlab.demlabs.net/cellframe/libdap + branch = master +[submodule "libdap-server-core"] + path = libdap-server-core + url = https://gitlab.demlabs.net/cellframe/libdap-server-core + branch = master diff --git a/libdap-server-udp/.travis.yml b/libdap-server-udp/.travis.yml new file mode 100755 index 0000000000000000000000000000000000000000..256452d22b659f80791b9ef389c823db745803da --- /dev/null +++ b/libdap-server-udp/.travis.yml @@ -0,0 +1,25 @@ +sudo: required +language: cpp +compiler: c +dist: xenial +notifications: + email: false + +before_install: + - git submodule init + - git submodule update --recursive + +script: + - mkdir build + - cd build + - cmake -DBUILD_DAP_UDP_SERVER_TESTS=ON ../ + - make + - ctest --verbose + +addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - libev-dev + diff --git a/libdap-server-udp/CMakeLists.txt b/libdap-server-udp/CMakeLists.txt new file mode 100755 index 0000000000000000000000000000000000000000..6e1e123bf79ab592cae3ac2d82494833fdb172fa --- /dev/null +++ b/libdap-server-udp/CMakeLists.txt @@ -0,0 +1,35 @@ +cmake_minimum_required(VERSION 3.1) +project (dap_udp_server C) + +if(NOT SUBMODULES_NO_BUILD) + +# if ( NOT ( TARGET dap_server_core ) ) +# add_subdirectory(libdap-server-core) +# endif() + + if ( NOT ( TARGET dap_core ) ) + add_subdirectory(libdap) + endif() + + if ( NOT ( TARGET dap_server_core ) ) + add_subdirectory(libdap-server-core) + endif() + + enable_testing() + add_subdirectory(test) +endif() + +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(../3rdparty/wepoll/) + include_directories(../3rdparty/uthash/src/) + #include_directories(../3rdparty/curl/include/) +endif() + +add_library(${PROJECT_NAME} STATIC ${DAP_UDP_SERVER_SRCS}) + +target_link_libraries(${PROJECT_NAME} dap_core dap_server_core dap_chain_net) + +target_include_directories(${PROJECT_NAME} INTERFACE .) diff --git a/libdap-server-udp/README.md b/libdap-server-udp/README.md new file mode 100755 index 0000000000000000000000000000000000000000..fd721b1b5275b5e23bf6e83fb70f3dad69b08b0d --- /dev/null +++ b/libdap-server-udp/README.md @@ -0,0 +1,3 @@ +# libdap-server-udp + +[](https://travis-ci.com/kelvinblockchain/libdap-server-udp) diff --git a/libdap-server-udp/dap_dns_server.c b/libdap-server-udp/dap_dns_server.c new file mode 100755 index 0000000000000000000000000000000000000000..a93c8f55cd8720f6f481afdc8619ba898a35f4f8 --- /dev/null +++ b/libdap-server-udp/dap_dns_server.c @@ -0,0 +1,336 @@ +/* + * 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, '.'); + if (zone_up++ == NULL) { + 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); + if (!s_dns_server->instance) { + log_it(L_ERROR, "Can't star DNS server"); + return; + } + s_dns_server->instance->client_read_callback = dap_dns_client_read; + 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); + DAP_DELETE(s_dns_server); +} diff --git a/libdap-server-udp/dap_dns_server.h b/libdap-server-udp/dap_dns_server.h new file mode 100755 index 0000000000000000000000000000000000000000..6743732de06df3cd20c9a62f5d8fa8846ed45352 --- /dev/null +++ b/libdap-server-udp/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/libdap-server-udp/dap_udp_client.c b/libdap-server-udp/dap_udp_client.c new file mode 100755 index 0000000000000000000000000000000000000000..ab13f7de654ba89a6184c4c38eb71a4e7a3c9d28 --- /dev/null +++ b/libdap-server-udp/dap_udp_client.c @@ -0,0 +1,253 @@ +/* + Copyright (c) 2017-2019 (c) Project "DeM Labs Inc" https://demlabs.net + 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/>. +*/ + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.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/select.h> +#include <sys/queue.h> +#include <errno.h> +#include <netdb.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/epoll.h> +#else +#include <winsock2.h> +#include <windows.h> +#include <mswsock.h> +#include <ws2tcpip.h> +#include <io.h> +#include <pthread.h> +#endif + +#include "uthash.h" +#include "utlist.h" + +#include "dap_common.h" +#include "dap_udp_client.h" +#include "dap_udp_server.h" + +#define LOG_TAG "udp_client" + +/** + * @brief get_key Make key for hash table from host and port + * @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 + * @param sh Server instance + * @param host Client host address + * @param w_client Clients event loop watcher + * @param port Client port + * @return Pointer to the new list's node + */ +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 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 ); + + dap_client_remote_t *ret = DAP_NEW_Z( dap_client_remote_t ); + inh->client = ret; + + ret->pevent.events = EPOLLIN | EPOLLERR; + ret->pevent.data.fd = dap_srv->socket_listener; + + ret->server = dap_srv; + ret->efd = efd; + + ret->flags = DAP_SOCK_READY_TO_READ; + +// ret->signal_close = false; +// ret->_ready_to_read = true; +// ret->_ready_to_write = false; + + ret->_inheritor = inh; + + pthread_mutex_init( &inh->mutex_on_client, NULL ); + + pthread_mutex_lock( &udp_server->mutex_on_list ); + HASH_ADD_INT( udp_server->hclients, host_key, inh ); + pthread_mutex_unlock( &udp_server->mutex_on_list ); + + if( dap_srv->client_new_callback ) + dap_srv->client_new_callback( ret, NULL ); // Init internal structure + + return ret; +} + +/** + * @brief udp_client_get_address Get host address and port of client + * @param client Pointer to client structure + * @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 ) +{ + dap_udp_client_t* udp_client = DAP_UDP_CLIENT( client ); + *host = udp_client->host_key >> 32; + *port = udp_client->host_key; +} + +/** + * @brief udp_client_find Find client structure by host address and port + * @param sh Server instance + * @param host Source host address + * @param port Source port + * @return Pointer to client or NULL if not found + */ +dap_client_remote_t *dap_udp_client_find( dap_server_t *dap_srv, unsigned long host, unsigned short port ) +{ + dap_udp_client_t *inh = NULL; + dap_udp_server_t *udp_server = DAP_UDP_SERVER( dap_srv ); + + uint64_t token = get_key( host, port ); + + pthread_mutex_lock( &udp_server->mutex_on_list ); + HASH_FIND_INT( udp_server->hclients, &token, inh ); + pthread_mutex_unlock( &udp_server->mutex_on_list ); + + if( inh == NULL ) + return NULL; + else + return inh->client; +} + +/** + * @brief udp_client_ready_to_read Set ready_to_read flag + * @param dap_rclient Client structure + * @param is_ready Flag value + */ +void dap_udp_client_ready_to_read( dap_client_remote_t *sc, bool is_ready ) +{ + if( is_ready == (bool)(sc->flags & DAP_SOCK_READY_TO_READ) ) + return; + + 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->server->socket_listener, &sc->pevent) != 0 ) { + log_it( L_ERROR, "epoll_ctl failed 002" ); + } +} + +/** + * @brief udp_client_ready_to_write Set ready_to_write flag + * @param dap_rclient Client structure + * @param is_ready Flag value + */ +void dap_udp_client_ready_to_write( dap_client_remote_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 ) + { + 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; + + if ( epoll_ctl(sc->efd, EPOLL_CTL_MOD, sc->pevent.data.fd, &sc->pevent) != 0 ) { + log_it( L_ERROR, "epoll_ctl failed 003" ); + } +} + +/** + * @brief add_waiting_client Add Client to write queue + * @param client Client instance + */ +void add_waiting_client( dap_client_remote_t *dap_rclient ) +{ + dap_udp_client_t* udp_cl, *tmp; + + dap_server_t *dap_srv = dap_rclient->server; + dap_udp_server_t *udp_server = DAP_UDP_SERVER( dap_srv ); + dap_udp_client_t *udp_client = DAP_UDP_CLIENT( dap_rclient ); + + pthread_mutex_lock( &udp_server->mutex_on_list ); + LL_FOREACH_SAFE( udp_server->waiting_clients, udp_cl, tmp ) { + if( udp_cl == udp_client ) { + pthread_mutex_unlock( &udp_server->mutex_on_list ); + return; + } + } + LL_APPEND( udp_server->waiting_clients, udp_client ); + pthread_mutex_unlock( &udp_server->mutex_on_list ); +} + +size_t dap_udp_client_write( dap_client_remote_t *dap_rclient, const void *data, size_t data_size ) +{ + size_t size = dap_client_remote_write( dap_rclient, data, data_size ); + add_waiting_client( dap_rclient ); + return size; +} + +size_t dap_udp_client_write_f( dap_client_remote_t *dap_rclient, const char * a_format, ... ) +{ + size_t size = 0; + va_list va; + + va_start( va, a_format ); + size = dap_client_remote_write_f( dap_rclient, a_format, va ); + va_end( va ); + + add_waiting_client( dap_rclient ); + return size; +} + diff --git a/libdap-server-udp/dap_udp_client.h b/libdap-server-udp/dap_udp_client.h new file mode 100755 index 0000000000000000000000000000000000000000..7fc66f14585e359c482b97c201a7fb6bb5beb1ad --- /dev/null +++ b/libdap-server-udp/dap_udp_client.h @@ -0,0 +1,66 @@ +/* + 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 + +#include <stdint.h> +#include <stddef.h> +#include <stdbool.h> + +#ifndef WIN32 +#include <sys/queue.h> +#endif + +#include "uthash.h" + +#include "dap_client_remote.h" + +typedef struct dap_udp_server dap_udp_server_t; +struct dap_udp_client; + +#define UDP_CLIENT_BUF 65535 + +typedef struct dap_udp_client { + + dap_client_remote_t *client; + uint64_t host_key; //key contains host address in first 4 bytes and port in last 4 bytes + + UT_hash_handle hh; + + struct dap_udp_client *next, *prev; //pointers for writing queue + pthread_mutex_t mutex_on_client; + + void *_inheritor; // Internal data to specific client type, usualy states for state machine + +} dap_udp_client_t; // Node of bidirectional list of clients + +#define DAP_UDP_CLIENT(a) ((dap_udp_client_t *) (a)->_inheritor) + +dap_client_remote_t *dap_udp_client_create( dap_server_t *sh, EPOLL_HANDLE efd, unsigned long host, unsigned short port ); // Create new client and add it to the list +dap_client_remote_t *dap_udp_client_find( dap_server_t *sh, unsigned long host, unsigned short port ); // Find client by host and port + +void dap_udp_client_ready_to_read( dap_client_remote_t *sc, bool is_ready ); +void dap_udp_client_ready_to_write( dap_client_remote_t *sc, bool is_ready ); + +size_t dap_udp_client_write( dap_client_remote_t *sc, const void * data, size_t data_size ); +size_t dap_udp_client_write_f( dap_client_remote_t *a_client, const char * a_format, ... ); + +void add_waiting_client( dap_client_remote_t *client ); // Add client to writing queue + +void dap_udp_client_get_address( dap_client_remote_t *client, unsigned int *host, unsigned short *port ); diff --git a/libdap-server-udp/dap_udp_server.c b/libdap-server-udp/dap_udp_server.c new file mode 100644 index 0000000000000000000000000000000000000000..9469474ec03d162f0db6cb04c6ae64d52682f0ad --- /dev/null +++ b/libdap-server-udp/dap_udp_server.c @@ -0,0 +1,401 @@ +/* + Copyright (c) 2017-2019 (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/>. +*/ + +#include <string.h> +#include <time.h> +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <signal.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/select.h> +#include <sys/queue.h> +#include <errno.h> +#include <netdb.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/epoll.h> +#else +#include <winsock2.h> +#include <windows.h> +#include <mswsock.h> +#include <ws2tcpip.h> +#include <io.h> +#include <pthread.h> +#endif + +#include "uthash.h" +#include "utlist.h" + +#include "dap_common.h" +#include "dap_udp_server.h" + +#define LOG_TAG "dap_udp_server" + +#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; + +//static void write_cb( EPOLL_HANDLE efd, int revents ); + +int check_close( dap_client_remote_t *client ); + +/** + */ +static void error( char *msg ) { + + perror( msg ); + exit( 1 ); +} + +/** + * @brief dap_udp_server_new Initialize server structure + * @return Server pointer + */ +dap_server_t *dap_udp_server_new( ) +{ + dap_udp_server_t *udp_server = (dap_udp_server_t *)calloc( 1, sizeof(dap_udp_server_t) ); + udp_server->waiting_clients = NULL; + + dap_server_t *sh = (dap_server_t *) calloc( 1, sizeof(dap_server_t) ); + sh->_inheritor = udp_server; + + udp_server->dap_server = sh; + + return sh; +} + +/** + * @brief dap_udp_server_delete Safe delete server structure + * @param sh Server instance + */ +void dap_udp_server_delete( dap_server_t *sh ) +{ + if ( !sh ) return; + +// dap_client_remote_t *client, *tmp; +// dap_udp_server_t *udps = (dap_udp_server_t *)sh->_inheritor; + +// if ( !udps ) return; + + if( sh->address ) + free( sh->address ); + +// HASH_ITER( hh, udps->hclients, client, tmp ) +// dap_client_remote_remove( client ); + + if ( sh->server_delete_callback ) + sh->server_delete_callback( sh, NULL ); + + if ( sh->_inheritor ) + free( sh->_inheritor ); + + free( sh ); +} + +/** + * @brief dap_udp_server_listen Create and bind server structure + * @param port Binding port + * @return Server instance + */ +dap_server_t *dap_udp_server_listen( uint16_t port ) { + + dap_server_t *sh = dap_udp_server_new( ); + + sh->socket_listener = socket( AF_INET, SOCK_DGRAM, 0 ); + + if ( sh->socket_listener < 0 ) { + log_it ( L_ERROR, "Socket error %s", strerror(errno) ); + dap_udp_server_delete( sh ); + return NULL; + } + + int optval = 1; + if ( setsockopt( sh->socket_listener, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval , sizeof(int)) < 0 ) + log_it( L_WARNING, "Can't set up REUSEADDR flag to the socket" ); + + memset( (char *)&(sh->listener_addr), 0, sizeof(sh->listener_addr) ); + + sh->listener_addr.sin_family = AF_INET; + sh->listener_addr.sin_addr.s_addr = htonl( INADDR_ANY ); + sh->listener_addr.sin_port = htons( port ); + + 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_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 ); + + return sh; +} + +/** + * @brief write_cb + */ +static void write_cb( EPOLL_HANDLE efd, int revents, dap_server_t *sh ) +{ + dap_udp_client_t *udp_client, *tmp; + +// dap_server_t *sh = watcher->data; + dap_udp_server_t *udp = DAP_UDP_SERVER( sh ); + + pthread_mutex_lock( &udp->mutex_on_list ); + + LL_FOREACH_SAFE( udp->waiting_clients, udp_client, tmp ) { + + //log_it(L_INFO,"write_cb"); + //pthread_mutex_lock(&udp_client->mutex_on_client); + + dap_client_remote_t *client = udp_client->client; + + if( client != NULL && !check_close(client) && (client->flags & DAP_SOCK_READY_TO_WRITE) ) { + + if ( sh->client_write_callback ) + sh->client_write_callback( client, NULL ); + + if ( client->buf_out_size > 0 ) { + + + + 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; ) { + + 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 ) { + log_it(L_ERROR,"Some error occured in send() function"); + break; + } + total_sent += bytes_sent; + } + client->buf_out_size = 0; + memset( client->buf_out, 0, sizeof(client->buf_out) ); + client->flags &= ~DAP_SOCK_READY_TO_WRITE; + sb_payload_ready = false; + } + LL_DELETE( udp->waiting_clients, udp_client ); + } + else if( client == NULL ) { + LL_DELETE( udp->waiting_clients, udp_client ); + } + //pthread_mutex_unlock(&udp_client->mutex_on_client); + + } // for client + pthread_mutex_unlock(&udp->mutex_on_list); +} + +/** + * @brief check_close Check if client need to close + * @param client Client structure + * @return 1 if client deleted, 0 if client is no need to delete + */ +int check_close( dap_client_remote_t *client ) +{ + dap_udp_client_t *client_check, *tmp; + + if( !(client->flags & DAP_SOCK_SIGNAL_CLOSE) ) return 0; + + dap_udp_client_t *udp_client = DAP_UDP_CLIENT( client ); + dap_server_t *sh = client->server; + dap_udp_server_t *udp_server = DAP_UDP_SERVER( sh ); + + LL_FOREACH_SAFE( udp_server->waiting_clients, client_check, tmp ) { + + if ( client_check->host_key == udp_client->host_key ) + LL_DELETE( udp_server->waiting_clients, client_check ); + } + + dap_client_remote_remove( client ); + + return 1; +} + +/** + * @brief read_cb + */ +static void read_cb( EPOLL_HANDLE efd, int revents, dap_server_t *sh ) +{ +// if ( !(revents & EV_READ) ) return; + + struct sockaddr_in clientaddr; + int clientlen = sizeof(clientaddr); +// dap_server_t *sh = watcher->data; + + memset( buf, 0, BUFSIZE ); + + int32_t bytes = (int32_t) recvfrom( sh->socket_listener, buf, BUFSIZE, 0,(struct sockaddr *) &clientaddr, &clientlen ); + + dap_client_remote_t *client = dap_udp_client_find( sh, clientaddr.sin_addr.s_addr, clientaddr.sin_port ); + + if( client != NULL && check_close(client) != 0 ) + return; + + if ( bytes > 0 ) { + + char *hostaddrp = inet_ntoa( clientaddr.sin_addr ); + + if ( hostaddrp == NULL ) { + dap_udp_server_delete( sh ); + error("ERROR on inet_ntoa\n"); + } + + if ( client == NULL ) { + client = dap_udp_client_create( sh, efd, clientaddr.sin_addr.s_addr, clientaddr.sin_port ); + if(client == NULL) { + dap_udp_server_delete( sh ); + error("ERROR create client structure\n"); + } + } + + dap_udp_client_t* udp_client = client->_inheritor; + + pthread_mutex_lock( &udp_client->mutex_on_client ); + + size_t bytes_processed = 0; + size_t bytes_recieved = bytes; + + while ( bytes_recieved > 0 ) { + + size_t bytes_to_transfer = 0; + + if ( bytes_recieved > UDP_CLIENT_BUF - client->buf_in_size ) + bytes_to_transfer = UDP_CLIENT_BUF - client->buf_in_size; + else + bytes_to_transfer = bytes_recieved; + + memcpy( client->buf_in + client->buf_in_size,buf + bytes_processed, bytes_to_transfer ); + client->buf_in_size += bytes_to_transfer; + + if ( sh->client_read_callback ) + sh->client_read_callback( client, NULL ); + + bytes_processed += bytes_to_transfer; + bytes_recieved -= bytes_to_transfer; + } + + client->buf_in_size = 0; + memset( client->buf_in, 0, sizeof(client->buf_out) ); + + pthread_mutex_unlock( &udp_client->mutex_on_client ); + + } + else if ( bytes < 0 ) { + + log_it( L_ERROR, "Bytes read Error %s", strerror(errno) ); + if( client != NULL ) + client->flags |= DAP_SOCK_SIGNAL_CLOSE; + } + else if (bytes == 0) { + if ( client != NULL ) + client->flags |= DAP_SOCK_SIGNAL_CLOSE; + } +} + +/** + * @brief dap_udp_server_loop Start server event loop + * @param sh Server instance + */ +void dap_udp_server_loop( dap_server_t *d_server ) +{ + efd_read = epoll_create1( 0 ); + + if ( (intptr_t)efd_read == -1 ) { + + log_it( L_ERROR, "epoll_create1 failed" ); + goto udp_error; + } + + sb_payload_ready = false; + + struct epoll_event pev; + struct epoll_event events[ 16 ]; + + pev.events = EPOLLIN | EPOLLERR; + pev.data.fd = d_server->socket_listener; + + if ( epoll_ctl( efd_read, EPOLL_CTL_ADD, d_server->socket_listener, &pev) != 0 ) { + log_it( L_ERROR, "epoll_ctl failed 000" ); + goto udp_error; + } + + while( 1 ) { + + int32_t n = epoll_wait( efd_read, &events[0], 16, -1 ); + + if ( !n ) continue; + + if ( n < 0 ) { + if ( errno == EINTR ) + continue; + log_it( L_ERROR, "Server epoll error" ); + break; + } + + for( int32_t i = 0; i < n; ++ i ) { + + if ( events[i].events & EPOLLIN ) { + read_cb( efd_read, events[i].events, d_server ); + } + 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 udp_error; + } + } + + } + +udp_error: + + #ifndef _WIN32 + if ( efd_read != -1 ) + close( efd_read ); + #else + if ( efd_read != INVALID_HANDLE_VALUE ) + epoll_close( efd_read ); + #endif + + return; +} + diff --git a/libdap-server-udp/dap_udp_server.h b/libdap-server-udp/dap_udp_server.h new file mode 100755 index 0000000000000000000000000000000000000000..2ed9465c012118bf5f4edd3761ae1b92f58fa39a --- /dev/null +++ b/libdap-server-udp/dap_udp_server.h @@ -0,0 +1,64 @@ +/* + Copyright (c) 2017-2019 (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 <stdint.h> +#include <sys/socket.h> +#include <netdb.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/select.h> +#include <sys/queue.h> +#define EPOLL_HANDLE int +#endif + +#include "dap_udp_client.h" +#include "dap_server.h" +#include "dap_client_remote.h" + +struct dap_udp_server; + +typedef struct dap_udp_thread { + pthread_t tid; +} dap_udp_thread_t; + +typedef void (*dap_udp_server_callback_t) (struct dap_udp_server *,void *arg); // Callback for specific server's operations + +typedef struct dap_udp_server { + + dap_udp_client_t *hclients; + dap_udp_client_t *waiting_clients; // List clients for writing data + pthread_mutex_t mutex_on_list; + pthread_mutex_t mutex_on_hash; + void *_inheritor; + dap_server_t *dap_server; + +} dap_udp_server_t; + +#define DAP_UDP_SERVER(a) ((dap_udp_server_t *) (a)->_inheritor) + +void dap_udp_server_delete( dap_server_t *sh ); +void dap_udp_server_loop( dap_server_t *udp_server ); // Start server event loop +dap_server_t *dap_udp_server_listen( uint16_t port ); // Create and bind serv diff --git a/libdap-server-udp/libdap b/libdap-server-udp/libdap new file mode 160000 index 0000000000000000000000000000000000000000..78cc4a3aca1775288662ef7a9f49f7b747479e15 --- /dev/null +++ b/libdap-server-udp/libdap @@ -0,0 +1 @@ +Subproject commit 78cc4a3aca1775288662ef7a9f49f7b747479e15 diff --git a/libdap-server-udp/libdap-server-core b/libdap-server-udp/libdap-server-core new file mode 160000 index 0000000000000000000000000000000000000000..bbe4d2b4e00012effac21cda4c2d3554dc6173e0 --- /dev/null +++ b/libdap-server-udp/libdap-server-core @@ -0,0 +1 @@ +Subproject commit bbe4d2b4e00012effac21cda4c2d3554dc6173e0 diff --git a/libdap-server-udp/test/CMakeLists.txt b/libdap-server-udp/test/CMakeLists.txt new file mode 100755 index 0000000000000000000000000000000000000000..998462efc70d1e565c198cca14e9d87496a3fc84 --- /dev/null +++ b/libdap-server-udp/test/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 3.0) +project(udp-server-test) + +set(CMAKE_C_STANDARD 11) + +if ( NOT ( TARGET dap_test ) ) + add_subdirectory(libdap-test) +endif() + +file(GLOB SRC *.h *.c) + +add_executable(${PROJECT_NAME} ${SRC}) + +target_link_libraries(${PROJECT_NAME} dap_test) + +add_test( + NAME udp-server-test + COMMAND udp-server-test +) + diff --git a/libdap-server-udp/test/libdap-test b/libdap-server-udp/test/libdap-test new file mode 160000 index 0000000000000000000000000000000000000000..b76175acc517f085c319c8e66c62bd143f96bf94 --- /dev/null +++ b/libdap-server-udp/test/libdap-test @@ -0,0 +1 @@ +Subproject commit b76175acc517f085c319c8e66c62bd143f96bf94 diff --git a/libdap-server-udp/test/main.c b/libdap-server-udp/test/main.c new file mode 100755 index 0000000000000000000000000000000000000000..e02c1ef950a56e4077faed96e1ee2f6c5cfe8a3f --- /dev/null +++ b/libdap-server-udp/test/main.c @@ -0,0 +1,5 @@ +#include <stdio.h> +int main() +{ + return 0; +}