summaryrefslogtreecommitdiff
path: root/src/daemon/dlt_daemon_connection.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/daemon/dlt_daemon_connection.c')
-rw-r--r--src/daemon/dlt_daemon_connection.c374
1 files changed, 374 insertions, 0 deletions
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;
+}