summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrederic Berat <fberat@de.adit-jv.com>2015-07-14 16:36:14 +0200
committerLutz Helwing <lutz_helwing@mentor.com>2015-11-11 15:24:22 +0100
commitd29b6be9496db80e37a452bd42dc7813f369c33e (patch)
tree163ae1bf2e9488e2cff585cfa8cbb953630bfaf0
parent9e101ff434230a95fb8f4fd33dc48f4970496d1c (diff)
downloadDLT-daemon-d29b6be9496db80e37a452bd42dc7813f369c33e.tar.gz
dlt-daemon: Implement epoll based event handling
The event handling has been reworked in order to use epoll and restructure the code. There are 2 new structures. The DltConnection which contains all basic connection information, like the type, the file descriptor, and the receiver structure corresponding. The DltEventHandler that manages the DltConnections and the associated events. The concept is basically the following. The daemon will create different connections, serial connections, socket connections, fifos etc ... Each of them will then register itself to the event handler, and give it the ownership of this connection. From this point in time, the daemon can act on the connections. Once an event is triggered, the event handler will call the connection specific callback, creates new connections when clients arrives, and potentially destroy the connection in case of hangup. On exit, the daemon cleanup the event handler, which leads to the destruction of the connections. The work there is a first step for a global restructuring. Several modification will follow, in order to rationalize the different daemon structures, and avoid variable and code duplication. Signed-off-by: Frederic Berat <fberat@de.adit-jv.com>
-rw-r--r--src/daemon/CMakeLists.txt2
-rw-r--r--src/daemon/dlt-daemon.c509
-rw-r--r--src/daemon/dlt-daemon.h23
-rw-r--r--src/daemon/dlt_daemon_client.c374
-rw-r--r--src/daemon/dlt_daemon_client.h9
-rw-r--r--src/daemon/dlt_daemon_connection.c374
-rw-r--r--src/daemon/dlt_daemon_connection.h51
-rw-r--r--src/daemon/dlt_daemon_connection_types.h64
-rw-r--r--src/daemon/dlt_daemon_event_handler.c373
-rw-r--r--src/daemon/dlt_daemon_event_handler.h57
-rw-r--r--src/daemon/dlt_daemon_event_handler_types.h59
11 files changed, 1550 insertions, 345 deletions
diff --git a/src/daemon/CMakeLists.txt b/src/daemon/CMakeLists.txt
index a3c7439..d7d0d3a 100644
--- a/src/daemon/CMakeLists.txt
+++ b/src/daemon/CMakeLists.txt
@@ -20,7 +20,7 @@ if(WITH_SYSTEMD_WATCHDOG OR WITH_SYSTEMD)
message( STATUS "Added ${systemd_SRCS} to dlt-daemon")
endif(WITH_SYSTEMD_WATCHDOG OR WITH_SYSTEMD)
-set(dlt_daemon_SRCS dlt-daemon.c dlt_daemon_common.c dlt_daemon_socket.c dlt_daemon_serial.c dlt_daemon_client.c dlt_daemon_offline_logstorage.c ${CMAKE_SOURCE_DIR}/src/shared/dlt_user_shared.c ${CMAKE_SOURCE_DIR}/src/shared/dlt_common.c ${CMAKE_SOURCE_DIR}/src/shared/dlt_shm.c ${CMAKE_SOURCE_DIR}/src/shared/dlt_offline_trace.c ${CMAKE_SOURCE_DIR}/src/offlinelogstorage/dlt_offline_logstorage.c)
+set(dlt_daemon_SRCS dlt-daemon.c dlt_daemon_common.c dlt_daemon_connection.c dlt_daemon_event_handler.c dlt_daemon_socket.c dlt_daemon_serial.c dlt_daemon_client.c dlt_daemon_offline_logstorage.c ${CMAKE_SOURCE_DIR}/src/shared/dlt_user_shared.c ${CMAKE_SOURCE_DIR}/src/shared/dlt_common.c ${CMAKE_SOURCE_DIR}/src/shared/dlt_shm.c ${CMAKE_SOURCE_DIR}/src/shared/dlt_offline_trace.c ${CMAKE_SOURCE_DIR}/src/offlinelogstorage/dlt_offline_logstorage.c)
add_executable(dlt-daemon ${dlt_daemon_SRCS} ${systemd_SRCS})
target_link_libraries(dlt-daemon rt ${CMAKE_THREAD_LIBS_INIT})
diff --git a/src/daemon/dlt-daemon.c b/src/daemon/dlt-daemon.c
index c733e91..fb9fe22 100644
--- a/src/daemon/dlt-daemon.c
+++ b/src/daemon/dlt-daemon.c
@@ -59,6 +59,8 @@
#include "dlt_daemon_serial.h"
#include "dlt_daemon_client.h"
+#include "dlt_daemon_connection.h"
+#include "dlt_daemon_event_handler.h"
#if defined(DLT_SYSTEMD_WATCHDOG_ENABLE) || defined(DLT_SYSTEMD_ENABLE)
#include "sd-daemon.h"
@@ -441,7 +443,7 @@ int main(int argc, char* argv[])
char version[DLT_DAEMON_TEXTBUFSIZE];
DltDaemonLocal daemon_local;
DltDaemon daemon;
- int i,back;
+ int back;
/* Command line option handling */
if ((back = option_handling(&daemon_local,argc,argv))<0)
@@ -490,6 +492,13 @@ int main(int argc, char* argv[])
}
/* --- Daemon init phase 1 end --- */
+ if (dlt_daemon_prepare_event_handling(&daemon_local.pEvent))
+ {
+ /* TODO: Perform clean-up */
+ dlt_log(LOG_CRIT,"Initialization of event handling failed!\n");
+ return -1;
+ }
+
/* --- Daemon connection init begin */
if (dlt_daemon_local_connection_init(&daemon, &daemon_local, daemon_local.flags.vflag)==-1)
{
@@ -518,18 +527,37 @@ int main(int argc, char* argv[])
watchdogTimeoutSeconds = atoi(watchdogUSec)/2000000;
}
watchdog_trigger_interval = watchdogTimeoutSeconds;
- create_timer_fd(&daemon_local, watchdogTimeoutSeconds, watchdogTimeoutSeconds, &daemon_local.timer_wd, "Systemd watchdog");
+ create_timer_fd(&daemon_local,
+ watchdogTimeoutSeconds,
+ watchdogTimeoutSeconds,
+ &daemon_local.timer_wd.fd,
+ DLT_TIMER_SYSTEMD);
}
#endif
// create fd for timer timing packets
- create_timer_fd(&daemon_local, 1, 1, &daemon_local.timer_one_s, "Timing packet");
+ create_timer_fd(&daemon_local,
+ 1,
+ 1,
+ &daemon_local.timer_one_s.fd,
+ DLT_TIMER_PACKET);
// create fd for timer ecu version
- if(daemon_local.flags.sendECUSoftwareVersion > 0 || daemon_local.flags.sendTimezone > 0)
+ if((daemon_local.flags.sendECUSoftwareVersion > 0) ||
+ (daemon_local.flags.sendTimezone > 0))
+ {
+ create_timer_fd(&daemon_local,
+ 60,
+ 60,
+ &daemon_local.timer_sixty_s.fd,
+ DLT_TIMER_ECU);
+ }
+
+ if (dlt_connection_create_remaining(&daemon_local) == -1)
{
- //dlt_daemon_init_ecuversion(&daemon_local);
- create_timer_fd(&daemon_local, 60, 60, &daemon_local.timer_sixty_s, "ECU version");
+ /* TODO: Perform clean-up */
+ dlt_log(LOG_CRIT,"Fail to create remaining connection handler!\n");
+ return -1;
}
// For offline tracing we still can use the same states
@@ -542,132 +570,14 @@ int main(int argc, char* argv[])
dlt_daemon_log_internal(&daemon, &daemon_local, "Daemon launched. Starting to output traces...", daemon_local.flags.vflag);
- while (1)
+ /* Even handling loop. */
+ while (back >= 0)
{
+ back = dlt_daemon_handle_event(&daemon_local.pEvent,
+ &daemon,
+ &daemon_local);
+ }
- /* wait for events from all FIFO and sockets */
- daemon_local.read_fds = daemon_local.master;
- if (select(daemon_local.fdmax+1, &(daemon_local.read_fds), NULL, NULL, NULL) == -1)
- {
- int error = errno;
- /* retry if SIGINT was received, else error out */
- if ( error != EINTR ) {
- snprintf(str,DLT_DAEMON_TEXTBUFSIZE,"select() failed: %s\n", strerror(error) );
- dlt_log(LOG_ERR, str);
- return -1;
- }
- } /* if */
-
- /* run through the existing FIFO and sockets to check for events */
- for (i = 0; i <= daemon_local.fdmax; i++)
- {
- if (FD_ISSET(i, &(daemon_local.read_fds)))
- {
- if (i == daemon_local.sock)
- {
- /* event from TCP server socket, new connection */
- if (dlt_daemon_process_client_connect(&daemon, &daemon_local, daemon_local.flags.vflag)==-1)
- {
- dlt_log(LOG_ERR,"Connect to dlt client failed!\n");
- return -1;
- }
- }
- else if (i == daemon_local.fp)
- {
- /* event from the FIFO happened */
- if (dlt_daemon_process_user_messages(&daemon, &daemon_local, daemon_local.flags.vflag)==-1)
- {
- dlt_log(LOG_WARNING,"Processing of messages from user connection failed!\n");
- return -1;
- }
- }
- else if ((i == daemon_local.fdserial) && (daemon_local.flags.yvalue[0]))
- {
- /* event from serial connection to client received */
- if (dlt_daemon_process_client_messages_serial(&daemon, &daemon_local, daemon_local.flags.vflag)==-1)
- {
- dlt_log(LOG_WARNING,"Processing of messages from serial connection failed!\n");
- return -1;
- }
- }
-#ifdef DLT_SYSTEMD_WATCHDOG_ENABLE
- else if (i == daemon_local.timer_wd)
- {
- uint64_t expir=0;
- ssize_t res = read(daemon_local.timer_wd, &expir, sizeof(expir));
- if(res < 0) {
- snprintf(str,DLT_DAEMON_TEXTBUFSIZE,"Failed to read timer_wd; %s\n", strerror(errno) );
- dlt_log(LOG_WARNING, str);
- // Activity received on timer_wd, but unable to read the fd:
- // let's go on sending notification
- }
-
- dlt_log(LOG_DEBUG, "Timer watchdog\n");
-
- if(sd_notify(0, "WATCHDOG=1") < 0)
- {
- dlt_log(LOG_WARNING, "Could not reset systemd watchdog\n");
- }
- }
-#endif
- else if (i == daemon_local.timer_one_s)
- {
- uint64_t expir=0;
- ssize_t res = read(daemon_local.timer_one_s, &expir, sizeof(expir));
- if(res < 0) {
- snprintf(str,DLT_DAEMON_TEXTBUFSIZE,"Failed to read timer_timingpacket; %s\n", strerror(errno) );
- dlt_log(LOG_WARNING, str);
- // Activity received on timer_wd, but unable to read the fd:
- // let's go on sending notification
- }
- if(daemon.state == DLT_DAEMON_STATE_SEND_BUFFER || daemon.state == DLT_DAEMON_STATE_BUFFER_FULL)
- {
- if (dlt_daemon_send_ringbuffer_to_client(&daemon, &daemon_local, daemon_local.flags.vflag))
- {
- dlt_log(LOG_DEBUG,"Can't send contents of ringbuffer to clients\n");
- }
- }
- if (daemon.timingpackets && daemon.state == DLT_DAEMON_STATE_SEND_DIRECT)
- {
- dlt_daemon_control_message_time(DLT_DAEMON_SEND_TO_ALL, &daemon, &daemon_local, daemon_local.flags.vflag);
- }
- dlt_log(LOG_DEBUG, "Timer timingpacket\n");
-
- }
-
- else if (i == daemon_local.timer_sixty_s)
- {
- uint64_t expir=0;
- ssize_t res = read(daemon_local.timer_sixty_s, &expir, sizeof(expir));
- if(res < 0) {
- snprintf(str,DLT_DAEMON_TEXTBUFSIZE,"Failed to read timer_ecuversion; %s\n", strerror(errno) );
- dlt_log(LOG_WARNING, str);
- // Activity received on timer_wd, but unable to read the fd:
- // let's go on sending notification
- }
- if(daemon_local.flags.sendECUSoftwareVersion > 0)
- dlt_daemon_control_get_software_version(DLT_DAEMON_SEND_TO_ALL, &daemon,&daemon_local, daemon_local.flags.vflag);
-
- if(daemon_local.flags.sendTimezone > 0)
- {
- dlt_daemon_control_message_timezone(DLT_DAEMON_SEND_TO_ALL,&daemon,&daemon_local,daemon_local.flags.vflag);
- }
- dlt_log(LOG_DEBUG, "Timer ecuversion\n");
-
- }
- else
- {
- /* event from tcp connection to client received */
- daemon_local.receiverSock.fd = i;
- if (dlt_daemon_process_client_messages(&daemon, &daemon_local, daemon_local.flags.vflag)==-1)
- {
- dlt_log(LOG_WARNING,"Processing of messages from client connection failed!\n");
- return -1;
- }
- } /* else */
- } /* if */
- } /* for */
- } /* while */
dlt_daemon_log_internal(&daemon, &daemon_local, "Exiting Daemon...", daemon_local.flags.vflag);
@@ -870,18 +780,81 @@ int dlt_daemon_local_init_p2(DltDaemon *daemon, DltDaemonLocal *daemon_local, in
return 0;
}
-int dlt_daemon_local_connection_init(DltDaemon *daemon, DltDaemonLocal *daemon_local, int verbose)
+static int dlt_daemon_init_serial(DltDaemonLocal *daemon_local)
{
- int ret;
+ if (!daemon_local->flags.yvalue[0])
+ {
+ /* Nothing to do here. */
+ daemon_local->fdserial = -1;
+ return 0;
+ }
- PRINT_FUNCTION_VERBOSE(verbose);
+ /* create and open serial connection from/to client */
+ /* open serial connection */
+ daemon_local->fdserial = open(daemon_local->flags.yvalue, O_RDWR);
+ if (daemon_local->fdserial < 0)
+ {
+ snprintf(str,
+ DLT_DAEMON_TEXTBUFSIZE,
+ "Failed to open serial device %s\n",
+ daemon_local->flags.yvalue);
+ dlt_log(LOG_ERR, str);
- if ((daemon==0) || (daemon_local==0))
+ daemon_local->flags.yvalue[0] = 0;
+ return -1;
+ }
+
+ if (isatty(daemon_local->fdserial))
{
- dlt_log(LOG_ERR, "Invalid function parameters used for function dlt_daemon_local_connection_init()\n");
+ int speed = DLT_DAEMON_SERIAL_DEFAULT_BAUDRATE;
+
+ if (daemon_local->flags.bvalue[0])
+ {
+ speed = atoi(daemon_local->flags.bvalue);
+ }
+
+ daemon_local->baudrate = dlt_convert_serial_speed(speed);
+
+ if (dlt_setup_serial(daemon_local->fdserial,
+ daemon_local->baudrate) < 0)
+ {
+ close(daemon_local->fdserial);
+ daemon_local->flags.yvalue[0] = 0;
+
+ snprintf(str,
+ DLT_DAEMON_TEXTBUFSIZE,
+ "Failed to configure serial device %s (%s) \n",
+ daemon_local->flags.yvalue,
+ strerror(errno));
+ dlt_log(LOG_ERR, str);
+
+ return -1;
+ }
+
+ if (daemon_local->flags.vflag)
+ {
+ dlt_log(LOG_DEBUG, "Serial init done\n");
+ }
+ }
+ else
+ {
+ close(daemon_local->fdserial);
+ fprintf(stderr,
+ "Device is not a serial device, device = %s (%s) \n",
+ daemon_local->flags.yvalue,
+ strerror(errno));
+ daemon_local->flags.yvalue[0] = 0;
return -1;
}
+ return 0;
+}
+
+static int dlt_daemon_init_fifo(DltDaemonLocal *daemon_local)
+{
+ int ret;
+ char local_str[DLT_DAEMON_TEXTBUFSIZE];
+
/* open named pipe(FIFO) to receive DLT messages from users */
umask(0);
@@ -890,93 +863,77 @@ int dlt_daemon_local_connection_init(DltDaemon *daemon, DltDaemonLocal *daemon_l
unlink(tmpFifo);
ret=mkfifo(tmpFifo, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP );
- if (ret==-1)
+ if (ret == -1)
{
- snprintf(str,DLT_DAEMON_TEXTBUFSIZE,"FIFO user %s cannot be created (%s)!\n",tmpFifo, strerror(errno));
- dlt_log(LOG_WARNING, str);
+ snprintf(local_str,
+ DLT_DAEMON_TEXTBUFSIZE,
+ "FIFO user %s cannot be created (%s)!\n",
+ tmpFifo,
+ strerror(errno));
+ dlt_log(LOG_WARNING, local_str);
return -1;
} /* if */
daemon_local->fp = open(tmpFifo, O_RDWR);
- if (daemon_local->fp==-1)
+ if (daemon_local->fp == -1)
{
- snprintf(str,DLT_DAEMON_TEXTBUFSIZE,"FIFO user %s cannot be opened (%s)!\n",tmpFifo, strerror(errno));
- dlt_log(LOG_WARNING, str);
+ snprintf(local_str,
+ DLT_DAEMON_TEXTBUFSIZE,
+ "FIFO user %s cannot be opened (%s)!\n",
+ tmpFifo,
+ strerror(errno));
+ dlt_log(LOG_WARNING, local_str);
return -1;
} /* if */
- /* create and open socket to receive incoming connections from client */
- if(dlt_daemon_socket_open(&(daemon_local->sock), daemon_local->flags.port))
- {
- return -1;
- }
+ /* Early init, to be able to catch client (app) connections
+ * as soon as possible. This registration is automatically ignored
+ * during next execution.
+ */
+ return dlt_connection_create(daemon_local,
+ &daemon_local->pEvent,
+ daemon_local->fp,
+ EPOLLIN,
+ DLT_CONNECTION_APP_MSG);
+}
- /* prepare usage of select(), add FIFO and receiving socket */
- FD_ZERO(&(daemon_local->master));
- FD_ZERO(&(daemon_local->read_fds));
- FD_SET(daemon_local->sock, &(daemon_local->master));
+int dlt_daemon_local_connection_init(DltDaemon *daemon,
+ DltDaemonLocal *daemon_local,
+ int verbose)
+{
+ char local_str[DLT_DAEMON_TEXTBUFSIZE];
+ PRINT_FUNCTION_VERBOSE(verbose);
- daemon_local->fdmax = daemon_local->sock;
+ if ((daemon == NULL) || (daemon_local == NULL))
+ {
+ snprintf(local_str,
+ DLT_DAEMON_TEXTBUFSIZE,
+ "%s: Invalid function parameters\n",
+ __func__);
- FD_SET(daemon_local->fp, &(daemon_local->master));
+ dlt_log(LOG_ERR, local_str);
+ return -1;
+ }
- if (daemon_local->fp > daemon_local->fdmax)
+ if (dlt_daemon_init_fifo(daemon_local))
{
- daemon_local->fdmax = daemon_local->fp;
+ dlt_log(LOG_ERR, "Unable to initialize fifo.\n");
+ return -1;
}
- if (daemon_local->flags.yvalue[0])
+ /* create and open socket to receive incoming connections from client */
+ daemon_local->client_connections = 0;
+ if(dlt_daemon_socket_open(&(daemon_local->sock),daemon_local->flags.port))
{
- /* create and open serial connection from/to client */
- /* open serial connection */
- daemon_local->fdserial=open(daemon_local->flags.yvalue,O_RDWR);
- if (daemon_local->fdserial<0)
- {
- snprintf(str,DLT_DAEMON_TEXTBUFSIZE,"Failed to open serial device %s\n", daemon_local->flags.yvalue);
- daemon_local->flags.yvalue[0] = 0;
- dlt_log(LOG_ERR, str);
- return -1;
- }
-
- if (isatty(daemon_local->fdserial))
- {
- if (daemon_local->flags.bvalue[0])
- {
- daemon_local->baudrate = dlt_convert_serial_speed(atoi(daemon_local->flags.bvalue));
- }
- else
- {
- daemon_local->baudrate = dlt_convert_serial_speed(DLT_DAEMON_SERIAL_DEFAULT_BAUDRATE);
- }
-
- if (dlt_setup_serial(daemon_local->fdserial,daemon_local->baudrate) < DLT_RETURN_OK)
- {
- close(daemon_local->fdserial);
- snprintf(str,DLT_DAEMON_TEXTBUFSIZE,"Failed to configure serial device %s (%s) \n", daemon_local->flags.yvalue, strerror(errno));
- daemon_local->flags.yvalue[0] = 0;
- dlt_log(LOG_ERR, str);
- return -1;
- }
-
- FD_SET(daemon_local->fdserial, &(daemon_local->master));
-
- if (daemon_local->fdserial > daemon_local->fdmax)
- {
- daemon_local->fdmax = daemon_local->fdserial;
- }
+ dlt_log(LOG_ERR,"Could not initialize main socket.\n");
+ return -1;
+ }
- if (daemon_local->flags.vflag)
- {
- dlt_log(LOG_DEBUG, "Serial init done\n");
- }
- }
- else
- {
- close(daemon_local->fdserial);
- fprintf(stderr,"Device is not a serial device, device = %s (%s) \n", daemon_local->flags.yvalue, strerror(errno));
- daemon_local->flags.yvalue[0] = 0;
- return -1;
- }
+ /* Init serial */
+ if (dlt_daemon_init_serial(daemon_local) < 0)
+ {
+ dlt_log(LOG_ERR,"Could not initialize daemon data\n");
+ return -1;
}
return 0;
@@ -1096,6 +1053,8 @@ void dlt_daemon_local_cleanup(DltDaemon *daemon, DltDaemonLocal *daemon_local, i
/* Try to delete lock file, ignore result of unlink() */
unlink(DLT_DAEMON_LOCK_FILE);
+
+ dlt_event_handler_cleanup_connections(&daemon_local->pEvent);
}
void dlt_daemon_signal_handler(int sig)
@@ -1359,20 +1318,17 @@ int dlt_daemon_process_client_connect(DltDaemon *daemon, DltDaemonLocal *daemon_
if (setsockopt (in_sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout_send, sizeof(timeout_send)) < 0)
dlt_log(LOG_WARNING, "setsockopt failed\n");
- /* Set to non blocking mode */
- //flags = fcntl(in_sock, F_GETFL, 0);
- //fcntl(in_sock, F_SETFL, flags | O_NONBLOCK);
-
- //snprintf(str,DLT_DAEMON_TEXTBUFSIZE,"Client Connection from %s\n", inet_ntoa(cli.sin_addr));
- //dlt_log(str);
- FD_SET(in_sock, &(daemon_local->master)); /* add to master set */
- if (in_sock > daemon_local->fdmax)
+ if (dlt_connection_create(daemon_local,
+ &daemon_local->pEvent,
+ in_sock,
+ EPOLLIN,
+ DLT_CONNECTION_CLIENT_MSG_TCP))
{
- /* keep track of the maximum */
- daemon_local->fdmax = in_sock;
- } /* if */
+ dlt_log(LOG_ERR, "Failed to register new client. \n");
+ /* TODO: Perform clean-up */
+ return -1;
+ }
- daemon_local->client_connections++;
if (daemon_local->flags.vflag)
{
snprintf(str,DLT_DAEMON_TEXTBUFSIZE, "New connection to client established, #connections: %d\n",daemon_local->client_connections);
@@ -1429,9 +1385,15 @@ int dlt_daemon_process_client_messages(DltDaemon *daemon, DltDaemonLocal *daemon
if (dlt_receiver_receive_socket(&(daemon_local->receiverSock))<=0)
{
- dlt_daemon_close_socket(daemon_local->receiverSock.fd, daemon, daemon_local, verbose);
+ dlt_daemon_close_socket(daemon_local->receiverSock.fd,
+ daemon,
+ daemon_local,
+ verbose);
daemon_local->receiverSock.fd = -1;
- /* check: return 0; */
+ /* FIXME: Why the hell do we need to close the socket
+ * on control message reception ??
+ */
+ //return 0;
}
/* Process all received messages */
@@ -2407,55 +2369,11 @@ int dlt_daemon_process_user_message_log_shm(DltDaemon *daemon, DltDaemonLocal *d
}
/* look if TCP connection to client is available */
- for (j = 0;((daemon->mode == DLT_USER_MODE_EXTERNAL) || (daemon->mode == DLT_USER_MODE_BOTH)) && (j <= daemon_local->fdmax); j++)
+ if((daemon->mode == DLT_USER_MODE_EXTERNAL) ||
+ (daemon->mode == DLT_USER_MODE_BOTH))
{
- /* send to everyone! */
- if (FD_ISSET(j, &(daemon_local->master)))
- {
- /* except the listener and ourselves */
- if (daemon_local->flags.yvalue[0])
- {
- third_value = daemon_local->fdserial;
- }
- else
- {
- third_value = daemon_local->sock;
- }
-
- if ((j != daemon_local->fp) && (j != daemon_local->sock) && (j != third_value))
- {
- DLT_DAEMON_SEM_LOCK();
-
- if (daemon_local->flags.lflag)
- {
- send(j,dltSerialHeader,sizeof(dltSerialHeader),0);
- }
-
- send(j,daemon_local->msg.headerbuffer+sizeof(DltStorageHeader),daemon_local->msg.headersize-sizeof(DltStorageHeader),0);
- send(j,daemon_local->msg.databuffer,daemon_local->msg.datasize,0);
-
- DLT_DAEMON_SEM_FREE();
-
- sent=1;
- } /* if */
- else if ((j == daemon_local->fdserial) && (daemon_local->flags.yvalue[0]))
- {
- DLT_DAEMON_SEM_LOCK();
-
- if (daemon_local->flags.lflag)
- {
- ret=write(j,dltSerialHeader,sizeof(dltSerialHeader));
- }
-
- ret=write(j,daemon_local->msg.headerbuffer+sizeof(DltStorageHeader),daemon_local->msg.headersize-sizeof(DltStorageHeader));
- ret=write(j,daemon_local->msg.databuffer,daemon_local->msg.datasize);
-
- DLT_DAEMON_SEM_FREE();
-
- sent=1;
- }
- } /* if */
- } /* for */
+ sent = dlt_daemon_client_send_all(daemon, daemon_local, verbose);
+ }
/* Message was not sent to client, so store it in client ringbuffer */
if (sent==1 || (daemon->mode == DLT_USER_MODE_OFF))
@@ -2679,16 +2597,36 @@ int dlt_daemon_send_ringbuffer_to_client(DltDaemon *daemon, DltDaemonLocal *daem
return DLT_DAEMON_ERROR_OK;
}
-int create_timer_fd(DltDaemonLocal *daemon_local, int period_sec, int starts_in, int* fd, const char* timer_name)
+static char dlt_timer_names[DLT_TIMER_UNKNOWN + 1][32] = {
+ [DLT_TIMER_PACKET] = "Timing packet",
+ [DLT_TIMER_ECU] = "ECU version",
+#ifdef DLT_SYSTEMD_WATCHDOG_ENABLE
+ [DLT_TIMER_SYSTEMD] = "Systemd watchdog",
+#endif
+ [DLT_TIMER_UNKNOWN] = "Unknown timer"
+};
+
+int create_timer_fd(DltDaemonLocal *daemon_local,
+ int period_sec,
+ int starts_in,
+ int* fd,
+ DltTimers timer_id)
{
int local_fd = -1;
struct itimerspec l_timer_spec;
+ char *timer_name = dlt_timer_names[timer_id];
if(timer_name == NULL)
{
timer_name = "timer_not_named";
}
+ if(daemon_local == NULL)
+ {
+ dlt_log(DLT_LOG_ERROR, "Daemaon local structure is NULL");
+ return -1;
+ }
+
if( fd == NULL )
{
snprintf(str, sizeof(str), "<%s> fd is NULL pointer\n", timer_name );
@@ -2725,18 +2663,17 @@ int create_timer_fd(DltDaemonLocal *daemon_local, int period_sec, int starts_in,
local_fd = -1;
}
- // If fd is fully initialized, let's add it to the fd sets
- if(local_fd>0)
+ /* If fully initialized we are done.
+ * Event handling registration is done later on with other connections.
+ */
+ if(local_fd > 0)
{
- snprintf(str, sizeof(str), "<%s> initialized with %ds timer\n", timer_name, period_sec);
+ snprintf(str,
+ sizeof(str),
+ "<%s> initialized with %d timer\n",
+ timer_name,
+ period_sec);
dlt_log(LOG_INFO, str);
-
- FD_SET(local_fd, &(daemon_local->master));
- //FD_SET(local_fd, &(daemon_local->timer_fds));
- if (local_fd > daemon_local->fdmax)
- {
- daemon_local->fdmax = local_fd;
- }
}
*fd = local_fd;
@@ -2747,16 +2684,22 @@ int create_timer_fd(DltDaemonLocal *daemon_local, int period_sec, int starts_in,
/* Close connection function */
int dlt_daemon_close_socket(int sock, DltDaemon *daemon, DltDaemonLocal *daemon_local, int verbose)
{
- dlt_daemon_socket_close(sock);
-
- FD_CLR(sock, &(daemon_local->master));
+ PRINT_FUNCTION_VERBOSE(verbose);
- if (daemon_local->client_connections)
+ if((daemon_local == NULL)|| (daemon == NULL))
{
- daemon_local->client_connections--;
+ dlt_log(LOG_ERR, "dlt_daemon_close_socket: Invalid input parmeters\n");
+ return -1;
}
- if(daemon_local->client_connections==0)
+ /* Closure is done while unregistering has for any connection */
+ dlt_event_handler_unregister_connection(&daemon_local->pEvent,
+ daemon_local,
+ sock,
+ DLT_CONNECTION_CLIENT_MSG_TCP);
+
+
+ if(daemon_local->client_connections==0)
{
/* send new log state to all applications */
daemon->connectionState = 0;
diff --git a/src/daemon/dlt-daemon.h b/src/daemon/dlt-daemon.h
index 25431d8..0096ba6 100644
--- a/src/daemon/dlt-daemon.h
+++ b/src/daemon/dlt-daemon.h
@@ -74,7 +74,7 @@
#include "dlt_daemon_common.h"
#include "dlt_user_shared.h"
#include "dlt_user_shared_cfg.h"
-
+#include "dlt_daemon_event_handler_types.h"
#include <dlt_offline_trace.h>
#include <sys/time.h>
@@ -126,11 +126,8 @@ typedef struct
int fp; /**< handle for own fifo */
int sock; /**< handle for tcp connection to client */
int fdserial; /**< handle for serial connection */
- int fdmax; /**< highest number of used handles */
- fd_set master; /**< master set of handles */
- fd_set read_fds; /**< read set of handles */
DltFile file; /**< struct for file access */
- //int ohandle; /**< handle to output file */
+ DltEventHandler pEvent; /**< struct for message producer event handling */
DltMessage msg; /**< one dlt message */
DltReceiver receiver; /**< receiver for fifo connection */
DltReceiver receiverSock; /**< receiver for socket connection */
@@ -141,15 +138,15 @@ typedef struct
DltShm dlt_shm; /**< Shared memory handling */
#endif
DltOfflineTrace offlineTrace; /**< Offline trace handling */
-#if defined(DLT_SYSTEMD_WATCHDOG_ENABLE)
- int timer_wd; /** file descriptor for watchdog timer */
-#endif
int timeoutOnSend;
unsigned long RingbufferMinSize;
unsigned long RingbufferMaxSize;
unsigned long RingbufferStepSize;
- int timer_one_s;
- int timer_sixty_s;
+ DltReceiver timer_one_s;
+ DltReceiver timer_sixty_s;
+#if defined(DLT_SYSTEMD_WATCHDOG_ENABLE)
+ DltReceiver timer_wd; /**< file descriptor for watchdog timer */
+#endif
} DltDaemonLocal;
typedef struct
@@ -181,11 +178,13 @@ int dlt_daemon_local_ecu_version_init(DltDaemon *daemon, DltDaemonLocal *daemon_
void dlt_daemon_daemonize(int verbose);
void dlt_daemon_signal_handler(int sig);
-
int dlt_daemon_process_client_connect(DltDaemon *daemon, DltDaemonLocal *daemon_local, int verbose);
int dlt_daemon_process_client_messages(DltDaemon *daemon, DltDaemonLocal *daemon_local, int verbose);
int dlt_daemon_process_client_messages_serial(DltDaemon *daemon, DltDaemonLocal *daemon_local, int verbose);
int dlt_daemon_process_user_messages(DltDaemon *daemon, DltDaemonLocal *daemon_local, int verbose);
+int dlt_daemon_process_one_s_timer(DltDaemon *daemon, DltDaemonLocal *daemon_local, int verbose);
+int dlt_daemon_process_sixty_s_timer(DltDaemon *daemon, DltDaemonLocal *daemon_local, int verbose);
+int dlt_daemon_process_systemd_timer(DltDaemon *daemon, DltDaemonLocal *daemon_local, int verbose);
int dlt_daemon_process_user_message_overflow(DltDaemon *daemon, DltDaemonLocal *daemon_local, int verbose);
int dlt_daemon_send_message_overflow(DltDaemon *daemon, DltDaemonLocal *daemon_local, int verbose);
@@ -208,7 +207,7 @@ void dlt_daemon_ecu_version_thread(void *ptr);
void dlt_daemon_systemd_watchdog_thread(void *ptr);
#endif
-int create_timer_fd(DltDaemonLocal *daemon_local, int period_sec, int starts_in, int* fd, const char* timer_name);
+int create_timer_fd(DltDaemonLocal *daemon_local, int period_sec, int starts_in, int* fd, DltTimers timer);
int dlt_daemon_close_socket(int sock, DltDaemon *daemon, DltDaemonLocal *daemon_local, int verbose);
diff --git a/src/daemon/dlt_daemon_client.c b/src/daemon/dlt_daemon_client.c
index e1cf841..89b5489 100644
--- a/src/daemon/dlt_daemon_client.c
+++ b/src/daemon/dlt_daemon_client.c
@@ -59,15 +59,153 @@
#include "dlt_daemon_serial.h"
#include "dlt_daemon_client.h"
+#include "dlt_daemon_connection.h"
#include "dlt_daemon_offline_logstorage.h"
/** Global text output buffer, mainly used for creation of error/warning strings */
static char str[DLT_DAEMON_TEXTBUFSIZE];
+/** @brief Sends up to 2 messages to all the clients.
+ *
+ * Runs through the client list and sends the messages to them. If the message
+ * transfer fails and the connection is a socket connection, the socket is closed.
+ * Takes and release dlt_daemon_mutex.
+ *
+ * @param daemon Daemon structure needed for socket closure.
+ * @param daemon_local Daemon local structure
+ * @param data1 The first message to be sent.
+ * @param size1 The size of the first message.
+ * @param data2 The second message to be send.
+ * @param size2 The second message size.
+ * @param verbose Needed for socket closure.
+ *
+ * @return The amount of data transfered.
+ */
+static int dlt_daemon_client_send_all_multiple(DltDaemon *daemon,
+ DltDaemonLocal *daemon_local,
+ void* data1,
+ int size1,
+ void* data2,
+ int size2,
+ int verbose)
+{
+ int j, sent = 0;
+ DltConnection* temp = NULL;
+ int type_mask =
+ (DLT_CON_MASK_CLIENT_MSG_TCP | DLT_CON_MASK_CLIENT_MSG_SERIAL);
+ char local_str[DLT_DAEMON_TEXTBUFSIZE];
+
+ if ((daemon == NULL) || (daemon_local == NULL))
+ {
+ snprintf(local_str,
+ DLT_DAEMON_TEXTBUFSIZE,
+ "%s: Invalid parameters\n",
+ __func__);
+ dlt_log(LOG_ERR, local_str);
+ return 0;
+ }
+
+ temp = daemon_local->pEvent.connections;
+ temp = dlt_connection_get_next(temp, type_mask);
+
+ /* FIXME: the lock shall include the for loop as data
+ * can be affect between each iteration, but
+ * dlt_daemon_close_socket may call us too ...
+ */
+ for (j = 0; ((j < daemon_local->client_connections) && (temp != NULL)); j++)
+ {
+ int ret = 0;
+ DLT_DAEMON_SEM_LOCK();
+ ret = dlt_connection_send_multiple(temp,
+ data1,
+ size1,
+ data2,
+ size2,
+ daemon->sendserialheader);
+ DLT_DAEMON_SEM_FREE();
+
+ if((ret != DLT_DAEMON_ERROR_OK) &&
+ DLT_CONNECTION_CLIENT_MSG_TCP == temp->type)
+ {
+ dlt_daemon_close_socket(temp->fd,
+ daemon,
+ daemon_local,
+ verbose);
+ }
+
+ if (ret != DLT_DAEMON_ERROR_OK)
+ {
+ snprintf(local_str,
+ DLT_DAEMON_TEXTBUFSIZE,
+ "%s: send dlt message failed\n",
+ __func__);
+ dlt_log(LOG_WARNING, local_str);
+ }
+ else
+ {
+ /* If sent to at least one client,
+ * then do not store in ring buffer
+ */
+ sent = 1;
+ }
+
+ temp = dlt_connection_get_next(temp->next, type_mask);
+ } /* for */
+
+ return sent;
+}
+
+/** @brief Send out message to all the clients.
+ *
+ * @param daemon pointer to dlt daemon structure
+ * @param daemon_local pointer to dlt daemon local structure
+ * @param verbose if set to true verbose information is printed out.
+ *
+ * @return 1 if transfer succeed, 0 otherwise.
+ */
+int dlt_daemon_client_send_all(DltDaemon *daemon,
+ DltDaemonLocal *daemon_local,
+ int verbose)
+{
+ void *msg1, *msg2;
+ int msg1_sz, msg2_sz;
+ int ret = 0;
+ char local_str[DLT_DAEMON_TEXTBUFSIZE];
+
+ if ((daemon == NULL) || (daemon_local == NULL))
+ {
+ snprintf(local_str,
+ DLT_DAEMON_TEXTBUFSIZE,
+ "%s: Invalid parameters\n",
+ __func__);
+ dlt_log(LOG_ERR, local_str);
+ return 0;
+ }
+
+ /* FIXME: the lock shall include the for loop but
+ * dlt_daemon_close_socket may call us too ...
+ */
+ DLT_DAEMON_SEM_LOCK();
+ msg1 = daemon_local->msg.headerbuffer + sizeof(DltStorageHeader);
+ msg1_sz = daemon_local->msg.headersize - sizeof(DltStorageHeader);
+ msg2 = daemon_local->msg.databuffer;
+ msg2_sz = daemon_local->msg.datasize;
+ DLT_DAEMON_SEM_FREE();
+
+ ret = dlt_daemon_client_send_all_multiple(daemon,
+ daemon_local,
+ msg1,
+ msg1_sz,
+ msg2,
+ msg2_sz,
+ verbose);
+
+ return ret;
+}
+
int dlt_daemon_client_send(int sock,DltDaemon *daemon,DltDaemonLocal *daemon_local,void* storage_header,int storage_header_size,void* data1,int size1,void* data2,int size2,int verbose)
{
- int ret;
- int j;
+ int sent,ret;
if (sock!=DLT_DAEMON_SEND_TO_ALL && sock!=DLT_DAEMON_SEND_FORCE)
{
@@ -135,58 +273,20 @@ int dlt_daemon_client_send(int sock,DltDaemon *daemon,DltDaemonLocal *daemon_loc
{
if ((sock==DLT_DAEMON_SEND_FORCE) || (daemon->state == DLT_DAEMON_STATE_SEND_DIRECT))
{
- int sent = 0;
- /* look if TCP connection to client is available */
- for (j = 0; j <= daemon_local->fdmax; j++)
- {
- /* send to everyone! */
- if (FD_ISSET(j, &(daemon_local->master)))
- {
- if ((j != daemon_local->fp) && (j != daemon_local->sock) && (j != daemon_local->sock)
- #ifdef DLT_SYSTEMD_WATCHDOG_ENABLE
- && (j!=daemon_local->timer_wd)
- #endif
- && (j!=daemon_local->timer_one_s) && (j!=daemon_local->timer_sixty_s))
- {
- /* Send message */
- if (isatty(j))
- {
- DLT_DAEMON_SEM_LOCK();
-
- if((ret=dlt_daemon_serial_send(j,data1,size1,data2,size2,daemon->sendserialheader)))
- {
- DLT_DAEMON_SEM_FREE();
- dlt_log(LOG_WARNING,"dlt_daemon_client_send: serial send dlt message failed\n");
- return ret;
- }
-
- DLT_DAEMON_SEM_FREE();
- }
- else
- {
- DLT_DAEMON_SEM_LOCK();
-
- if((ret=dlt_daemon_socket_send(j,data1,size1,data2,size2,daemon->sendserialheader)))
- {
- DLT_DAEMON_SEM_FREE();
- dlt_log(LOG_WARNING,"dlt_daemon_client_send: socket send dlt message failed\n");
- dlt_daemon_close_socket(j, daemon, daemon_local, verbose);
- return ret;
- }
-
- DLT_DAEMON_SEM_FREE();
- }
- sent=1;
-
- }
- }
- }
+ sent = dlt_daemon_client_send_all_multiple(daemon,
+ daemon_local,
+ data1,
+ size1,
+ data2,
+ size2,
+ verbose);
+
if((sock==DLT_DAEMON_SEND_FORCE) && !sent)
{
return DLT_DAEMON_ERROR_SEND_FAILED;
}
}
- }
+ }
/* Message was not sent to client, so store it in client ringbuffer */
if ((sock!=DLT_DAEMON_SEND_FORCE) && (daemon->state == DLT_DAEMON_STATE_BUFFER || daemon->state == DLT_DAEMON_STATE_SEND_BUFFER || daemon->state == DLT_DAEMON_STATE_BUFFER_FULL))
@@ -1639,6 +1739,182 @@ void dlt_daemon_control_message_time(int sock, DltDaemon *daemon, DltDaemonLocal
dlt_message_free(&msg,0);
}
+int dlt_daemon_process_one_s_timer(DltDaemon *daemon,
+ DltDaemonLocal *daemon_local,
+ int verbose)
+{
+ uint64_t expir = 0;
+ ssize_t res = 0;
+ char local_str[DLT_DAEMON_TEXTBUFSIZE];
+
+ PRINT_FUNCTION_VERBOSE(verbose);
+
+ if((daemon_local == NULL) || (daemon == NULL))
+ {
+ snprintf(local_str,
+ DLT_DAEMON_TEXTBUFSIZE,
+ "%s: invalid parameters",
+ __func__);
+ dlt_log(LOG_ERR, local_str);
+ return -1;
+ }
+
+ res = read(daemon_local->timer_one_s.fd, &expir, sizeof(expir));
+
+ if(res < 0)
+ {
+ snprintf(local_str,
+ DLT_DAEMON_TEXTBUFSIZE,
+ "%s: Fail to read timer (%s)\n", __func__, strerror(errno));
+ dlt_log(LOG_WARNING, str);
+ /* Activity received on timer_wd, but unable to read the fd:
+ let's go on sending notification */
+ }
+
+ if((daemon->state == DLT_DAEMON_STATE_SEND_BUFFER) ||
+ (daemon->state == DLT_DAEMON_STATE_BUFFER_FULL))
+ {
+ if (dlt_daemon_send_ringbuffer_to_client(daemon,
+ daemon_local,
+ daemon_local->flags.vflag))
+ {
+ dlt_log(LOG_DEBUG,
+ "Can't send contents of ring buffer to clients\n");
+ }
+ }
+
+ if((daemon->timingpackets) &&
+ (daemon->state == DLT_DAEMON_STATE_SEND_DIRECT))
+ {
+ dlt_daemon_control_message_time(DLT_DAEMON_SEND_TO_ALL,
+ daemon,
+ daemon_local,
+ daemon_local->flags.vflag);
+ }
+
+ dlt_log(LOG_DEBUG, "Timer timingpacket\n");
+
+ return 0;
+}
+
+int dlt_daemon_process_sixty_s_timer(DltDaemon *daemon,
+ DltDaemonLocal *daemon_local,
+ int verbose)
+{
+ uint64_t expir = 0;
+ ssize_t res = 0;
+ char local_str[DLT_DAEMON_TEXTBUFSIZE];
+
+ PRINT_FUNCTION_VERBOSE(verbose);
+
+ if((daemon_local == NULL) || (daemon == NULL))
+ {
+ snprintf(str,
+ DLT_DAEMON_TEXTBUFSIZE,
+ "%s: invalid parameters",
+ __func__);
+ dlt_log(LOG_ERR, str);
+ return -1;
+ }
+
+ res = read(daemon_local->timer_sixty_s.fd, &expir, sizeof(expir));
+
+ if(res < 0)
+ {
+ snprintf(local_str,
+ DLT_DAEMON_TEXTBUFSIZE,
+ "%s: Fail to read timer (%s)\n", __func__, strerror(errno));
+ dlt_log(LOG_WARNING, str);
+ /* Activity received on timer_wd, but unable to read the fd:
+ let's go on sending notification */
+ }
+
+ if(daemon_local->flags.sendECUSoftwareVersion > 0)
+ {
+ dlt_daemon_control_get_software_version(DLT_DAEMON_SEND_TO_ALL,
+ daemon,
+ daemon_local,
+ daemon_local->flags.vflag);
+ }
+
+ if(daemon_local->flags.sendTimezone > 0)
+ {
+ // send timezone information
+ time_t t = time(NULL);
+ struct tm lt;
+
+ /*Added memset to avoid compiler warning for near initialization */
+ memset((void*)&lt, 0, sizeof(lt));
+ localtime_r(&t, &lt);
+
+ dlt_daemon_control_message_timezone(DLT_DAEMON_SEND_TO_ALL,
+ daemon,
+ daemon_local,
+ daemon_local->flags.vflag);
+ }
+
+ dlt_log(LOG_DEBUG, "Timer ecuversion\n");
+
+ return 0;
+}
+
+#ifdef DLT_SYSTEMD_WATCHDOG_ENABLE
+int dlt_daemon_process_systemd_timer(DltDaemon *daemon,
+ DltDaemonLocal *daemon_local,
+ int verbose)
+{
+ uint64_t expir = 0;
+ ssize_t res = -1;
+ char local_str[DLT_DAEMON_TEXTBUFSIZE];
+
+ PRINT_FUNCTION_VERBOSE(verbose);
+
+ if((daemon_local == NULL) || (daemon == NULL))
+ {
+ snprintf(local_str,
+ DLT_DAEMON_TEXTBUFSIZE,
+ "%s: invalid parameters",
+ __func__);
+ dlt_log(LOG_ERR, local_str);
+ return res;
+ }
+
+ res = read(daemon_local->timer_wd.fd, &expir, sizeof(expir));
+
+ if(res < 0)
+ {
+ snprintf(local_str,
+ DLT_DAEMON_TEXTBUFSIZE,
+ "Failed to read timer_wd; %s\n",
+ strerror(errno));
+ dlt_log(LOG_WARNING, local_str);
+ /* Activity received on timer_wd, but unable to read the fd:
+ let's go on sending notification */
+ }
+
+ if(sd_notify(0, "WATCHDOG=1") < 0)
+ {
+ dlt_log(LOG_CRIT, "Could not reset systemd watchdog\n");
+ }
+
+ dlt_log(LOG_DEBUG, "Timer watchdog\n");
+
+ return 0;
+}
+#else
+int dlt_daemon_process_systemd_timer(DltDaemon *daemon,
+ DltDaemonLocal *daemon_local,
+ int verbose)
+{
+ (void)daemon;
+ (void)daemon_local;
+ (void)verbose;
+
+ dlt_log(LOG_DEBUG, "Timer watchdog not enabled\n");
+
+ return -1;
+}
+#endif
void dlt_daemon_control_service_logstorage(int sock, DltDaemon *daemon, DltDaemonLocal *daemon_local, DltMessage *msg, int verbose)
{
diff --git a/src/daemon/dlt_daemon_client.h b/src/daemon/dlt_daemon_client.h
index c7ec9e9..4b5ebcb 100644
--- a/src/daemon/dlt_daemon_client.h
+++ b/src/daemon/dlt_daemon_client.h
@@ -67,6 +67,15 @@
#include <sys/time.h>
/**
+ * Send out message to all the clients.
+ * @param daemon pointer to dlt daemon structure
+ * @param daemon_local pointer to dlt daemon local structure
+ * @param verbose if set to true verbose information is printed out.
+ * @return 1 if transfer succeed, 0 otherwise.
+ */
+int dlt_daemon_client_send_all(DltDaemon *daemon, DltDaemonLocal *daemon_local, int verbose);
+
+/**
* Send out message to client or store message in offline trace.
* @param sock connection handle used for sending response
* @param daemon pointer to dlt daemon structure
diff --git a/src/daemon/dlt_daemon_connection.c b/src/daemon/dlt_daemon_connection.c
new file mode 100644
index 0000000..0eee668
--- /dev/null
+++ b/src/daemon/dlt_daemon_connection.c
@@ -0,0 +1,374 @@
+/*
+ * @licence app begin@
+ * SPDX license identifier: MPL-2.0
+ *
+ * Copyright (C) 2015 Advanced Driver Information Technology.
+ * This code is developed by Advanced Driver Information Technology.
+ * Copyright of Advanced Driver Information Technology, Bosch and DENSO.
+ *
+ * This file is part of GENIVI Project DLT - Diagnostic Log and Trace.
+ *
+ * This Source Code Form is subject to the terms of the
+ * Mozilla Public License (MPL), v. 2.0.
+ * If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * For further information see http://www.genivi.org/.
+ * @licence end@
+ */
+
+/*!
+ * \author
+ * Frederic Berat <fberat@de.adit-jv.com>
+ *
+ * \copyright Copyright © 2015 Advanced Driver Information Technology. \n
+ * License MPL-2.0: Mozilla Public License version 2.0 http://mozilla.org/MPL/2.0/.
+ *
+ * \file dlt_daemon_connection.c
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/socket.h>
+#include <sys/syslog.h>
+#include <sys/types.h>
+
+#include "dlt_daemon_connection_types.h"
+#include "dlt_daemon_connection.h"
+#include "dlt_daemon_event_handler_types.h"
+#include "dlt_daemon_event_handler.h"
+#include "dlt-daemon.h"
+#include "dlt-daemon_cfg.h"
+#include "dlt_daemon_common.h"
+#include "dlt_common.h"
+
+/** @brief Generic sending function.
+ *
+ * We manage different type of connection which have similar send/write
+ * functions. We can then abstract the data transfer using this function,
+ * moreover as we often transfer data to different kind of connection
+ * within the same loop.
+ *
+ * @param conn The connection structure.
+ * @param msg The message buffer to be sent
+ * @param msg_size The length of the message to be sent
+ *
+ * @return The amount of bytes send on success, -1 otherwise.
+ * errno is appropriately set.
+ */
+static int dlt_connection_send(DltConnection *conn,
+ void *msg,
+ size_t msg_size)
+{
+ DltConnectionType type = DLT_CONNECTION_TYPE_MAX;
+
+ if (conn != NULL)
+ {
+ type = conn->type;
+ }
+
+ switch (type)
+ {
+ case DLT_CONNECTION_CLIENT_MSG_SERIAL:
+ return write(conn->fd, msg, msg_size);
+ case DLT_CONNECTION_CLIENT_MSG_TCP:
+ return send(conn->fd, msg, msg_size, 0);
+ default:
+ return -1;
+ }
+}
+
+/** @brief Send up to two messages through a connection.
+ *
+ * We often need to send 2 messages through a specific connection, plus
+ * the serial header. This function groups these different calls.
+ *
+ * @param con The connection to send the messages through.
+ * @param data1 The first message to be sent.
+ * @param size1 The size of the first message.
+ * @param data2 The second message to be send.
+ * @param size2 The second message size.
+ * @param sendserialheader Whether we need or not to send the serial header.
+ *
+ * @return DLT_DAEMON_ERROR_OK on success, -1 otherwise. errno is properly set.
+ */
+int dlt_connection_send_multiple(DltConnection *con,
+ void *data1,
+ int size1,
+ void *data2,
+ int size2,
+ int sendserialheader)
+{
+ int ret = 0;
+
+ if (con == NULL)
+ {
+ return -1;
+ }
+
+ if (sendserialheader)
+ {
+ ret = dlt_connection_send(con,
+ (void *)dltSerialHeader,
+ sizeof(dltSerialHeader));
+ }
+
+ if ((data1 != NULL) && (ret >= 0))
+ {
+ ret = dlt_connection_send(con, data1, size1);
+ }
+
+ if ((data2 != NULL) && (ret >= 0))
+ {
+ ret = dlt_connection_send(con, data2, size2);
+ }
+
+ if (ret >=0)
+ {
+ ret = DLT_DAEMON_ERROR_OK;
+ }
+
+ return ret;
+}
+
+/** @brief Get the next connection filtered with a type mask.
+ *
+ * In some cases we need the next connection available of a specific type or
+ * specific different types. This function returns the next available connection
+ * that is of one of the types included in the mask. The current connection can
+ * be returned.
+ *
+ * @param current The current connection pointer.
+ * @param type_mask A bit mask representing the connection types to be filtered.
+ *
+ * @return The next available connection of the considered types or NULL.
+ */
+DltConnection *dlt_connection_get_next(DltConnection *current, int type_mask)
+{
+ while (current && !((1 << current->type) & type_mask))
+ {
+ current = current->next;
+ }
+
+ return current;
+}
+
+/** @brief Get the receiver structure associated to a connection.
+ *
+ * The receiver structure is sometimes needed while handling the event.
+ * This behavior is mainly due to the fact that it's not intended to modify
+ * the whole design of the daemon while implementing the new event handling.
+ * Based on the connection type provided, this function returns the pointer
+ * to the DltReceiver structure corresponding.
+ *
+ * @param dameon_local Structure where to take the DltReceiver pointer from.
+ * @param type Type of the connection.
+ *
+ * @return DltReceiver structure or NULL if none corresponds to the type.
+ */
+static DltReceiver *dlt_connection_get_receiver(DltDaemonLocal *daemon_local,
+ DltConnectionType type)
+{
+ DltReceiver *ret = NULL;
+
+ switch (type)
+ {
+ case DLT_CONNECTION_CLIENT_CONNECT:
+ /* FALL THROUGH */
+ /* There must be the same structure for this case */
+ case DLT_CONNECTION_CLIENT_MSG_TCP:
+ ret = &daemon_local->receiverSock;
+ break;
+ case DLT_CONNECTION_CLIENT_MSG_SERIAL:
+ ret = &daemon_local->receiverSerial;
+ break;
+ case DLT_CONNECTION_APP_MSG:
+ ret = &daemon_local->receiver;
+ break;
+ case DLT_CONNECTION_ONE_S_TIMER:
+ ret = &daemon_local->timer_one_s;
+ break;
+ case DLT_CONNECTION_SIXTY_S_TIMER:
+ ret = &daemon_local->timer_sixty_s;
+ break;
+#ifdef DLT_SYSTEMD_WATCHDOG_ENABLE
+ case DLT_CONNECTION_SYSTEMD_TIMER:
+ ret = &daemon_local->timer_wd;
+ break;
+#endif
+ default:
+ ret = NULL;
+ }
+
+ return ret;
+}
+
+/** @brief Get the callback from a specific connection.
+ *
+ * The callback retrieved that way is used to handle event for this connection.
+ * It as been chosen to proceed that way instead of having the callback directly
+ * in the structure in order to have some way to check that the structure is
+ * still valid, or at least gracefully handle errors instead of crashing.
+ *
+ * @param con The connection to retrieve the callback from.
+ *
+ * @return Function pointer or NULL.
+ */
+void *dlt_connection_get_callback(DltConnection *con)
+{
+ void *ret = NULL;
+ DltConnectionType type = DLT_CONNECTION_TYPE_MAX;
+
+ if (con)
+ {
+ type = con->type;
+ }
+
+ switch (type)
+ {
+ case DLT_CONNECTION_CLIENT_CONNECT:
+ ret = dlt_daemon_process_client_connect;
+ break;
+ case DLT_CONNECTION_CLIENT_MSG_TCP:
+ ret = dlt_daemon_process_client_messages;
+ break;
+ case DLT_CONNECTION_CLIENT_MSG_SERIAL:
+ ret = dlt_daemon_process_client_messages_serial;
+ break;
+ case DLT_CONNECTION_APP_MSG:
+ ret = dlt_daemon_process_user_messages;
+ break;
+ case DLT_CONNECTION_ONE_S_TIMER:
+ ret = dlt_daemon_process_one_s_timer;
+ break;
+ case DLT_CONNECTION_SIXTY_S_TIMER:
+ ret = dlt_daemon_process_sixty_s_timer;
+ break;
+#ifdef DLT_SYSTEMD_WATCHDOG_ENABLE
+ case DLT_CONNECTION_SYSTEMD_TIMER:
+ ret = dlt_daemon_process_systemd_timer;
+ break;
+#endif
+ default:
+ ret = NULL;
+ }
+
+ return ret;
+}
+
+/** @brief Destroys a connection.
+ *
+ * This function closes and frees the corresponding connection. This is expected
+ * to be called by the connection owner: the DltEventHandler.
+ * Ownership of the connection is given during the registration to
+ * the DltEventHandler.
+ *
+ * @param to_destroy Connection to be destroyed.
+ */
+void dlt_connection_destroy(DltConnection *to_destroy)
+{
+ close(to_destroy->fd);
+ free(to_destroy);
+}
+
+/** @brief Creates a connection and registers it to the DltEventHandler.
+ *
+ * The function will allocate memory for the connection, and give the pointer
+ * to the DltEventHandler in order to register it for incoming events.
+ * The connection is then destroyed later on, once it's not needed anymore or
+ * it the event handler is destroyed.
+ *
+ * @param daemon_local Structure were some needed information is.
+ * @param evh DltEventHandler to register the connection to.
+ * @param fd File descriptor of the connection.
+ * @param mask Event list bit mask.
+ * @param type Connection type.
+ *
+ * @return 0 On success, -1 otherwise.
+ */
+int dlt_connection_create(DltDaemonLocal *daemon_local,
+ DltEventHandler *evh,
+ int fd,
+ int mask,
+ DltConnectionType type)
+{
+ DltConnection *temp = NULL;
+
+ if (dlt_event_handler_find_connection(evh, fd) != NULL)
+ {
+ /* No need for the same client to be registered twice
+ * for the same event.
+ * TODO: If another mask can be expected,
+ * we need it to update the epoll event here.
+ */
+ return 0;
+ }
+
+ temp = (DltConnection *)malloc(sizeof(DltConnection));
+
+ if (temp == NULL)
+ {
+ dlt_log(LOG_CRIT, "Allocation of client handle failed\n");
+ return -1;
+ }
+
+ memset(temp, 0, sizeof(DltConnection));
+
+ temp->fd = fd;
+ temp->type = type;
+ temp->receiver = dlt_connection_get_receiver(daemon_local, type);
+
+ /* Now give the ownership of the newly created connection
+ * to the event handler, by registering for events.
+ */
+ return dlt_event_handler_register_connection(evh, daemon_local, temp, mask);
+}
+
+/** @brief Creates connection from all types.
+ *
+ * This functions run through all connection types and tries to register
+ * on the event handler the one that were not already registered.
+ *
+ * @param daemon_local Structure to retrieve information from.
+ *
+ * @return 0 on success, -1 if a failure occurs.
+ */
+int dlt_connection_create_remaining(DltDaemonLocal *daemon_local)
+{
+ DltConnectionType i = 0;
+ DltEventHandler *ev = &daemon_local->pEvent;
+ char local_str[DLT_DAEMON_TEXTBUFSIZE];
+
+ for (i = 0 ; i < DLT_CONNECTION_TYPE_MAX ; i++)
+ {
+ int fd = 0;
+ DltReceiver *rec = dlt_connection_get_receiver(daemon_local, i);
+
+ if (rec == NULL)
+ {
+ /* We are not interested if there is no receiver available */
+ continue;
+ }
+
+ fd = rec->fd;
+
+ /* Already created connections are ignored here */
+ if ((fd > 0) && dlt_connection_create(daemon_local, ev, fd, EPOLLIN, i))
+ {
+ snprintf(local_str,
+ DLT_DAEMON_TEXTBUFSIZE,
+ "Unable to register type %i event handler.\n",
+ i);
+
+ dlt_log(LOG_ERR, local_str);
+
+ return -1;
+ }
+ }
+
+ return 0;
+}
diff --git a/src/daemon/dlt_daemon_connection.h b/src/daemon/dlt_daemon_connection.h
new file mode 100644
index 0000000..aa21a11
--- /dev/null
+++ b/src/daemon/dlt_daemon_connection.h
@@ -0,0 +1,51 @@
+/*
+ * @licence app begin@
+ * SPDX license identifier: MPL-2.0
+ *
+ * Copyright (C) 2015 Advanced Driver Information Technology.
+ * This code is developed by Advanced Driver Information Technology.
+ * Copyright of Advanced Driver Information Technology, Bosch and DENSO.
+ *
+ * This file is part of GENIVI Project DLT - Diagnostic Log and Trace.
+ *
+ * This Source Code Form is subject to the terms of the
+ * Mozilla Public License (MPL), v. 2.0.
+ * If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * For further information see http://www.genivi.org/.
+ * @licence end@
+ */
+
+/*!
+ * \author
+ * Frederic Berat <fberat@de.adit-jv.com>
+ *
+ * \copyright Copyright © 2015 Advanced Driver Information Technology. \n
+ * License MPL-2.0: Mozilla Public License version 2.0 http://mozilla.org/MPL/2.0/.
+ *
+ * \file dlt_daemon_connection.h
+ */
+
+#ifndef DLT_DAEMON_CONNECTION_H
+#define DLT_DAEMON_CONNECTION_H
+
+#include "dlt_daemon_connection_types.h"
+#include "dlt_daemon_event_handler_types.h"
+#include "dlt-daemon.h"
+
+int dlt_connection_send_multiple(DltConnection *, void *, int, void *, int, int);
+
+DltConnection *dlt_connection_get_next(DltConnection *, int);
+int dlt_connection_create_remaining(DltDaemonLocal *);
+
+int dlt_connection_create(DltDaemonLocal *,
+ DltEventHandler *,
+ int,
+ int,
+ DltConnectionType);
+void dlt_connection_destroy(DltConnection *);
+
+void *dlt_connection_get_callback(DltConnection *);
+
+#endif /* DLT_DAEMON_CONNECTION_H */
diff --git a/src/daemon/dlt_daemon_connection_types.h b/src/daemon/dlt_daemon_connection_types.h
new file mode 100644
index 0000000..4f4bb1c
--- /dev/null
+++ b/src/daemon/dlt_daemon_connection_types.h
@@ -0,0 +1,64 @@
+/*
+ * @licence app begin@
+ * SPDX license identifier: MPL-2.0
+ *
+ * Copyright (C) 2015 Advanced Driver Information Technology.
+ * This code is developed by Advanced Driver Information Technology.
+ * Copyright of Advanced Driver Information Technology, Bosch and DENSO.
+ *
+ * This file is part of GENIVI Project DLT - Diagnostic Log and Trace.
+ *
+ * This Source Code Form is subject to the terms of the
+ * Mozilla Public License (MPL), v. 2.0.
+ * If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * For further information see http://www.genivi.org/.
+ * @licence end@
+ */
+
+/*!
+ * \author
+ * Frederic Berat <fberat@de.adit-jv.com>
+ *
+ * \copyright Copyright © 2015 Advanced Driver Information Technology. \n
+ * License MPL-2.0: Mozilla Public License version 2.0 http://mozilla.org/MPL/2.0/.
+ *
+ * \file dlt_daemon_connection_types.h
+ */
+
+#ifndef DLT_DAEMON_CONNECTION_TYPES_H
+#define DLT_DAEMON_CONNECTION_TYPES_H
+#include "dlt_common.h"
+
+typedef enum {
+ DLT_CONNECTION_CLIENT_CONNECT = 0,
+ DLT_CONNECTION_CLIENT_MSG_TCP,
+ DLT_CONNECTION_CLIENT_MSG_SERIAL,
+ DLT_CONNECTION_APP_MSG,
+ DLT_CONNECTION_ONE_S_TIMER,
+ DLT_CONNECTION_SIXTY_S_TIMER,
+ DLT_CONNECTION_SYSTEMD_TIMER,
+ DLT_CONNECTION_TYPE_MAX
+} DltConnectionType;
+
+#define DLT_CON_MASK_CLIENT_CONNECT (1 << DLT_CONNECTION_CLIENT_CONNECT)
+#define DLT_CON_MASK_CLIENT_MSG_TCP (1 << DLT_CONNECTION_CLIENT_MSG_TCP)
+#define DLT_CON_MASK_CLIENT_MSG_SERIAL (1 << DLT_CONNECTION_CLIENT_MSG_SERIAL)
+#define DLT_CON_MASK_APP_MSG (1 << DLT_CONNECTION_APP_MSG)
+#define DLT_CON_MASK_ONE_S_TIMER (1 << DLT_CONNECTION_ONE_S_TIMER)
+#define DLT_CON_MASK_SIXTY_S_TIMER (1 << DLT_CONNECTION_SIXTY_S_TIMER)
+#define DLT_CON_MASK_SYSTEMD_TIMER (1 << DLT_CONNECTION_SYSTEMD_TIMER)
+#define DLT_CON_MASK_ALL (0xff)
+
+/* TODO: squash the DltReceiver structure in there
+ * and remove any other duplicates of FDs
+ */
+typedef struct DltConnection {
+ int fd; /**< File descriptor */
+ DltConnectionType type; /**< Represents what type of handle is this (like FIFO, serial, client, server) */
+ DltReceiver *receiver; /**< Pointer to the affected receiver structure */
+ struct DltConnection *next; /**< For multiple client connection using linked list */
+} DltConnection;
+
+#endif /* DLT_DAEMON_CONNECTION_TYPES_H */
diff --git a/src/daemon/dlt_daemon_event_handler.c b/src/daemon/dlt_daemon_event_handler.c
new file mode 100644
index 0000000..3762ca2
--- /dev/null
+++ b/src/daemon/dlt_daemon_event_handler.c
@@ -0,0 +1,373 @@
+/*
+ * @licence app begin@
+ * SPDX license identifier: MPL-2.0
+ *
+ * Copyright (C) 2015 Advanced Driver Information Technology.
+ * This code is developed by Advanced Driver Information Technology.
+ * Copyright of Advanced Driver Information Technology, Bosch and DENSO.
+ *
+ * This file is part of GENIVI Project DLT - Diagnostic Log and Trace.
+ *
+ * This Source Code Form is subject to the terms of the
+ * Mozilla Public License (MPL), v. 2.0.
+ * If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * For further information see http://www.genivi.org/.
+ * @licence end@
+ */
+
+/*!
+ * \author
+ * Frederic Berat <fberat@de.adit-jv.com>
+ *
+ * \copyright Copyright © 2015 Advanced Driver Information Technology. \n
+ * License MPL-2.0: Mozilla Public License version 2.0 http://mozilla.org/MPL/2.0/.
+ *
+ * \file dlt_daemon_event_handler.c
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/epoll.h>
+#include <sys/syslog.h>
+
+#include "dlt_common.h"
+
+#include "dlt-daemon.h"
+#include "dlt-daemon_cfg.h"
+#include "dlt_daemon_common.h"
+#include "dlt_daemon_connection.h"
+#include "dlt_daemon_connection_types.h"
+#include "dlt_daemon_event_handler.h"
+#include "dlt_daemon_event_handler_types.h"
+
+/**
+ * \def DLT_EPOLL_TIMEOUT_MSEC
+ * The maximum amount of time to wait for an epoll event.
+ * Set to 1 second to avoid unnecessary wake ups.
+ */
+#define DLT_EPOLL_TIMEOUT_MSEC 1000
+
+/** @brief Prepare the event handler
+ *
+ * This will create the epoll file descriptor.
+ *
+ * @param ev The event handler to prepare.
+ *
+ * @return 0 on success, -1 otherwise.
+ */
+int dlt_daemon_prepare_event_handling(DltEventHandler *ev)
+{
+ ev->epfd = epoll_create(DLT_EPOLL_MAX_EVENTS);
+
+ if (ev->epfd < 0)
+ {
+ dlt_log(LOG_CRIT, "Creation of epoll instance failed!\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/** @brief Catch and process incoming events.
+ *
+ * This function waits for events on all connections. Once an event raise,
+ * the callback for the specific connection is called, or the connection is
+ * destroyed if a hangup occurs.
+ *
+ * @param daemon Structure to be passed to the callback.
+ * @param daemon_local Structure containing needed information.
+ * @param pEvent Event handler structure.
+ *
+ * @return 0 on success, -1 otherwise. May be interrupted.
+ */
+int dlt_daemon_handle_event(DltEventHandler *pEvent,
+ DltDaemon *daemon,
+ DltDaemonLocal *daemon_local)
+{
+ int nfds = 0;
+ int i = 0;
+ char str[DLT_DAEMON_TEXTBUFSIZE];
+ int (*callback)(DltDaemon *, DltDaemonLocal *, int) = NULL;
+
+ /*CM Change begin*/
+ nfds = epoll_wait(pEvent->epfd,
+ pEvent->events,
+ DLT_EPOLL_MAX_EVENTS,
+ DLT_EPOLL_TIMEOUT_MSEC);
+
+ if (nfds < 0)
+ {
+ /* We are not interested in EINTR has it comes
+ * either from timeout or signal.
+ */
+ if (errno != EINTR)
+ {
+ snprintf(str,
+ DLT_DAEMON_TEXTBUFSIZE,
+ "epoll_wait() failed: %s\n",
+ strerror(errno));
+ dlt_log(LOG_CRIT, str);
+ return -1;
+ }
+
+ return 0;
+ }
+
+ for (i = 0 ; i < nfds ; i++)
+ {
+ struct epoll_event *ev = &pEvent->events[i];
+ int fd = 0;
+ DltConnectionType type = DLT_CONNECTION_TYPE_MAX;
+
+ if ((DltConnection *)ev->data.ptr)
+ {
+ type = ((DltConnection *)ev->data.ptr)->type;
+ fd = ((DltConnection *)ev->data.ptr)->fd;
+ }
+
+ /* First of all handle epoll error events
+ * We only expect EPOLLIN or EPOLLOUT
+ */
+ if ((ev->events != EPOLLIN) && (ev->events != EPOLLOUT))
+ {
+ /* epoll reports an error, we need to clean-up the concerned event
+ */
+ dlt_event_handler_unregister_connection(pEvent,
+ daemon_local,
+ fd,
+ type);
+ continue;
+ }
+
+ /* Get the function to be used to handle the event */
+ callback = dlt_connection_get_callback((DltConnection *)ev->data.ptr);
+
+ if (!callback)
+ {
+ snprintf(str,
+ DLT_DAEMON_TEXTBUFSIZE,
+ "Unable to find function for %d handle type.\n",
+ type);
+ dlt_log(LOG_CRIT, str);
+ return -1;
+ }
+
+ /* TODO: Review the design to clean-up this line.
+ * fd are currently wrongly duplicated which may lead to errors. */
+ ((DltConnection *)ev->data.ptr)->receiver->fd = fd;
+
+ /* From now on, callback is correct */
+ if (callback(daemon, daemon_local, daemon_local->flags.vflag) == -1)
+ {
+ snprintf(str,
+ DLT_DAEMON_TEXTBUFSIZE,
+ "Processing from %d handle type failed!\n",
+ type );
+ dlt_log(LOG_CRIT, str);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/** @brief Find connection with a specific \a fd in the connection list.
+ *
+ * There can be only one event per \a fd. We can then find a specific connection
+ * based on this \a fd. That allows to check if a specific \a fd has already been
+ * registered.
+ *
+ * @param ev The event handler structure where the list of connection is.
+ * @param fd The file descriptor of the connection to be found.
+ *
+ * @return The found connection pointer, NULL otherwise.
+ */
+DltConnection *dlt_event_handler_find_connection(DltEventHandler *ev,
+ int fd)
+{
+ DltConnection *temp = ev->connections;
+
+ while ((temp != NULL) && (temp->fd != fd))
+ {
+ temp = temp->next;
+ }
+
+ return temp;
+}
+
+/** @brief Remove a connection from the list and destroy it.
+ *
+ * This function will first look for the connection in the event handler list,
+ * remove it from the list and then destroy it.
+ *
+ * @param ev The event handler structure where the list of connection is.
+ * @param to_remove The connection to remove from the list.
+ *
+ * @return 0 on success, -1 if the connection is not found.
+ */
+static int dlt_daemon_remove_connection(DltEventHandler *ev,
+ DltConnection *to_remove)
+{
+ DltConnection **curr = &ev->connections;
+
+ /* Find the address where to_remove value is registered */
+ while (*curr && (*curr != to_remove))
+ {
+ curr = &(*curr)->next;
+ }
+
+ if (!*curr)
+ {
+ /* Must not be possible as we check for existence before */
+ dlt_log(LOG_CRIT, "Connection not found for removal.\n");
+ return -1;
+ }
+
+ /* Replace the content of the address by the next value */
+ *curr = (*curr)->next;
+
+ /* Now we can destroy our pointer */
+ dlt_connection_destroy(to_remove);
+
+ return 0;
+}
+
+/** @brief Destroy the connection list.
+ *
+ * This function runs through the connection list and destroy them one by one.
+ *
+ * @param ev Pointer to the event handler structure.
+ */
+void dlt_event_handler_cleanup_connections(DltEventHandler *ev)
+{
+ if (ev == NULL)
+ {
+ /* Nothing to do. */
+ return;
+ }
+
+ while (ev->connections != NULL)
+ {
+ /* We don really care on failure */
+ (void)dlt_daemon_remove_connection(ev, ev->connections);
+ }
+}
+
+/** @brief Add a new connection to the list.
+ *
+ * The connection is added at the tail of the list.
+ *
+ * @param ev The event handler structure where the connection list is.
+ * @param connection The connection to be added.
+ */
+static void dlt_daemon_add_connection(DltEventHandler *ev,
+ DltConnection *connection)
+{
+ DltConnection **temp = &ev->connections;
+
+ while (*temp != NULL)
+ {
+ temp = &(*temp)->next;
+ }
+
+ *temp = connection;
+}
+
+/** @brief Registers a connection for event handling and takes its ownership.
+ *
+ * As we add the connection to the list of connection, we take its ownership.
+ * That's the only place where the connection pointer is stored.
+ * The connection is then used to create a new event trigger.
+ * If the connection is of type DLT_CONNECTION_CLIENT_MSG_TCP, we increase
+ * the daemon_local->client_connections counter. TODO: Move this counter inside
+ * the event handler structure.
+ *
+ * @param evhdl The event handler structure where the connection list is.
+ * @param daemon_local Structure containing needed information.
+ * @param connection The connection to be registered.
+ * @param mask The bit mask of event to be registered.
+ *
+ * @return 0 on success, -1 otherwise.
+ */
+int dlt_event_handler_register_connection(DltEventHandler *evhdl,
+ DltDaemonLocal *daemon_local,
+ DltConnection *connection,
+ int mask)
+{
+ struct epoll_event ev; /* Content will be copied by the kernel */
+
+ dlt_daemon_add_connection(evhdl, connection);
+
+ ev.events = mask;
+ ev.data.ptr = (void *)connection;
+
+ if (epoll_ctl(evhdl->epfd, EPOLL_CTL_ADD, connection->fd, &ev) == -1)
+ {
+ dlt_log(LOG_ERR, "epoll_ctl() failed!\n");
+ dlt_daemon_remove_connection(evhdl, connection);
+ return -1;
+ }
+
+ if (connection->type == DLT_CONNECTION_CLIENT_MSG_TCP)
+ {
+ daemon_local->client_connections++;
+ }
+
+ return 0;
+}
+
+/** @brief Unregisters a connection from the event handler and destroys it.
+ *
+ * We first look for the connection to be unregistered, delete the event
+ * corresponding and then destroy the connection.
+ * If the connection is of type DLT_CONNECTION_CLIENT_MSG_TCP, we decrease
+ * the daemon_local->client_connections counter. TODO: Move this counter inside
+ * the event handler structure.
+ *
+ * @param evhdl The event handler structure where the connection list is.
+ * @param daemon_local Structure containing needed information.
+ * @param fd The file descriptor of the connection to be unregistered.
+ * @param type the connection type.
+ *
+ * @return 0 on success, -1 otherwise.
+ */
+int dlt_event_handler_unregister_connection(DltEventHandler *evhdl,
+ DltDaemonLocal *daemon_local,
+ int fd,
+ DltConnectionType type)
+{
+ /* Look for the pointer in the client list.
+ * There shall be only one event handler with the same fd.
+ */
+ DltConnection *temp = dlt_event_handler_find_connection(evhdl, fd);
+
+ if (!temp)
+ {
+ dlt_log(LOG_ERR, "Connection not found for unregistration.\n");
+ return -1;
+ }
+
+ if (epoll_ctl(evhdl->epfd, EPOLL_CTL_DEL, fd, NULL) < 0)
+ {
+ dlt_log(LOG_ERR, "Unable to unregister event.\n");
+ return -1;
+ }
+
+ if (type == DLT_CONNECTION_CLIENT_MSG_TCP)
+ {
+ daemon_local->client_connections--;
+
+ if (daemon_local->client_connections < 0)
+ {
+ daemon_local->client_connections = 0;
+ dlt_log(LOG_CRIT, "Unregistering more client than registered!\n");
+ }
+ }
+
+ /* Cannot fail as far as dlt_daemon_find_connection succeed */
+ return dlt_daemon_remove_connection(evhdl, temp);
+}
diff --git a/src/daemon/dlt_daemon_event_handler.h b/src/daemon/dlt_daemon_event_handler.h
new file mode 100644
index 0000000..cd5d8ca
--- /dev/null
+++ b/src/daemon/dlt_daemon_event_handler.h
@@ -0,0 +1,57 @@
+/*
+ * @licence app begin@
+ * SPDX license identifier: MPL-2.0
+ *
+ * Copyright (C) 2015 Advanced Driver Information Technology.
+ * This code is developed by Advanced Driver Information Technology.
+ * Copyright of Advanced Driver Information Technology, Bosch and DENSO.
+ *
+ * This file is part of GENIVI Project DLT - Diagnostic Log and Trace.
+ *
+ * This Source Code Form is subject to the terms of the
+ * Mozilla Public License (MPL), v. 2.0.
+ * If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * For further information see http://www.genivi.org/.
+ * @licence end@
+ */
+
+/*!
+ * \author
+ * Frederic Berat <fberat@de.adit-jv.com>
+ *
+ * \copyright Copyright © 2015 Advanced Driver Information Technology. \n
+ * License MPL-2.0: Mozilla Public License version 2.0 http://mozilla.org/MPL/2.0/.
+ *
+ * \file dlt_daemon_event_handler.h
+ */
+
+#include <sys/epoll.h>
+
+#include "dlt_daemon_connection_types.h"
+#include "dlt_daemon_event_handler_types.h"
+#include "dlt-daemon.h"
+
+#ifndef DLT_DAEMON_EVENT_HANDLER_H
+# define DLT_DAEMON_EVENT_HANDLER_H
+
+int dlt_daemon_prepare_event_handling(DltEventHandler *);
+int dlt_daemon_handle_event(DltEventHandler *, DltDaemon *, DltDaemonLocal *);
+
+DltConnection *dlt_event_handler_find_connection(DltEventHandler *,
+ int);
+
+void dlt_event_handler_cleanup_connections(DltEventHandler *);
+
+int dlt_event_handler_register_connection(DltEventHandler *,
+ DltDaemonLocal *,
+ DltConnection *,
+ int);
+
+int dlt_event_handler_unregister_connection(DltEventHandler *,
+ DltDaemonLocal *,
+ int,
+ DltConnectionType);
+
+#endif /* DLT_DAEMON_EVENT_HANDLER_H */
diff --git a/src/daemon/dlt_daemon_event_handler_types.h b/src/daemon/dlt_daemon_event_handler_types.h
new file mode 100644
index 0000000..080c331
--- /dev/null
+++ b/src/daemon/dlt_daemon_event_handler_types.h
@@ -0,0 +1,59 @@
+/*
+ * @licence app begin@
+ * SPDX license identifier: MPL-2.0
+ *
+ * Copyright (C) 2015 Advanced Driver Information Technology.
+ * This code is developed by Advanced Driver Information Technology.
+ * Copyright of Advanced Driver Information Technology, Bosch and DENSO.
+ *
+ * This file is part of GENIVI Project DLT - Diagnostic Log and Trace.
+ *
+ * This Source Code Form is subject to the terms of the
+ * Mozilla Public License (MPL), v. 2.0.
+ * If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * For further information see http://www.genivi.org/.
+ * @licence end@
+ */
+
+/*!
+ * \author
+ * Frederic Berat <fberat@de.adit-jv.com>
+ *
+ * \copyright Copyright © 2015 Advanced Driver Information Technology. \n
+ * License MPL-2.0: Mozilla Public License version 2.0 http://mozilla.org/MPL/2.0/.
+ *
+ * \file dlt_daemon_event_handler_types.h
+ */
+
+#include <sys/epoll.h>
+
+#include "dlt_daemon_connection_types.h"
+
+#ifndef DLT_DAEMON_EVENT_HANDLER_TYPES_H
+#define DLT_DAEMON_EVENT_HANDLER_TYPES_H
+
+/* FIXME: Remove the need for DltDaemonLocal everywhere in the code
+ * These typedefs are needed by DltDaemonLocal which is
+ * itself needed for functions used by the event handler
+ * (as this structure is used everywhere in the code ...)
+ */
+
+typedef enum {
+ DLT_TIMER_PACKET = 0,
+ DLT_TIMER_ECU,
+#ifdef DLT_SYSTEMD_WATCHDOG_ENABLE
+ DLT_TIMER_SYSTEMD,
+#endif
+ DLT_TIMER_UNKNOWN
+} DltTimers;
+
+#define DLT_EPOLL_MAX_EVENTS 10
+typedef struct {
+ int epfd;
+ struct epoll_event events[DLT_EPOLL_MAX_EVENTS];
+ DltConnection *connections;
+} DltEventHandler;
+
+#endif /* DLT_DAEMON_EVENT_HANDLER_TYPES_H */