diff --git a/CMakeLists.txt b/CMakeLists.txt index cdf2bbc19792f45fa893864836fb1bb350775a37..15c912ffaa67acdb5990f595456342a735574f82 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,4 +4,5 @@ cmake_minimum_required(VERSION 2.8) add_subdirectory(core_server) add_subdirectory(http_server) add_subdirectory(enc_server) +add_subdirectory(udp_server) diff --git a/udp_server/CMakeLists.txt b/udp_server/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..920e35e9d51af2929b8194cd7c4fa7bd2a0f2e7e --- /dev/null +++ b/udp_server/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 2.8) +project (dap_udp_server C) + +set(DAP_UDP_SERVER_SRCS dap_udp_server.c dap_udp_client.h dap_udp_client.c ) + + +include_directories("${INCLUDE_DIRECTORIES} ${dap_core_INCLUDE_DIRS}") +include_directories("${INCLUDE_DIRECTORIES} ${dap_crypto_INCLUDE_DIRS}") + +add_definitions ("${dap_core_DEFINITIONS}") +add_definitions ("${dap_crypto_DEFINITIONS}") + +add_library(${PROJECT_NAME} STATIC ${DAP_UDP_SERVER_SRCS}) +set(${PROJECT_NAME}_DEFINITIONS CACHE INTERNAL "${PROJECT_NAME}: Definitions" FORCE) + +set(${PROJECT_NAME}_INCLUDE_DIRS ${PROJECT_SOURCE_DIR} CACHE INTERNAL "${PROJECT_NAME}: Include Directories" FORCE) \ No newline at end of file diff --git a/udp_server/dap_udp_client.c b/udp_server/dap_udp_client.c new file mode 100644 index 0000000000000000000000000000000000000000..b8dd4d9fca5b9495f5a6baf6aa0daec981c41e41 --- /dev/null +++ b/udp_server/dap_udp_client.c @@ -0,0 +1,286 @@ +/* + 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/>. +*/ + +#include "dap_udp_client.h" +#include <sys/epoll.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <unistd.h> +#include <string.h> +#include <stdint.h> +#include <ev.h> +#include "utlist.h" +#include "dap_common.h" +#include "dap_loop.h" +#include "dap_udp_server.h" + +#define LOG_TAG "udp_client" + + +/** + * @brief udp_client_init Init clients module + * @return Zero if ok others if no + */ +int dap_udp_client_init() +{ + log_it(L_NOTICE,"Initialized socket client module"); + return 0; +} + +/** + * @brief udp_client_deinit Deinit clients module + */ +void dap_udp_client_deinit() +{ + +} + +/** + * @brief get_key Make key for hash table from host and port + * @return 64 bit Key + */ +uint64_t get_key(unsigned long host,unsigned short port){ + uint64_t key = host; + key = key << 32; + key += port; + return key; +} + +/** + * @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_udp_client_t * dap_udp_client_create(dap_udp_server_t * sh, ev_io* w_client, unsigned long host, unsigned short port) +{ + pthread_mutex_lock(&sh->mutex_on_hash); + log_it(L_DEBUG,"Client structure create"); + + dap_udp_client_t * ret=DAP_NEW_Z(dap_udp_client_t); + ret->server = sh; + ret->watcher_client = w_client; + ret->signal_close = false; + ret->host_key = get_key(host,port); + ret->_ready_to_read=true; + ret->_ready_to_write=false; + + HASH_ADD_INT( sh->clients, host_key, ret); + if(sh->client_new_callback) + sh->client_new_callback(ret,NULL); // Init internal structure + + pthread_mutex_unlock(&sh->mutex_on_hash); + 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_udp_client_t *client, unsigned long* host,unsigned short* port){ + *host = client->host_key >> 32; + *port = client->host_key - (*host<<32); +} + +/** + * @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_udp_client_t * dap_udp_client_find(dap_udp_server_t * sh, unsigned long host,unsigned short port) +{ + pthread_mutex_lock(&sh->mutex_on_hash); + + dap_udp_client_t * ret = NULL; + uint64_t token = get_key(host,port); + HASH_FIND_INT(sh->clients,&token,ret); + + pthread_mutex_unlock(&sh->mutex_on_hash); + return ret; +} + +/** + * @brief udp_client_read Read data from input buffer + * @param sc Client instance + * @param data Pointer to memory where to store the data + * @param data_size Size of data to read + * @return Actual bytes number that were read + */ +size_t dap_udp_client_read(dap_udp_client_t *sc, void * data, size_t data_size) +{ + if (data_size < sc->buf_in_size) { + memcpy(data, sc->buf_in, data_size); + memmove(data, sc->buf_in + data_size, sc->buf_in_size - data_size); + } else { + if (data_size > sc->buf_in_size) { + data_size = sc->buf_in_size; + } + memcpy(data, sc->buf_in, data_size); + } + sc->buf_in_size -= data_size; + return data_size; +} + +/** + * @brief udp_client_ready_to_read Set ready_to_read flag + * @param sc Client structure + * @param is_ready Flag value + */ +void dap_udp_client_ready_to_read(dap_udp_client_t * sc,bool is_ready) +{ + if(is_ready != sc->_ready_to_read) { + + uint32_t events = 0; + sc->_ready_to_read=is_ready; + + if(sc->_ready_to_read) + { + events |= EV_READ; + } + + if(sc->_ready_to_write) + events |= EV_WRITE; + + ev_io_set(sc->watcher_client, sc->server->socket_listener, events ); + } +} + +/** + * @brief udp_client_ready_to_write Set ready_to_write flag + * @param sc Client structure + * @param is_ready Flag value + */ +void dap_udp_client_ready_to_write(dap_udp_client_t * sc,bool is_ready) +{ + if(is_ready) + add_waiting_client(sc); // Add client to writing queue + if(is_ready != sc->_ready_to_write) { + uint32_t events = 0; + sc->_ready_to_write=is_ready; + + if(sc->_ready_to_read) + events |= EV_READ; + + if(sc->_ready_to_write) + { + events |= EV_WRITE; + } + int descriptor = sc->watcher_client->fd; + ev_io_set(sc->watcher_client, descriptor, events ); + } +} + +/** + * @brief udp_client_remove Removes the client from the hashmap + * @param sc Client instance + * @param sh Server instance + */ +void dap_udp_client_remove(dap_udp_client_t *sc, dap_udp_server_t * sh) +{ + pthread_mutex_lock(&sh->mutex_on_hash); + + log_it(L_DEBUG, "Client structure remove"); + HASH_DEL(sc->server->clients,sc); + + if(sc->server->client_delete_callback) + sc->server->client_delete_callback(sc,NULL); // Init internal structure + if(sc->_inheritor) + free(sc->_inheritor); + free(sc); + pthread_mutex_unlock(&sh->mutex_on_hash); +} + +/** + * @brief udp_client_write Write data to the client + * @param sc Client instance + * @param data Pointer to data + * @param data_size Size of data to write + * @return Number of bytes that were placed into the buffer + */ +size_t dap_udp_client_write(dap_udp_client_t *sc, const void * data, size_t data_size) +{ + data_size = ((sc->buf_out_size+data_size)<(sizeof(sc->buf_out)))?data_size:(sizeof(sc->buf_out)-sc->buf_out_size ); + memcpy(sc->buf_out+sc->buf_out_size,data,data_size); + sc->buf_out_size+=data_size; + return data_size; +} + +/** + * @brief udp_client_write_f Write formatted text to the client + * @param a_client Client instance + * @param a_format Format + * @return Number of bytes that were placed into the buffer + */ +size_t dap_udp_client_write_f(dap_udp_client_t *a_client, const char * a_format,...) +{ + size_t max_data_size = sizeof(a_client->buf_out)-a_client->buf_out_size; + va_list ap; + va_start(ap,a_format); + int ret=vsnprintf(a_client->buf_out+a_client->buf_out_size,max_data_size,a_format,ap); + va_end(ap); + if(ret>0){ + a_client->buf_out_size+=ret; + return ret; + }else{ + log_it(L_ERROR,"Can't write out formatted data '%s'",a_format); + return 0; + } +} + +/** + * @brief add_waiting_client Add Client to write queue + * @param client Client instance + */ +void add_waiting_client(dap_udp_client_t* client){ + dap_udp_server_t* serv = client->server; + LL_APPEND(serv->waiting_clients, client); +} + + +/** + * @brief shrink_client_buf_in Shrink input buffer (shift it left) + * @param cl Client instance + * @param shrink_size Size on wich we shrink the buffer with shifting it left + */ +void dap_udp_client_shrink_buf_in(dap_udp_client_t * cl, size_t shrink_size) +{ + if((shrink_size==0)||(cl->buf_in_size==0) ){ + return; + }else if(cl->buf_in_size>shrink_size){ + size_t buf_size=cl->buf_in_size-shrink_size; + void * buf = malloc(buf_size); + memcpy(buf,cl->buf_in+ shrink_size,buf_size ); + memcpy(cl->buf_in,buf,buf_size); + cl->buf_in_size=buf_size; + free(buf); + }else { + cl->buf_in_size=0; + } + +} + diff --git a/udp_server/dap_udp_client.h b/udp_server/dap_udp_client.h new file mode 100644 index 0000000000000000000000000000000000000000..584dacfe96d8d6af59f32b25ce26e5c92ea98fdb --- /dev/null +++ b/udp_server/dap_udp_client.h @@ -0,0 +1,86 @@ +/* + Copyright (c) 2017-2018 (c) Project "DeM Labs Inc" https://github.com/demlabsinc + All rights reserved. + + This file is part of DAP (Deus Applications Prototypes) the open source project + + DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + DAP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with any DAP based project. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once +#ifndef _UDP_CLIENT_H +#define _UDP_CLIENT_H + +#include <sys/queue.h> +#include <stdint.h> +#include <stddef.h> +#include <stdbool.h> +#include <sys/queue.h> +#include "uthash.h" +#include <ev.h> + + +typedef struct dap_udp_server dap_udp_server_t; +struct dap_udp_client; + +typedef void (*dap_udp_client_callback_t) (struct udp_client *,void * arg); // Callback for specific client operations + +#define UDP_CLIENT_BUF 100000 + +typedef struct dap_udp_client{ + bool signal_close; + + bool _ready_to_write; + bool _ready_to_read; + + uint32_t buf_out_zero_count; + char buf_in[UDP_CLIENT_BUF+1]; // Internal buffer for input data + size_t buf_in_size; // size of data that is in the input buffer + + char buf_out[UDP_CLIENT_BUF+1]; // Internal buffer for output data + size_t buf_out_size; // size of data that is in the output buffer + + uint64_t host_key; //key contains host address in first 4 bytes and port in last 4 bytes + + ev_io* watcher_client; + + struct dap_udp_server * server; + + UT_hash_handle hh; + struct dap_udp_client *next, *prev; //pointers for writing queue + + void * _inheritor; // Internal data to specific client type, usualy states for state machine +} dap_udp_client_t; // Node of bidirectional list of clients + + + +int dap_udp_client_init(); // Init clients module +void dap_udp_client_deinit(); // Deinit clients module + +dap_udp_client_t * dap_udp_client_create(dap_udp_server_t * sh, ev_io* w_client, unsigned long host, unsigned short port); // Create new client and add it to the list +dap_udp_client_t * dap_udp_client_find(dap_udp_server_t * sh, unsigned long host, unsigned short port); // Find client by host and port + +void dap_udp_client_ready_to_read(dap_udp_client_t * sc,bool is_ready); +void dap_udp_client_ready_to_write(dap_udp_client_t * sc,bool is_ready); + +size_t dap_udp_client_write(dap_udp_client_t *sc, const void * data, size_t data_size); +size_t dap_udp_client_write_f(dap_udp_client_t *a_client, const char * a_format,...); +size_t dap_udp_client_read(dap_udp_client_t *sc, void * data, size_t data_size); + +void add_waiting_client(dap_udp_client_t* client); // Add client to writing queue + +void dap_udp_client_remove(dap_udp_client_t *sc, dap_udp_server_t * sh); // Removes the client from the hash-table + +void dap_udp_client_shrink_buf_in(dap_udp_client_t * cl, size_t shrink_size); + +#endif \ No newline at end of file diff --git a/udp_server/dap_udp_server.c b/udp_server/dap_udp_server.c new file mode 100644 index 0000000000000000000000000000000000000000..15c72ef0e53afa16d0ea695354b9f02406ea8b2c --- /dev/null +++ b/udp_server/dap_udp_server.c @@ -0,0 +1,278 @@ +/* + 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/>. +*/ + +#include "dap_udp_server.h" +#include <stdio.h> +#include "dap_common.h" +#include <errno.h> +#include <netdb.h> +#include <unistd.h> +#include <fcntl.h> +#include <ev.h> +#include "utlist.h" + +#define LOG_TAG "dap_udp_server" + +#define BUFSIZE 1024 + +char buf[BUFSIZE]; /* message buf */ +struct ev_io w_read; +struct ev_io w_write; + +static void write_cb(struct ev_loop* loop, struct ev_io* watcher, int revents); + +/** + * @brief dap_udp_server_init Init server module + * @return Zero if ok others if no + */ +int dap_udp_server_init() +{ + signal(SIGPIPE, SIG_IGN); + log_it(L_NOTICE,"Initialized socket server module"); + return 0; +} + +/** + * @brief dap_udp_server_deinit Deinit server module + */ +void dap_udp_server_deinit() +{ +} + +/** + */ +void error(char *msg) { + perror(msg); + exit(1); +} + +/** + * @brief dap_udp_server_new Initialize server structure + * @return Server pointer + */ +dap_udp_server_t * dap_udp_server_new() +{ + dap_udp_server_t* server = (dap_udp_server_t*)calloc(1,sizeof(dap_udp_server_t)); + server->waiting_clients = NULL; + return server; +} + +/** + * @brief dap_udp_client_loop Create client listening event loop + */ +void* dap_udp_client_loop(void * arg) +{ + dap_udp_server_t* sh = (dap_udp_server_t*)arg; + log_it(L_NOTICE, "Start client listener thread"); + struct ev_loop * ev_client_loop = ev_loop_new(0); + w_write.data = sh; + ev_io_init(&w_write, write_cb, sh->socket_listener, EV_WRITE); + ev_io_start(ev_client_loop, &w_write); + ev_loop(ev_client_loop, 0); + return NULL; +} + +/** + * @brief dap_udp_server_delete Safe delete server structure + * @param sh Server instance + */ +void dap_udp_server_delete(dap_udp_server_t * sh) +{ + if(sh->address) + free(sh->address); + + dap_udp_client_t * client, * tmp; + HASH_ITER(hh,sh->clients,client,tmp) + dap_udp_client_remove(client, sh); + + 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_udp_server_t * dap_udp_server_listen(uint16_t port){ + dap_udp_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"); + + bzero((char *) &(sh->listener_addr), 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; + } + return sh; +} + +/** + * @brief write_cb + */ +static void write_cb(struct ev_loop* loop, struct ev_io* watcher, int revents) +{ + if( ( revents & EV_WRITE ) ) { + dap_udp_server_t* sh = watcher->data; + dap_udp_client_t * client, * tmp; + LL_FOREACH_SAFE(sh->waiting_clients,client,tmp) + { + if(client != NULL && check_close(client) == 0 && client->_ready_to_write) + { + if(sh->client_write_callback) + sh->client_write_callback(client, NULL); + if(client->buf_out_size > 0) + { + 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,&addr.sin_addr.s_addr,&addr.sin_port); + 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; + } + LL_DELETE(sh->waiting_clients,client); + } + else if(client == NULL) + LL_DELETE(sh->waiting_clients,client); + } + } +} + +/** + * @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_udp_client_t* client){ + if(client->signal_close) + { + dap_udp_server_t* sh = client->server; + dap_udp_client_t * client_check, * tmp; + LL_FOREACH_SAFE(sh->waiting_clients,client_check,tmp) + if(client_check->host_key == client->host_key) + LL_DELETE(sh->waiting_clients,client_check); + dap_udp_client_remove(client, sh); + return 1; + } + return 0; +} + +/** + * @brief read_cb + */ +static void read_cb(struct ev_loop* loop, struct ev_io* watcher, int revents) +{ + if ( revents & EV_READ ) + { + struct sockaddr_in clientaddr; + int clientlen = sizeof(clientaddr); + dap_udp_server_t* sh = watcher->data; + bzero(buf, BUFSIZE); + socklen_t bytes = recvfrom(sh->socket_listener, buf, BUFSIZE, 0,(struct sockaddr *) &clientaddr, &clientlen); + dap_udp_client_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,&w_write,clientaddr.sin_addr.s_addr,clientaddr.sin_port); + if(client == NULL) + { + dap_udp_server_delete(sh); + error("ERROR create client structure\n"); + } + } + size_t bytes_processed = 0; + size_t bytes_recieved = strlen(buf); + 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; + } + } + else if(bytes < 0) + { + log_it(L_ERROR,"Bytes read Error %s",strerror(errno)); + if(client != NULL) + client->signal_close = true; + + } + else if (bytes == 0) + { + if(client != NULL) + client->signal_close = true; + } + } +} + +/** + * @brief dap_udp_server_loop Start server event loop + * @param sh Server instance + */ +void dap_udp_server_loop(dap_udp_server_t * sh){ + sh->proc_thread.tid = pthread_self(); + + pthread_t thread; + pthread_create(&thread, NULL, dap_udp_client_loop, sh); + struct ev_loop * ev_main_loop = ev_default_loop(0); + w_read.data = sh; + ev_io_init(&w_read, read_cb, sh->socket_listener, EV_READ); + ev_io_start(ev_main_loop, &w_read); + ev_run(ev_main_loop, 0); +} + diff --git a/udp_server/dap_udp_server.h b/udp_server/dap_udp_server.h new file mode 100644 index 0000000000000000000000000000000000000000..e4aa672f61c13b9c4d0eed9ed0f5d6a0e3c04c36 --- /dev/null +++ b/udp_server/dap_udp_server.h @@ -0,0 +1,82 @@ +/* + Copyright (c) 2017-2018 (c) Project "DeM Labs Inc" https://github.com/demlabsinc + All rights reserved. + + This file is part of DAP (Deus Applications Prototypes) the open source project + + DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + DAP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with any DAP based project. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once +#ifndef _UDP_SERVER_H_ +#define _UDP_SERVER_H_ + +#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> +#include "dap_udp_client.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{ + uint16_t port; // Listen port + char * address; // Listen address + + dap_udp_client_t * clients; // Hashmap of clients + dap_udp_client_t * waiting_clients; // List clients for writing data + + int socket_listener; // Socket for listener + int epoll_fd; // Epoll fd + + struct sockaddr_in listener_addr; // Kernel structure for listener's binded address + + void * _inheritor; // Pointer to the internal data, HTTP for example + + dap_udp_thread_t proc_thread; + pthread_mutex_t mutex_on_hash; + + dap_udp_server_callback_t server_delete_callback; + + dap_udp_client_callback_t client_new_callback; // Create new client callback + dap_udp_client_callback_t client_delete_callback; // Delete client callback + dap_udp_client_callback_t client_read_callback; // Read function + dap_udp_client_callback_t client_write_callback; // Write function + dap_udp_client_callback_t client_error_callback; // Error processing function + +} dap_udp_server_t; + +extern int dap_udp_server_init(); // Init server module + +extern void dap_udp_server_deinit(); // Deinit server module + +extern void dap_udp_server_delete(dap_udp_server_t * sh); + +extern void dap_udp_server_loop(dap_udp_server_t* udp_server); // Start server event loop + +extern dap_udp_server_t* dap_udp_server_listen(uint16_t port); // Create and bind server + +#endif + +