diff --git a/build_inside_container.sh b/build_inside_container.sh index 72467960..b2e2003a 100755 --- a/build_inside_container.sh +++ b/build_inside_container.sh @@ -27,7 +27,7 @@ autoreconf --install # FLags to print compiler warnings DEBUG_CFLAGS="-Wall -Werror -Wextra" -export CFLAGS=" ${DEBUG_CFLAGS} -I${INSTALL_DIR}/include/rtmessage -I${INSTALL_DIR}/include/msgpack -I${INSTALL_DIR}/include/rbus -I${INSTALL_DIR}/include -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/local/include -DFEATURE_SUPPORT_WEBCONFIG -DRDK_LOGGER -DPERSIST_LOG_MON_REF -DDCMAGENT" +export CFLAGS=" ${DEBUG_CFLAGS} -I/usr/lib/x86_64-linux-gnu/dbus-1.0/include -I/usr/include/dbus-1.0 -I${INSTALL_DIR}/include/rtmessage -I${INSTALL_DIR}/include/msgpack -I${INSTALL_DIR}/include/rbus -I${INSTALL_DIR}/include -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/local/include -DFEATURE_SUPPORT_WEBCONFIG -DRDK_LOGGER -DPERSIST_LOG_MON_REF -DDCMAGENT" export LDFLAGS="-L/usr/lib/x86_64-linux-gnu -lglib-2.0" diff --git a/source/bulkdata/reportprofiles.c b/source/bulkdata/reportprofiles.c index dbe48be5..b647f7b3 100644 --- a/source/bulkdata/reportprofiles.c +++ b/source/bulkdata/reportprofiles.c @@ -315,7 +315,9 @@ T2ERROR ReportProfiles_setProfileXConf(ProfileXConf *profile) { unregisterDEforCompEventList(); createComponentDataElements(); - publishEventsProfileUpdates(); + //publishEventsProfileUpdates(); + publishDBUSEventsProfileUpdates(); + } T2ER_StartDispatchThread(); @@ -1082,7 +1084,8 @@ void ReportProfiles_ProcessReportProfilesBlob(cJSON *profiles_root, bool rprofil { createComponentDataElements(); // Notify registered components that profile has received an update - publishEventsProfileUpdates(); + //publishEventsProfileUpdates(); + publishDBUSEventsProfileUpdates(); getMarkerCompRbusSub(true); } hash_map_destroy(receivedProfileHashMap, freeReportProfileHashMap); @@ -1451,7 +1454,8 @@ int __ReportProfiles_ProcessReportProfilesMsgPackBlob(void *msgpack, bool checkP { createComponentDataElements(); // Notify registered components that profile has received an update - publishEventsProfileUpdates(); + // publishEventsProfileUpdates(); + publishDBUSEventsProfileUpdates(); getMarkerCompRbusSub(true); } msgpack_unpacked_destroy(&result); diff --git a/source/bulkdata/t2eventreceiver.c b/source/bulkdata/t2eventreceiver.c index 5099e0e0..804ddcbf 100644 --- a/source/bulkdata/t2eventreceiver.c +++ b/source/bulkdata/t2eventreceiver.c @@ -196,13 +196,13 @@ void T2ER_Push(char* eventName, char* eventValue) } else { - T2Debug("Received eventInfo : %s value : %s\n", eventName, (char* ) eventValue); + T2Info("Received eventInfo : %s value : %s\n", eventName, (char* ) eventValue); T2Event *event = (T2Event *) malloc(sizeof(T2Event)); if(event != NULL) { event->name = strdup(eventName); event->value = strdup(eventValue); - T2Debug("Adding eventName : %s eventValue : %s to t2event queue\n", event->name, event->value); + T2Info("Adding eventName : %s eventValue : %s to t2event queue\n", event->name, event->value); t2_queue_push(eQueue, (void *) event); if(!stopDispatchThread) { diff --git a/source/bulkdata/t2markers.c b/source/bulkdata/t2markers.c index 20bb3b3e..3a19baec 100644 --- a/source/bulkdata/t2markers.c +++ b/source/bulkdata/t2markers.c @@ -330,7 +330,18 @@ void createComponentDataElements() char *compName = (char*) Vector_At(componentList, i); if(compName) { - regDEforCompEventList(compName, getComponentMarkerList); + T2Info("Register data element for component %s \n", compName); + //TODO componet specific dbus inteface registration like rbus data element registration + if(T2ERROR_SUCCESS == registerGetMarkerListCallback(getComponentMarkerList)) + { + T2Info("Registered get marker list callback for component %s \n", compName); + i = length; // exit for loop because dbus uses common callback for all components + } + else + { + T2Error("Failed to register get marker list callback for component %s \n", compName); + } + //regDEforCompEventList(compName, getComponentMarkerList); } } pthread_mutex_unlock(&t2CompListMutex); diff --git a/source/ccspinterface/Makefile.am b/source/ccspinterface/Makefile.am index af372e01..13ddb27e 100644 --- a/source/ccspinterface/Makefile.am +++ b/source/ccspinterface/Makefile.am @@ -20,9 +20,9 @@ AM_CFLAGS = lib_LTLIBRARIES = libccspinterface.la -libccspinterface_la_SOURCES = busInterface.c rbusInterface.c +libccspinterface_la_SOURCES = busInterface.c rbusInterface.c dbusInterface.c libccspinterface_la_CFLAGS = $(GLIB_CFLAGS) -libccspinterface_la_LDFLAGS = -shared -fPIC -lrbus $(GLIB_LIBS) +libccspinterface_la_LDFLAGS = -shared -fPIC -lrbus -ldbus-1 $(GLIB_LIBS) if ENABLE_CCSP_SUPPORT libccspinterface_la_LDFLAGS += -lccsp_common libccspinterface_la_SOURCES += ccspinterface.c diff --git a/source/ccspinterface/busInterface.c b/source/ccspinterface/busInterface.c index 60c0051a..684d9bc5 100644 --- a/source/ccspinterface/busInterface.c +++ b/source/ccspinterface/busInterface.c @@ -29,6 +29,7 @@ #endif #include "rbusInterface.h" +#include "dbusInterface.h" static bool isRbus = false ; static bool isBusInit = false ; @@ -59,6 +60,15 @@ static bool busInit( ) T2Debug("%s --RBUS mode is active \n", __FUNCTION__); //CID 158206:Unchecked return value } isBusInit = true; + + if (dBusInterface_Init() == T2ERROR_SUCCESS) + { + T2Debug("%s --DBUS mode is active \n", __FUNCTION__); //CID 158206:Unchecked return value + } + else + { + T2Error("%s --DBUS init failed \n", __FUNCTION__); + } } T2Debug("%s --out \n", __FUNCTION__); return isBusInit; @@ -112,6 +122,28 @@ Vector* getProfileParameterValues(Vector *paramList, int count) return profileValueList; } +T2ERROR publishDBUSEventsProfileUpdates() +{ + T2Debug("%s ++in\n", __FUNCTION__); + T2ERROR ret = T2ERROR_FAILURE ; + T2Info("Publishing dbus event for t2profile update notification to components \n"); + ret = publishdbusEventsProfileUpdates(); + + T2Debug("%s --out\n", __FUNCTION__); + return ret; +} + +T2ERROR registerGetMarkerListCallback(T2EventMarkerListCallback callback) +{ + T2Debug("%s ++in\n", __FUNCTION__); + T2ERROR ret = T2ERROR_FAILURE ; + + ret = registerDbusHandlerGetMarkerListCallback(callback); + + T2Debug("%s --out\n", __FUNCTION__); + return ret; +} + /** * Register with right bus call back dpending on dbus/rbus mode */ @@ -124,9 +156,12 @@ T2ERROR registerForTelemetryEvents(TelemetryEventCallback eventCB) busInit(); } + ret = registerDbusT2EventListener(eventCB); + if (isRbus) { - ret = registerRbusT2EventListener(eventCB); + // ret = registerRbusT2EventListener(eventCB); + T2Info("RBUS repeaceled with dbus\n"); #ifdef DCMAGENT /* Register DCM Events */ diff --git a/source/ccspinterface/busInterface.h b/source/ccspinterface/busInterface.h index de0f33e9..bf90243a 100644 --- a/source/ccspinterface/busInterface.h +++ b/source/ccspinterface/busInterface.h @@ -93,7 +93,8 @@ T2ERROR registerForTelemetryEvents(TelemetryEventCallback eventCB); // Needs to be called only in rBus mode T2ERROR regDEforCompEventList(const char* componentName, T2EventMarkerListCallback callBackHandler) ; - +// Common callback registration for dbus +T2ERROR registerGetMarkerListCallback(T2EventMarkerListCallback callback); void setT2EventReceiveState(int T2_STATE); void unregisterDEforCompEventList(); @@ -101,6 +102,7 @@ void unregisterDEforCompEventList(); T2ERROR regDEforProfileDataModel(callBackHandlers* cbHandlers); T2ERROR publishEventsProfileUpdates() ; +T2ERROR publishDBUSEventsProfileUpdates(); #ifdef DCMAGENT /* DCM RBus event Publish functions */ diff --git a/source/ccspinterface/dbusInterface.c b/source/ccspinterface/dbusInterface.c new file mode 100755 index 00000000..138e61c2 --- /dev/null +++ b/source/ccspinterface/dbusInterface.c @@ -0,0 +1,646 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2026 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +/** + * @file dbusInterface.c + * @brief D-Bus Interface Implementation for Telemetry 2.0 + * + * This file implements D-Bus based inter-process communication + * as an alternative to RBUS for telemetry operations. + */ + +#include +#include +#include +#include +#include +#include + +#include "dbusInterface.h" +#include "t2collection.h" +#include "t2common.h" +#include "busInterface.h" +#include "telemetry2_0.h" +#include "t2log_wrapper.h" +#include "profile.h" + +#define BUFF_LEN 1024 +#define MAX_PARAM_LEN 128 + +/* Global D-Bus handle */ +static T2DbusHandle_t t2dbus_handle = {NULL, NULL, false}; + +/* Callback handlers */ +static TelemetryEventCallback eventCallBack = NULL; +static T2EventMarkerListCallback getMarkerListCallBack = NULL; + +/* State variables */ +static uint32_t t2ReadyStatus = T2_STATE_NOT_READY; + +/* Threading */ +static pthread_mutex_t dbusMutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_t dbusListenerThread; +static bool stopListenerThread = false; + +/** + * @brief Check if D-Bus is initialized + */ +bool isDbusInitialized(void) { + return t2dbus_handle.is_initialized; +} + +/* Handle GetOperationalStatus Method */ +static DBusHandlerResult handle_get_operational_status(DBusConnection *connection, DBusMessage *message) { + + DBusError error; + dbus_error_init(&error); + + const char* param_name = NULL; + if (!dbus_message_get_args(message, &error, + DBUS_TYPE_STRING, ¶m_name, + DBUS_TYPE_INVALID)) { + T2Error("Failed to parse GetOperationalStatus arguments: %s\n", error.message); + dbus_error_free(&error); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + T2Debug("GetOperationalStatus called with param_name: %s\n", param_name); + + uint32_t value = 0; + /* TODO check oprtational status of specific component param_name will componet name */ + value = t2ReadyStatus; + T2Info("Returning operational status for %s: 0x%08X\n", param_name, value); + + /* Create reply */ + DBusMessage *reply = dbus_message_new_method_return(message); + if (!reply) { + T2Error("Failed to create reply message\n"); + return DBUS_HANDLER_RESULT_NEED_MEMORY; + } + + if (!dbus_message_append_args(reply, + DBUS_TYPE_UINT32, &value, + DBUS_TYPE_INVALID)) { + T2Error("Failed to append reply arguments\n"); + dbus_message_unref(reply); + return DBUS_HANDLER_RESULT_NEED_MEMORY; + } + + if (!dbus_connection_send(connection, reply, NULL)) { + T2Error("Failed to send reply\n"); + dbus_message_unref(reply); + return DBUS_HANDLER_RESULT_NEED_MEMORY; + } + + dbus_message_unref(reply); + //dbus_connection_flush(connection); + + return DBUS_HANDLER_RESULT_HANDLED; +} + +/* Handle SendT2Event Method */ +static DBusHandlerResult handle_send_t2_event(DBusConnection *connection, DBusMessage *message) { + T2Debug("handle_send_t2_event: Received SendT2Event method call\n"); + + DBusError error; + dbus_error_init(&error); + + const char* marker_name = NULL; + const char* data = NULL; + dbus_bool_t success = FALSE; + + if (!dbus_message_get_args(message, &error, + DBUS_TYPE_STRING, &marker_name, + DBUS_TYPE_STRING, &data, + DBUS_TYPE_INVALID)) { + T2Error("Failed to parse SendT2Event arguments: %s\n", error.message); + dbus_error_free(&error); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + if (marker_name && data && eventCallBack) { + T2Info("Received event: name=%s, value=%s\n", marker_name, data); + eventCallBack(strdup(marker_name), strdup(data)); + success = TRUE; + } else { + T2Error("Failed to process event - invalid parameters or callback not registered\n"); + success = FALSE; + } + + /* Create reply with success status */ + DBusMessage *reply = dbus_message_new_method_return(message); + if (!reply) { + T2Error("Failed to create reply message\n"); + return DBUS_HANDLER_RESULT_NEED_MEMORY; + } + + if (!dbus_message_append_args(reply, + DBUS_TYPE_BOOLEAN, &success, + DBUS_TYPE_INVALID)) { + T2Error("Failed to append reply arguments\n"); + dbus_message_unref(reply); + return DBUS_HANDLER_RESULT_NEED_MEMORY; + } + + if (!dbus_connection_send(connection, reply, NULL)) { + T2Error("Failed to send reply\n"); + dbus_message_unref(reply); + return DBUS_HANDLER_RESULT_NEED_MEMORY; + } + + T2Debug("SendT2Event: Reply sent successfully with status=%s\n", success ? "true" : "false"); + dbus_message_unref(reply); + //dbus_connection_flush(connection); + + return DBUS_HANDLER_RESULT_HANDLED; +} + +/* Handle GetMarkerList Method */ +static DBusHandlerResult handle_get_marker_list(DBusConnection *connection, DBusMessage *message) { + T2Debug("handle_get_marker_list: Received GetMarkerList method call\n"); + DBusMessage *reply = NULL; + DBusError error; + dbus_error_init(&error); + + const char* component_name = NULL; + if (!dbus_message_get_args(message, &error, + DBUS_TYPE_STRING, &component_name, + DBUS_TYPE_INVALID)) { + T2Error("Failed to parse GetMarkerList arguments: %s\n", error.message); + dbus_error_free(&error); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + T2Info("GetMarkerList called for component: %s\n", component_name); + + if (!getMarkerListCallBack) { + T2Error("GetMarkerList callback not registered\n"); + reply = dbus_message_new_error(message, DBUS_ERROR_FAILED, + "Marker list callback not initialized"); + if (reply) { + dbus_connection_send(connection, reply, NULL); + //dbus_connection_flush(connection); + dbus_message_unref(reply); + } + } + else + { + Vector *markerList = NULL; + getMarkerListCallBack(component_name, (void**)&markerList); + char markerListStr[4096] = ""; + if (markerList && Vector_Size(markerList) > 0) { + for (size_t i = 0; i < Vector_Size(markerList); i++) { + char *marker = (char*)Vector_At(markerList, i); + if (marker) { + if (i > 0) strcat(markerListStr, ","); + strcat(markerListStr, marker); + } + } + Vector_Destroy(markerList, free); + } + + reply = dbus_message_new_method_return(message); + if (!reply) { + T2Error("Failed to create reply message\n"); + return DBUS_HANDLER_RESULT_NEED_MEMORY; + } + const char *result = markerListStr; + + if (!dbus_message_append_args(reply, + DBUS_TYPE_STRING, &result, + DBUS_TYPE_INVALID)) { + T2Error("Failed to append reply arguments\n"); + dbus_message_unref(reply); + return DBUS_HANDLER_RESULT_NEED_MEMORY; + } + + T2Info("Returning marker list: %s\n", markerListStr); + + if (!dbus_connection_send(connection, reply, NULL)) { + T2Error("Failed to send reply\n"); + dbus_message_unref(reply); + return DBUS_HANDLER_RESULT_NEED_MEMORY; + } + + //dbus_connection_flush(connection); + T2Debug("GetMarkerList: Reply sent successfully\n"); + dbus_message_unref(reply); + } + + return DBUS_HANDLER_RESULT_HANDLED; +} + +/* Message Handler */ +static DBusHandlerResult message_handler(DBusConnection *connection, DBusMessage *message, void *user_data) { + (void)user_data; + + const char* interface = dbus_message_get_interface(message); + const char* member = dbus_message_get_member(message); + const char* path = dbus_message_get_path(message); + + T2Debug("Received D-Bus message: interface=%s, member=%s, path=%s\n", + interface ? interface : "NULL", + member ? member : "NULL", + path ? path : "NULL"); + + /* Check if message is for our interface */ + if (interface && strcmp(interface, T2_DBUS_INTERFACE_NAME) == 0) + { + if (dbus_message_is_method_call(message, T2_DBUS_INTERFACE_NAME, "GetOperationalStatus")) { + return handle_get_operational_status(connection, message); + } + else if (dbus_message_is_method_call(message, T2_DBUS_INTERFACE_NAME, "SendT2Event")) { + return handle_send_t2_event(connection, message); + } + else if (dbus_message_is_method_call(message, T2_DBUS_INTERFACE_NAME, "GetMarkerList")) { + return handle_get_marker_list(connection, message); + } + } + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +/** + * @brief D-Bus listener thread function + */ +static void* dbusListenerThreadFunc(void *arg) { + (void)arg; + + T2Debug("%s ++in\n", __FUNCTION__); + + while (!stopListenerThread && t2dbus_handle.connection) { + dbus_connection_read_write_dispatch(t2dbus_handle.connection, 0); + usleep(1); // Sleep for 1us to avoid busy-waiting + } + T2Debug("%s --out\n", __FUNCTION__); + return NULL; +} + +T2ERROR publishdbusEventsProfileUpdates(void) +{ + T2Debug("%s ++in\n", __FUNCTION__); + if (!t2dbus_handle.is_initialized) { + if (dBusInterface_Init() != T2ERROR_SUCCESS) { + return T2ERROR_FAILURE; + } + } + + DBusMessage *signal = dbus_message_new_signal(T2_DBUS_OBJECT_PATH, + T2_DBUS_EVENT_INTERFACE_NAME, + T2_DBUS_SIGNAL_PROFILE_UPDATE); + if (!signal) { + T2Error("Failed to create ProfileUpdate signal\n"); + return T2ERROR_FAILURE; + } + + /* Send signal - this queues the message */ + dbus_uint32_t serial = 0; + if (!dbus_connection_send(t2dbus_handle.connection, signal, &serial)) { + T2Error("Failed to send ProfileUpdate signal - out of memory\n"); + dbus_message_unref(signal); + return T2ERROR_FAILURE; + } + + //dbus_message_unref(signal); + + /* Flush to ensure signal is sent immediately */ + //dbus_connection_flush(t2dbus_handle.connection); + + T2Debug("ProfileUpdate signal sent successfully (serial=%u)\n", serial); + return T2ERROR_SUCCESS; +} + +/** + * @brief Initialize D-Bus interface + */ +T2ERROR dBusInterface_Init() { + T2Debug("%s ++in\n", __FUNCTION__); + + pthread_mutex_lock(&dbusMutex); + + if (t2dbus_handle.is_initialized) { + T2Warning("D-Bus interface already initialized\n"); + pthread_mutex_unlock(&dbusMutex); + return T2ERROR_SUCCESS; + } + + DBusError error; + dbus_error_init(&error); + + if (!dbus_threads_init_default()) { + T2Error("Failed to initialize D-Bus threading\n"); + return 1; + } + + /* Connect to system bus */ + t2dbus_handle.connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error); + if (dbus_error_is_set(&error)) { + T2Error("D-Bus connection error: %s\n", error.message); + dbus_error_free(&error); + pthread_mutex_unlock(&dbusMutex); + return T2ERROR_FAILURE; + } + + if (!t2dbus_handle.connection) { + T2Error("Failed to get D-Bus connection\n"); + pthread_mutex_unlock(&dbusMutex); + return T2ERROR_FAILURE; + } + T2Info("Connected to D-Bus system bus\n"); + int ret = dbus_bus_request_name(t2dbus_handle.connection, T2_DBUS_SERVICE_NAME, + DBUS_NAME_FLAG_REPLACE_EXISTING, &error); + if (dbus_error_is_set(&error)) { + T2Error("D-Bus name request error: %s\n", error.message); + dbus_error_free(&error); + dbus_connection_unref(t2dbus_handle.connection); + t2dbus_handle.connection = NULL; + pthread_mutex_unlock(&dbusMutex); + return T2ERROR_FAILURE; + } + + if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { + T2Error("Not primary owner of the name (ret=%d)\n", ret); + dbus_connection_unref(t2dbus_handle.connection); + t2dbus_handle.connection = NULL; + pthread_mutex_unlock(&dbusMutex); + return T2ERROR_FAILURE; + } + + T2Info("Acquired service name: %s\n", T2_DBUS_SERVICE_NAME); + /* Store unique name */ + t2dbus_handle.unique_name = strdup(dbus_bus_get_unique_name(t2dbus_handle.connection)); + + /* Register object path */ + DBusObjectPathVTable vtable = { + .message_function = message_handler, + .unregister_function = NULL + }; + + if (!dbus_connection_register_object_path(t2dbus_handle.connection, T2_DBUS_OBJECT_PATH, + &vtable, NULL)) { + T2Error("Failed to register object path\n"); + dbus_connection_unref(t2dbus_handle.connection); + return T2ERROR_FAILURE; + } + T2Info("Registered object path: %s\n", T2_DBUS_OBJECT_PATH); + //TODO check ready status based on component initialization + t2ReadyStatus = T2_STATE_COMPONENT_READY; + t2dbus_handle.is_initialized = true; + + /* Start listener thread */ + stopListenerThread = false; + if (pthread_create(&dbusListenerThread, NULL, dbusListenerThreadFunc, NULL) != 0) { + T2Error("Failed to create D-Bus listener thread\n"); + dBusInterface_Uninit(); + pthread_mutex_unlock(&dbusMutex); + return T2ERROR_FAILURE; + } + //TODO change to detached thread + + pthread_mutex_unlock(&dbusMutex); + + T2Info("D-Bus interface initialized successfully with name: %s\n", T2_DBUS_SERVICE_NAME); + T2Debug("%s --out\n", __FUNCTION__); + + return T2ERROR_SUCCESS; +} + +/** + * @brief Uninitialize D-Bus interface + */ +void dBusInterface_Uninit(void) { + T2Debug("%s ++in\n", __FUNCTION__); + + pthread_mutex_lock(&dbusMutex); + + if (!t2dbus_handle.is_initialized) { + pthread_mutex_unlock(&dbusMutex); + return; + } + + /* Stop listener thread */ + stopListenerThread = true; + pthread_mutex_unlock(&dbusMutex); + + if (dbusListenerThread) { + pthread_join(dbusListenerThread, NULL); + } + + pthread_mutex_lock(&dbusMutex); + + /* Clean up D-Bus connection */ + if (t2dbus_handle.connection) { + dbus_connection_unref(t2dbus_handle.connection); + t2dbus_handle.connection = NULL; + } + + if (t2dbus_handle.unique_name) { + free(t2dbus_handle.unique_name); + t2dbus_handle.unique_name = NULL; + } + + t2dbus_handle.is_initialized = false; + + pthread_mutex_unlock(&dbusMutex); + + T2Debug("%s --out\n", __FUNCTION__); +} + +/** + * @brief Get parameter value via D-Bus + */ +T2ERROR getDbusParameterVal(const char* paramName, char **paramValue) { + T2Debug("%s ++in\n", __FUNCTION__); + + if (!paramName || !paramValue) { + T2Error("Invalid parameters\n"); + return T2ERROR_INVALID_ARGS; + } + + if (!t2dbus_handle.is_initialized) { + if (dBusInterface_Init() != T2ERROR_SUCCESS) { + return T2ERROR_FAILURE; + } + } + + DBusMessage *msg = NULL; + DBusMessage *reply = NULL; + DBusError error; + dbus_error_init(&error); + + /* Create method call message */ + msg = dbus_message_new_method_call(T2_DBUS_SERVICE_NAME, + T2_DBUS_OBJECT_PATH, + T2_DBUS_INTERFACE_NAME, + T2_DBUS_METHOD_GET_PARAM); + if (!msg) { + T2Error("Failed to create D-Bus message\n"); + return T2ERROR_FAILURE; + } + + /* Append parameter name */ + if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, ¶mName, DBUS_TYPE_INVALID)) { + T2Error("Failed to append arguments\n"); + dbus_message_unref(msg); + return T2ERROR_FAILURE; + } + + /* Send message and get reply */ + reply = dbus_connection_send_with_reply_and_block(t2dbus_handle.connection, msg, + T2_DBUS_DEFAULT_TIMEOUT_MS, &error); + dbus_message_unref(msg); + + if (dbus_error_is_set(&error)) { + T2Error("D-Bus error: %s\n", error.message); + dbus_error_free(&error); + return T2ERROR_FAILURE; + } + + if (!reply) { + T2Error("No reply received\n"); + return T2ERROR_FAILURE; + } + + /* Parse reply */ + char *value = NULL; + if (dbus_message_get_args(reply, &error, + DBUS_TYPE_STRING, &value, + DBUS_TYPE_INVALID)) { + *paramValue = strdup(value); + T2Debug("Retrieved value: %s = %s\n", paramName, *paramValue); + } else { + T2Error("Failed to parse reply: %s\n", error.message); + dbus_error_free(&error); + dbus_message_unref(reply); + return T2ERROR_FAILURE; + } + + dbus_message_unref(reply); + + T2Debug("%s --out\n", __FUNCTION__); + return T2ERROR_SUCCESS; +} + +/** + * @brief Set parameter value via D-Bus + */ +T2ERROR setDbusParameterVal(const char* paramName, const char* paramValue, int paramType) { + T2Debug("%s ++in\n", __FUNCTION__); + + if (!paramName || !paramValue) { + T2Error("Invalid parameters\n"); + return T2ERROR_INVALID_ARGS; + } + + if (!t2dbus_handle.is_initialized) { + if (dBusInterface_Init() != T2ERROR_SUCCESS) { + return T2ERROR_FAILURE; + } + } + + DBusMessage *msg = NULL; + DBusMessage *reply = NULL; + DBusError error; + dbus_error_init(&error); + + /* Create method call message */ + msg = dbus_message_new_method_call(T2_DBUS_SERVICE_NAME, + T2_DBUS_OBJECT_PATH, + T2_DBUS_INTERFACE_NAME, + T2_DBUS_METHOD_SET_PARAM); + if (!msg) { + T2Error("Failed to create D-Bus message\n"); + return T2ERROR_FAILURE; + } + + /* Append arguments */ + if (!dbus_message_append_args(msg, + DBUS_TYPE_STRING, ¶mName, + DBUS_TYPE_STRING, ¶mValue, + DBUS_TYPE_INT32, ¶mType, + DBUS_TYPE_INVALID)) { + T2Error("Failed to append arguments\n"); + dbus_message_unref(msg); + return T2ERROR_FAILURE; + } + + /* Send message and get reply */ + reply = dbus_connection_send_with_reply_and_block(t2dbus_handle.connection, msg, + T2_DBUS_DEFAULT_TIMEOUT_MS, &error); + dbus_message_unref(msg); + + if (dbus_error_is_set(&error)) { + T2Error("D-Bus error: %s\n", error.message); + dbus_error_free(&error); + return T2ERROR_FAILURE; + } + + if (reply) { + dbus_message_unref(reply); + } + + T2Debug("%s --out\n", __FUNCTION__); + return T2ERROR_SUCCESS; +} + + +/** + * @brief Register for telemetry event notifications + */ +T2ERROR registerDbusT2EventListener(TelemetryEventCallback eventCB) { + T2Debug("%s ++in\n", __FUNCTION__); + + if (!eventCB) { + T2Error("Invalid callback\n"); + return T2ERROR_INVALID_ARGS; + } + + T2Info("Registering D-Bus telemetry event listener\n"); + eventCallBack = eventCB; + + T2Debug("%s --out\n", __FUNCTION__); + return T2ERROR_SUCCESS; +} + +/** + * @brief Unregister from telemetry event notifications + */ +T2ERROR unregisterDbusT2EventListener(void) { + T2Debug("%s ++in\n", __FUNCTION__); + + eventCallBack = NULL; + + T2Debug("%s --out\n", __FUNCTION__); + return T2ERROR_SUCCESS; +} + +T2ERROR registerDbusHandlerGetMarkerListCallback(T2EventMarkerListCallback callback) { + T2Debug("%s ++in\n", __FUNCTION__); + + if (!callback) { + T2Error("Invalid callback\n"); + return T2ERROR_INVALID_ARGS; + } + + getMarkerListCallBack = callback; + T2Info("Registered GetMarkerList callback\n"); + T2Debug("%s --out\n", __FUNCTION__); + + return T2ERROR_SUCCESS; +} diff --git a/source/ccspinterface/dbusInterface.h b/source/ccspinterface/dbusInterface.h new file mode 100755 index 00000000..21464610 --- /dev/null +++ b/source/ccspinterface/dbusInterface.h @@ -0,0 +1,91 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2026 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +/** + * @file dbusInterface.h + * @brief D-Bus Interface for Telemetry 2.0 + * + * This header provides D-Bus based inter-process communication APIs + * as an alternative to RBUS for the Telemetry 2.0 framework. + * + * Key Features: + * - Parameter get/set operations + * - Event publishing and subscription + * - Method invocation + * - Signal handling + */ + +#ifndef _DBUSINTERFACE_H_ +#define _DBUSINTERFACE_H_ + +#include +#include +#include +#include +#include "busInterface.h" +#include "telemetry2_0.h" + +/* D-Bus Service Information */ +#define T2_DBUS_SERVICE_NAME "telemetry.t2" +#define T2_DBUS_OBJECT_PATH "/telemetry/t2" +#define T2_DBUS_INTERFACE_NAME "telemetry.t2.interface" +#define T2_DBUS_EVENT_INTERFACE_NAME "telemetry.t2.event.interface" + +/* D-Bus Method Names */ +#define T2_DBUS_METHOD_GET_PARAM "GetParameter" +#define T2_DBUS_METHOD_SET_PARAM "SetParameter" + +/* D-Bus Signal Names */ +#define T2_DBUS_SIGNAL_PROFILE_UPDATE "ProfileUpdate" + +/* D-Bus Error Codes */ +#define T2_DBUS_ERROR_SUCCESS 0 +#define T2_DBUS_ERROR_FAILURE -1 +#define T2_DBUS_ERROR_OUT_OF_MEMORY -2 +#define T2_DBUS_ERROR_INVALID_PARAM -3 +#define T2_DBUS_ERROR_NOT_INITIALIZED -4 +#define T2_DBUS_ERROR_TIMEOUT -5 +#define T2_DBUS_ERROR_NO_ELEMENT -6 + +/* Timeout values */ +#define T2_DBUS_DEFAULT_TIMEOUT_MS 10000 /* 10 seconds */ +#define T2_DBUS_METHOD_TIMEOUT_MS 10000 /* 10 seconds */ + +typedef struct { + DBusConnection *connection; + char *unique_name; + bool is_initialized; +} T2DbusHandle_t; + +typedef void (*dbusMethodCallBackPtr)(DBusMessage *reply, int retStatus); + +bool isDbusInitialized(void); +T2ERROR dBusInterface_Init(void); +void dBusInterface_Uninit(void); + +T2ERROR getDbusParameterVal(const char* paramName, char **paramValue); +T2ERROR setDbusParameterVal(const char* paramName, const char* paramValue, int paramType); + +T2ERROR registerDbusT2EventListener(TelemetryEventCallback eventCB); +T2ERROR unregisterDbusT2EventListener(void); + +T2ERROR publishdbusEventsProfileUpdates(void); +T2ERROR registerDbusHandlerGetMarkerListCallback(T2EventMarkerListCallback callback); + +#endif /* _DBUSINTERFACE_H_ */ diff --git a/source/commonlib/Makefile.am b/source/commonlib/Makefile.am index c058b698..bdff690b 100644 --- a/source/commonlib/Makefile.am +++ b/source/commonlib/Makefile.am @@ -25,13 +25,12 @@ lib_LTLIBRARIES = libtelemetry_msgsender.la libtelemetry_msgsender_la_SOURCES = telemetry_busmessage_sender.c libtelemetry_msgsender_la_LDFLAGS = -shared -libtelemetry_msgsender_la_LIBADD = -lrbus ${top_builddir}/source/utils/libt2utils.la +libtelemetry_msgsender_la_LIBADD = -ldbus-1 ${top_builddir}/source/utils/libt2utils.la if ENABLE_CCSP_SUPPORT libtelemetry_msgsender_la_LIBADD += -lccsp_common endif -libtelemetry_msgsender_la_CPPFLAGS = -fPIC -I${PKG_CONFIG_SYSROOT_DIR}$(includedir)/dbus-1.0 \ - -I${PKG_CONFIG_SYSROOT_DIR}$(libdir)/dbus-1.0/include \ - -I${PKG_CONFIG_SYSROOT_DIR}$(includedir)/rbus \ +libtelemetry_msgsender_la_CPPFLAGS = -fPIC -I/usr/include/dbus-1.0 \ + -I/usr/lib/x86_64-linux-gnu/dbus-1.0/include \ -I${top_srcdir}/source/utils \ -I${top_srcdir}/include libtelemetry_msgsender_la_DEPENDENCIES = ${top_builddir}/source/utils/libt2utils.la @@ -39,14 +38,13 @@ libtelemetry_msgsender_la_DEPENDENCIES = ${top_builddir}/source/utils/libt2utils bin_PROGRAMS = telemetry2_0_client telemetry2_0_client_SOURCES = telemetry_client.c telemetry_busmessage_sender.c -telemetry2_0_client_LDADD = -lrbus ${top_builddir}/source/utils/libt2utils.la -lpthread +telemetry2_0_client_LDADD = -ldbus-1 ${top_builddir}/source/utils/libt2utils.la -lpthread if ENABLE_CCSP_SUPPORT telemetry2_0_client_LDADD += -lccsp_common endif -telemetry2_0_client_CPPFLAGS = -fPIC -I${PKG_CONFIG_SYSROOT_DIR}$(includedir)/dbus-1.0 \ - -I${PKG_CONFIG_SYSROOT_DIR}$(libdir)/dbus-1.0/include \ - -I${PKG_CONFIG_SYSROOT_DIR}$(includedir)/ccsp \ - -I${PKG_CONFIG_SYSROOT_DIR}$(includedir)/rbus \ +telemetry2_0_client_CPPFLAGS = -fPIC -I/usr/include/dbus-1.0 \ + -I/usr/lib/x86_64-linux-gnu/dbus-1.0/include \ + -I/usr/include/ccsp \ -I${top_srcdir}/source/utils \ -I${top_srcdir}/include telemetry2_0_client_DEPENDENCIES = ${top_builddir}/source/utils/libt2utils.la diff --git a/source/commonlib/telemetry_busmessage_sender.c b/source/commonlib/telemetry_busmessage_sender.c index c5d43127..2dad3ef8 100644 --- a/source/commonlib/telemetry_busmessage_sender.c +++ b/source/commonlib/telemetry_busmessage_sender.c @@ -32,7 +32,10 @@ #include #include #endif +#include +#if defined(RBUS_SUPPORT_ENABLED) #include +#endif #include "telemetry_busmessage_sender.h" @@ -48,14 +51,23 @@ #define T2_SCRIPT_EVENT_COMPONENT "telemetry_client" #define SENDER_LOG_FILE "/tmp/t2_sender_debug.log" +/* D-Bus Configuration */ +#define T2_DBUS_SERVICE_NAME "telemetry.t2" +#define T2_DBUS_OBJECT_PATH "/telemetry/t2" +#define T2_DBUS_INTERFACE_NAME "telemetry.t2.interface" +#define T2_DBUS_EVENT_INTERFACE_NAME "telemetry.t2.event.interface" + static const char* CCSP_FIXED_COMP_ID = "com.cisco.spvtg.ccsp.t2commonlib" ; static char *componentName = NULL; -static void *bus_handle = NULL; +static void *bus_handle = NULL; /* For method calls (main thread) */ +static void *signal_bus_handle = NULL; /* For signal listening (event thread) */ static bool isRFCT2Enable = false ; static bool isT2Ready = false; +#if defined(RBUS_SUPPORT_ENABLED) static bool isRbusEnabled = false ; -static int count = 0; +#endif +static bool isDbusEnabled = false ; static pthread_mutex_t initMtx = PTHREAD_MUTEX_INITIALIZER; static bool isMutexInitialized = false ; @@ -71,6 +83,10 @@ static pthread_mutex_t FileCacheMutex ; static pthread_mutex_t markerListMutex ; static pthread_mutex_t loggerMutex ; +// D-Bus event loop thread +static pthread_t dbus_event_thread; +static bool dbus_event_thread_running = false; + static void EVENT_DEBUG(char* format, ...) { @@ -85,13 +101,23 @@ static void EVENT_DEBUG(char* format, ...) logHandle = fopen(SENDER_LOG_FILE, "a+"); if(logHandle) { - time_t rawtime; - struct tm* timeinfo; + struct timespec ts; + struct tm timeinfo; - time(&rawtime); - timeinfo = localtime(&rawtime); - static char timeBuffer[20] = { '\0' }; - strftime(timeBuffer, sizeof(timeBuffer), "%Y-%m-%d %H:%M:%S", timeinfo); + if(clock_gettime(CLOCK_REALTIME, &ts) == -1) + { + fclose(logHandle); + pthread_mutex_unlock(&loggerMutex); + return; + } + + char timeBuffer[24] = { '\0' }; + long msecs; + + localtime_r(&ts.tv_sec, &timeinfo); + msecs = ts.tv_nsec / 1000000; + strftime(timeBuffer, sizeof(timeBuffer), "%Y-%m-%d %H:%M:%S", &timeinfo); + snprintf(timeBuffer + strlen(timeBuffer), sizeof(timeBuffer) - strlen(timeBuffer), ".%03ld", msecs); fprintf(logHandle, "%s : ", timeBuffer); va_list argList; va_start(argList, format); @@ -102,6 +128,23 @@ static void EVENT_DEBUG(char* format, ...) pthread_mutex_unlock(&loggerMutex); } +#if 0 +#define EVENT_DEBUG(format, ...) do { \ + struct timespec ts; \ + struct tm timeinfo; \ + char timeBuffer[32]; \ + if (clock_gettime(CLOCK_REALTIME, &ts) == 0) { \ + localtime_r(&ts.tv_sec, &timeinfo); \ + long msecs = ts.tv_nsec / 1000000; \ + strftime(timeBuffer, sizeof(timeBuffer), "%Y-%m-%d %H:%M:%S", &timeinfo); \ + snprintf(timeBuffer + strlen(timeBuffer), sizeof(timeBuffer) - strlen(timeBuffer), ".%03ld", msecs); \ + fprintf(stderr, "[%s] T2DEBUG:%s %s:%d: ", timeBuffer, __func__ , __FILE__, __LINE__ ); \ + } else { \ + fprintf(stderr, "T2DEBUG:%s %s:%d: ", __func__ , __FILE__, __LINE__ ); \ + } \ + fprintf(stderr, (format), ##__VA_ARGS__ ); \ +} while(0) +#endif static void initMutex() { @@ -187,21 +230,152 @@ static T2ERROR getCCSPParamVal(const char* paramName, char **paramValue) } #endif - +#if defined(RBUS_SUPPORT_ENABLED) static void rBusInterface_Uninit( ) { rbus_close(bus_handle); } +#endif + +static void dBusInterface_Uninit(void) +{ + if(isDbusEnabled) + { + // Stop D-Bus event loop thread + if (dbus_event_thread_running) + { + EVENT_DEBUG("D-Bus: Stopping event loop thread\n"); + dbus_event_thread_running = false; + // Thread is detached and will exit on its own - no need to wait + } + + // Flush all pending messages before closing connections + if (bus_handle) + { + EVENT_DEBUG("D-Bus: Flushing pending method call messages\n"); + dbus_connection_flush((DBusConnection*)bus_handle); + } + + if (signal_bus_handle) + { + EVENT_DEBUG("D-Bus: Flushing pending signal messages\n"); + dbus_connection_flush((DBusConnection*)signal_bus_handle); + dbus_connection_unref((DBusConnection*)signal_bus_handle); + signal_bus_handle = NULL; + } + + if (bus_handle) + { + dbus_connection_unref((DBusConnection*)bus_handle); + bus_handle = NULL; + } + + isDbusEnabled = false; + } +} + +static int dbus_checkStatus(void) +{ + // Check if D-Bus is available by attempting to connect + DBusError error; + dbus_error_init(&error); + DBusConnection *test_conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error); + + if (dbus_error_is_set(&error)) + { + dbus_error_free(&error); + return -1; // D-Bus not available + } + + if (test_conn) + { + dbus_connection_unref(test_conn); + isDbusEnabled = true; + return 0; // D-Bus available + } + + return -1; +} + +static T2ERROR dbus_getGetOperationalStatus(const char* paramName, uint32_t* value) +{ + if (!paramName || !value) + { + return T2ERROR_INVALID_ARGS; + } + + if (!bus_handle) + { + return T2ERROR_FAILURE; + } + + // D-Bus method call to get uint32 parameter + DBusMessage *msg = NULL; + DBusMessage *reply = NULL; + DBusError error; + dbus_error_init(&error); + + msg = dbus_message_new_method_call(T2_DBUS_SERVICE_NAME, + T2_DBUS_OBJECT_PATH, + T2_DBUS_INTERFACE_NAME, + "GetOperationalStatus"); + if (!msg) + { + EVENT_ERROR("%s:%d, D-Bus failed to create method call message\n", __func__, __LINE__); + return T2ERROR_FAILURE; + } + + if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, ¶mName, DBUS_TYPE_INVALID)) + { + dbus_message_unref(msg); + return T2ERROR_FAILURE; + } + + // Timeout: 10ms - GetOperationalStatus should respond quickly + // This prevents hanging if server is down/unresponsive + reply = dbus_connection_send_with_reply_and_block((DBusConnection*)bus_handle, msg, 10, &error); + dbus_message_unref(msg); + + if (dbus_error_is_set(&error)) + { + EVENT_ERROR("%s:%d, D-Bus error: %s\n", __func__, __LINE__, error.message); + dbus_error_free(&error); + return T2ERROR_FAILURE; + } + + if (!reply) + { + return T2ERROR_FAILURE; + } + + if (dbus_message_get_args(reply, &error, DBUS_TYPE_UINT32, value, DBUS_TYPE_INVALID)) + { + dbus_message_unref(reply); + EVENT_DEBUG("%s:%d, D-Bus got uint32 value: %u\n", __func__, __LINE__, *value); + return T2ERROR_SUCCESS; + } + else + { + if (dbus_error_is_set(&error)) + { + EVENT_ERROR("%s:%d, D-Bus error: %s\n", __func__, __LINE__, error.message); + dbus_error_free(&error); + } + dbus_message_unref(reply); + return T2ERROR_FAILURE; + } +} static T2ERROR initMessageBus( ) { - // EVENT_DEBUG("%s ++in\n", __FUNCTION__); + EVENT_DEBUG("%s ++in\n", __FUNCTION__); T2ERROR status = T2ERROR_SUCCESS; char* component_id = (char*)CCSP_FIXED_COMP_ID; #if defined(CCSP_SUPPORT_ENABLED) char *pCfg = (char*)CCSP_MSG_BUS_CFG; #endif +#if defined(RBUS_SUPPORT_ENABLED) if(RBUS_ENABLED == rbus_checkStatus()) { // EVENT_DEBUG("%s:%d, T2:rbus is enabled\n", __func__, __LINE__); @@ -223,6 +397,71 @@ static T2ERROR initMessageBus( ) } isRbusEnabled = true; } + else +#endif + if(0 == dbus_checkStatus()) + { + // D-Bus is available - initialize threading support first + if (!dbus_threads_init_default()) + { + EVENT_ERROR("%s:%d, Failed to initialize D-Bus threading\n", __func__, __LINE__); + return T2ERROR_FAILURE; + } + EVENT_DEBUG("%s:%d, D-Bus threading initialized\n", __func__, __LINE__); + + char dbusName[124] = { '\0' }; + char signalDbusName[124] = { '\0' }; + if(componentName) + { + snprintf(dbusName, 124, "telemetry.t2.lib_%s", componentName); + snprintf(signalDbusName, 124, "telemetry.t2.lib_%s_signals", componentName); + } + else + { + snprintf(dbusName, 124, "%s", component_id); + snprintf(signalDbusName, 124, "%s_signals", component_id); + } + + DBusError error; + dbus_error_init(&error); + + /* Initialize METHOD call connection */ + bus_handle = (void*)dbus_bus_get(DBUS_BUS_SYSTEM, &error); + + if (dbus_error_is_set(&error)) + { + EVENT_ERROR("%s:%d, D-Bus method call connection init failed: %s\n", __func__, __LINE__, error.message); + dbus_error_free(&error); + status = T2ERROR_FAILURE; + } + + /* Initialize SIGNAL connection separately */ + signal_bus_handle = (void*)dbus_bus_get(DBUS_BUS_SYSTEM, &error); + + if (dbus_error_is_set(&error)) + { + EVENT_ERROR("%s:%d, D-Bus signal connection init failed: %s\n", __func__, __LINE__, error.message); + dbus_error_free(&error); + /* Continue without signal support */ + signal_bus_handle = NULL; + } + + if (signal_bus_handle && bus_handle) + { + status = T2ERROR_SUCCESS; + EVENT_DEBUG("%s:%d, D-Bus initialized successfully with separate connections\n", __func__, __LINE__); + } + else + { + EVENT_ERROR("%s:%d, D-Bus initialization failed\n", __func__, __LINE__); + status = T2ERROR_FAILURE; + } + } + else + { + EVENT_ERROR("%s:%d, T2:No supported dbus available\n", __func__, __LINE__); + status = T2ERROR_FAILURE; + } #if defined(CCSP_SUPPORT_ENABLED) else { @@ -239,10 +478,11 @@ static T2ERROR initMessageBus( ) } } #endif // CCSP_SUPPORT_ENABLED - // EVENT_DEBUG("%s --out\n", __FUNCTION__); + EVENT_DEBUG("%s --out\n", __FUNCTION__); return status; } +#if defined(RBUS_SUPPORT_ENABLED) static T2ERROR getRbusParameterVal(const char* paramName, char **paramValue) { @@ -287,19 +527,29 @@ static T2ERROR getRbusParameterVal(const char* paramName, char **paramValue) return T2ERROR_SUCCESS; } +#endif T2ERROR getParamValue(const char* paramName, char **paramValue) { T2ERROR ret = T2ERROR_FAILURE ; +#if defined(RBUS_SUPPORT_ENABLED) if(isRbusEnabled) { ret = getRbusParameterVal(paramName, paramValue); } -#if defined(CCSP_SUPPORT_ENABLED) else +#endif +#if defined(CCSP_SUPPORT_ENABLED) { ret = getCCSPParamVal(paramName, paramValue); } +#else + { + // D-Bus mode - not implemented for parameter get + (void)paramName; + (void)paramValue; + ret = T2ERROR_FAILURE; + } #endif return ret; @@ -316,8 +566,9 @@ void *cacheEventToFile(void *arg) fl.l_len = 0; fl.l_pid = 0; FILE *fs = NULL; - char path[100]; pthread_detach(pthread_self()); + int ch; + int count = 0; EVENT_ERROR("%s:%d, Caching the event to File\n", __func__, __LINE__); if(telemetry_data == NULL) { @@ -353,12 +604,25 @@ void *cacheEventToFile(void *arg) EVENT_ERROR("%s: File open error %s\n", __FUNCTION__, T2_CACHE_FILE); goto unlock; } - fs = popen ("cat /tmp/t2_caching_file | wc -l", "r"); - if(fs != NULL) + + fs = fopen(T2_CACHE_FILE, "r"); + if (fs != NULL) { - fgets(path, 100, fs); - count = atoi ( path ); - pclose(fs); + while ((ch = fgetc(fs)) != EOF) + { + if (ch == '\n') + { + count++; + } + } + + //If the file is not empty and does not contain a newline, call it one line + if (count == 0 && ftell(fs) > 0) + { + count++; + } + fclose(fs); + fs = NULL; } if(count < MAX_EVENT_CACHE) { @@ -391,15 +655,18 @@ static bool initRFC( ) { bool status = true ; // Check for RFC and proceed - if true - else return now . - if(!bus_handle) + //TODO: Implement RFC check here + if(!bus_handle && !signal_bus_handle) { + EVENT_DEBUG("%s:%d, T2: Initializing Message Bus\n", __func__, __LINE__); if(initMessageBus() != 0) { EVENT_ERROR("initMessageBus failed\n"); - status = false ; + status = false; } else { + EVENT_DEBUG("initMessageBus successful\n"); status = true; } isRFCT2Enable = true; @@ -414,15 +681,15 @@ static bool initRFC( ) */ int filtered_event_send(const char* data, const char *markerName) { - rbusError_t ret = RBUS_ERROR_SUCCESS; int status = 0 ; EVENT_DEBUG("%s ++in\n", __FUNCTION__); if(!bus_handle) { EVENT_ERROR("bus_handle is null .. exiting !!! \n"); - return ret; + return status; } +#if defined(RBUS_SUPPORT_ENABLED) if(isRbusEnabled) { @@ -484,6 +751,114 @@ int filtered_event_send(const char* data, const char *markerName) rbusValue_Release(objVal); } + else +#endif + if(isDbusEnabled && bus_handle) + { + // Filter data from marker list + if(componentName && (0 != strcmp(componentName, T2_SCRIPT_EVENT_COMPONENT))) // Events from scripts needs to be sent without filtering + { + EVENT_DEBUG("markerListMutex lock & component %s , marker %s\n", componentName, markerName); + pthread_mutex_lock(&markerListMutex); + bool isEventingEnabled = false; + if(markerName && eventMarkerMap) + { + if(hash_map_get(eventMarkerMap, markerName)) + { + isEventingEnabled = true; + } + } + else + { + EVENT_DEBUG("eventMarkerMap for component %s is empty \n", componentName ); + } + EVENT_DEBUG("%s markerListMutex unlock\n", __FUNCTION__ ); + pthread_mutex_unlock(&markerListMutex); + if(!isEventingEnabled) + { + EVENT_DEBUG("markerName %s not found in event list for component %s \n", markerName, componentName); + return status; + } + } + + // D-Bus method call to send event + DBusMessage *msg = NULL; + DBusMessage *reply = NULL; + DBusError error; + dbus_error_init(&error); + + msg = dbus_message_new_method_call(T2_DBUS_SERVICE_NAME, + T2_DBUS_OBJECT_PATH, + T2_DBUS_INTERFACE_NAME, + "SendT2Event"); + if (!msg) + { + EVENT_ERROR("Failed to create D-Bus method call message\n"); + status = -1; + } + else + { + if (!dbus_message_append_args(msg, + DBUS_TYPE_STRING, &markerName, + DBUS_TYPE_STRING, &data, + DBUS_TYPE_INVALID)) + { + EVENT_ERROR("Failed to append D-Bus method call arguments\n"); + dbus_message_unref(msg); + status = -1; + } + else + { + // Send method call and wait for reply with timeout (10 ms) + reply = dbus_connection_send_with_reply_and_block((DBusConnection*)bus_handle, msg, 10, &error); + dbus_message_unref(msg); + + if (dbus_error_is_set(&error)) + { + EVENT_ERROR("D-Bus method call failed: %s\n", error.message); + dbus_error_free(&error); + status = -1; + } + else if (!reply) + { + EVENT_ERROR("No reply received from SendT2Event\n"); + status = -1; + } + else + { + // Parse boolean success status from reply + dbus_bool_t success = FALSE; + if (dbus_message_get_args(reply, &error, + DBUS_TYPE_BOOLEAN, &success, + DBUS_TYPE_INVALID)) + { + if (success) + { + EVENT_DEBUG("SendT2Event succeeded for marker [%s] with data [%s]\n", markerName, data); + status = 0; + } + else + { + EVENT_ERROR("SendT2Event returned failure for marker [%s]\n", markerName); + status = -1; + } + } + else + { + EVENT_ERROR("Failed to parse reply: %s\n", error.message); + dbus_error_free(&error); + status = -1; + } + dbus_message_unref(reply); + } + } + } + } + else + { + EVENT_ERROR("No supported bus available for sending event\n"); + status = -1 ; + } #if defined(CCSP_SUPPORT_ENABLED) else { @@ -492,7 +867,7 @@ int filtered_event_send(const char* data, const char *markerName) if(buffer) { snprintf(buffer, eventDataLen, "%s%s%s", markerName, MESSAGE_DELIMITER, data); - ret = CcspBaseIf_SendTelemetryDataSignal(bus_handle, buffer); + int ret = CcspBaseIf_SendTelemetryDataSignal(bus_handle, buffer); if(ret != CCSP_SUCCESS) { status = -1; @@ -517,85 +892,209 @@ int filtered_event_send(const char* data, const char *markerName) static T2ERROR doPopulateEventMarkerList( ) { - T2ERROR status = T2ERROR_SUCCESS; +#if defined(RBUS_SUPPORT_ENABLED) char deNameSpace[1][124] = {{ '\0' }}; if(!isRbusEnabled) { - return T2ERROR_SUCCESS; + // Fall through to D-Bus implementation } + else + { + EVENT_DEBUG("%s ++in\n", __FUNCTION__); + rbusError_t ret = RBUS_ERROR_SUCCESS; + rbusValue_t paramValue_t; - EVENT_DEBUG("%s ++in\n", __FUNCTION__); - rbusError_t ret = RBUS_ERROR_SUCCESS; - rbusValue_t paramValue_t; + if(!bus_handle && T2ERROR_SUCCESS != initMessageBus()) + { + EVENT_ERROR("Unable to get message bus handles \n"); + EVENT_DEBUG("%s --out\n", __FUNCTION__); + return T2ERROR_FAILURE; + } - if(!bus_handle && T2ERROR_SUCCESS != initMessageBus()) - { - EVENT_ERROR("Unable to get message bus handles \n"); - EVENT_DEBUG("%s --out\n", __FUNCTION__); - return T2ERROR_FAILURE; - } + snprintf(deNameSpace[0], 124, "%s%s%s", T2_ROOT_PARAMETER, componentName, T2_EVENT_LIST_PARAM_SUFFIX); + EVENT_DEBUG("rbus mode : Query marker list with data element = %s \n", deNameSpace[0]); - snprintf(deNameSpace[0], 124, "%s%s%s", T2_ROOT_PARAMETER, componentName, T2_EVENT_LIST_PARAM_SUFFIX); - EVENT_DEBUG("rbus mode : Query marker list with data element = %s \n", deNameSpace[0]); + pthread_mutex_lock(&markerListMutex); + EVENT_DEBUG("Lock markerListMutex & Clean up eventMarkerMap \n"); + if(eventMarkerMap != NULL) + { + hash_map_destroy(eventMarkerMap, free); + eventMarkerMap = NULL; + } - pthread_mutex_lock(&markerListMutex); - EVENT_DEBUG("Lock markerListMutex & Clean up eventMarkerMap \n"); - if(eventMarkerMap != NULL) - { - hash_map_destroy(eventMarkerMap, free); - eventMarkerMap = NULL; - } + ret = rbus_get(bus_handle, deNameSpace[0], ¶mValue_t); + if(ret != RBUS_ERROR_SUCCESS) + { + EVENT_ERROR("rbus mode : No event list configured in profiles %s and return value %d\n", deNameSpace[0], ret); + pthread_mutex_unlock(&markerListMutex); + EVENT_DEBUG("rbus mode : No event list configured in profiles %s and return value %d. Unlock markerListMutex\n", deNameSpace[0], ret); + EVENT_DEBUG("%s --out\n", __FUNCTION__); + return T2ERROR_SUCCESS; + } - ret = rbus_get(bus_handle, deNameSpace[0], ¶mValue_t); - if(ret != RBUS_ERROR_SUCCESS) - { - EVENT_ERROR("rbus mode : No event list configured in profiles %s and return value %d\n", deNameSpace[0], ret); - pthread_mutex_unlock(&markerListMutex); - EVENT_DEBUG("rbus mode : No event list configured in profiles %s and return value %d. Unlock markerListMutex\n", deNameSpace[0], ret); - EVENT_DEBUG("%s --out\n", __FUNCTION__); - return T2ERROR_SUCCESS; - } + rbusValueType_t type_t = rbusValue_GetType(paramValue_t); + if(type_t != RBUS_OBJECT) + { + EVENT_ERROR("rbus mode : Unexpected data object received for %s get query \n", deNameSpace[0]); + rbusValue_Release(paramValue_t); + pthread_mutex_unlock(&markerListMutex); + EVENT_DEBUG("Unlock markerListMutex\n"); + EVENT_DEBUG("%s --out\n", __FUNCTION__); + return T2ERROR_FAILURE; + } - rbusValueType_t type_t = rbusValue_GetType(paramValue_t); - if(type_t != RBUS_OBJECT) - { - EVENT_ERROR("rbus mode : Unexpected data object received for %s get query \n", deNameSpace[0]); - rbusValue_Release(paramValue_t); - pthread_mutex_unlock(&markerListMutex); + rbusObject_t objectValue = rbusValue_GetObject(paramValue_t); + if(objectValue) + { + eventMarkerMap = hash_map_create(); + rbusProperty_t rbusPropertyList = rbusObject_GetProperties(objectValue); + EVENT_DEBUG("\t rbus mode : Update event map for component %s with below events : \n", componentName); + while(NULL != rbusPropertyList) + { + const char* eventname = rbusProperty_GetName(rbusPropertyList); + if(eventname && strlen(eventname) > 0) + { + EVENT_DEBUG("\t %s\n", eventname); + hash_map_put(eventMarkerMap, (void*) strdup(eventname), (void*) strdup(eventname), free); + } + rbusPropertyList = rbusProperty_GetNext(rbusPropertyList); + } + } + else + { + EVENT_ERROR("rbus mode : No configured event markers for %s \n", componentName); + } EVENT_DEBUG("Unlock markerListMutex\n"); + pthread_mutex_unlock(&markerListMutex); + rbusValue_Release(paramValue_t); EVENT_DEBUG("%s --out\n", __FUNCTION__); - return T2ERROR_FAILURE; + return status; } +#endif - rbusObject_t objectValue = rbusValue_GetObject(paramValue_t); - if(objectValue) + // D-Bus implementation + if(isDbusEnabled && bus_handle) { - eventMarkerMap = hash_map_create(); - rbusProperty_t rbusPropertyList = rbusObject_GetProperties(objectValue); - EVENT_DEBUG("\t rbus mode : Update event map for component %s with below events : \n", componentName); - while(NULL != rbusPropertyList) + EVENT_DEBUG("%s ++in \n", __FUNCTION__); + + if(!bus_handle && T2ERROR_SUCCESS != initMessageBus()) + { + EVENT_ERROR("Unable to get message bus handles \n"); + EVENT_DEBUG("%s --out\n", __FUNCTION__); + return T2ERROR_FAILURE; + } + + pthread_mutex_lock(&markerListMutex); + EVENT_DEBUG("Lock markerListMutex & Clean up eventMarkerMap \n"); + if(eventMarkerMap != NULL) { - const char* eventname = rbusProperty_GetName(rbusPropertyList); - if(eventname && strlen(eventname) > 0) + hash_map_destroy(eventMarkerMap, free); + eventMarkerMap = NULL; + } + + // Get marker list via D-Bus method call + DBusMessage *msg = NULL; + DBusMessage *reply = NULL; + DBusError error; + dbus_error_init(&error); + + msg = dbus_message_new_method_call(T2_DBUS_SERVICE_NAME, + T2_DBUS_OBJECT_PATH, + T2_DBUS_INTERFACE_NAME, + "GetMarkerList"); + if (!msg) + { + EVENT_ERROR("D-Bus mode: Failed to create method call message\n"); + pthread_mutex_unlock(&markerListMutex); + return T2ERROR_FAILURE; + } + + if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &componentName, DBUS_TYPE_INVALID)) + { + EVENT_ERROR("D-Bus mode: Failed to append arguments\n"); + dbus_message_unref(msg); + pthread_mutex_unlock(&markerListMutex); + return T2ERROR_FAILURE; + } + // TODO : check markers list size and set timeout accordingly + // Timeout: 10ms + reply = dbus_connection_send_with_reply_and_block((DBusConnection*)bus_handle, msg, 10, &error); + dbus_message_unref(msg); + + if (dbus_error_is_set(&error)) + { + EVENT_ERROR("D-Bus mode: Method call failed: %s\n", error.message); + dbus_error_free(&error); + pthread_mutex_unlock(&markerListMutex); + EVENT_DEBUG("D-Bus mode: No event list configured. Unlock markerListMutex\n"); + return T2ERROR_SUCCESS; + } + + if (!reply) + { + EVENT_ERROR("D-Bus mode: No reply received\n"); + pthread_mutex_unlock(&markerListMutex); + return T2ERROR_SUCCESS; + } + + // Parse reply - expecting a string containing comma-separated marker list + char *markerListStr = NULL; + if (dbus_message_get_args(reply, &error, + DBUS_TYPE_STRING, &markerListStr, + DBUS_TYPE_INVALID)) + { + if(markerListStr && strlen(markerListStr) > 0) { - EVENT_DEBUG("\t %s\n", eventname); - hash_map_put(eventMarkerMap, (void*) strdup(eventname), (void*) strdup(eventname), free); + eventMarkerMap = hash_map_create(); + EVENT_DEBUG("Update event map for component %s with below events :\n", componentName); + + char* markerListCopy = strdup(markerListStr); + char* token = strtok(markerListCopy, ","); + while(token != NULL) + { + // Trim whitespace + while(*token == ' ' || *token == '\t') token++; + char* end = token + strlen(token) - 1; + while(end > token && (*end == ' ' || *end == '\t' || *end == '\n')) { + *end = '\0'; + end--; + } + + if(strlen(token) > 0) + { + EVENT_DEBUG("\t %s\n", token); + hash_map_put(eventMarkerMap, (void*)strdup(token), (void*)strdup(token), free); + } + token = strtok(NULL, ","); + } + free(markerListCopy); } - rbusPropertyList = rbusProperty_GetNext(rbusPropertyList); + else + { + EVENT_ERROR("D-Bus mode: No configured event markers for %s\n", componentName); + } + } + else + { + EVENT_ERROR("D-Bus mode: Failed to parse reply: %s\n", error.message); + dbus_error_free(&error); } + + dbus_message_unref(reply); + EVENT_DEBUG("Unlock markerListMutex\n"); + pthread_mutex_unlock(&markerListMutex); + EVENT_DEBUG("%s --out\n", __FUNCTION__); + return T2ERROR_SUCCESS; } else { - EVENT_ERROR("rbus mode : No configured event markers for %s \n", componentName); + EVENT_ERROR("No dbus supported message bus available\n"); } - EVENT_DEBUG("Unlock markerListMutex\n"); - pthread_mutex_unlock(&markerListMutex); - rbusValue_Release(paramValue_t); - EVENT_DEBUG("%s --out\n", __FUNCTION__); - return status; + return T2ERROR_FAILURE; } +#if defined(RBUS_SUPPORT_ENABLED) static void rbusEventReceiveHandler(rbusHandle_t handle, rbusEvent_t const* event, rbusEventSubscription_t* subscription) { (void)handle;//To fix compiler warning. @@ -613,6 +1112,49 @@ static void rbusEventReceiveHandler(rbusHandle_t handle, rbusEvent_t const* even EVENT_ERROR("eventName is null \n"); } } +#endif + +static DBusHandlerResult dbusEventReceiveHandler(DBusConnection *connection, DBusMessage *message, void *user_data) +{ + (void)connection; + (void)user_data; + + if (dbus_message_is_signal(message, T2_DBUS_EVENT_INTERFACE_NAME, "ProfileUpdate")) + { + EVENT_DEBUG("D-Bus: *** ProfileUpdate signal RECEIVED - updating marker list ***\n"); + doPopulateEventMarkerList(); + return DBUS_HANDLER_RESULT_HANDLED; + } + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +// D-Bus event loop thread function - processes BOTH connections +static void* dbus_event_loop_thread(void *arg) +{ + (void)arg; + + if (!signal_bus_handle || !bus_handle) + { + EVENT_ERROR("Signal bus handle is NULL\n"); + return NULL; + } + + EVENT_DEBUG("D-Bus: Event loop thread started (processing both connections)\n"); + + while (dbus_event_thread_running) + { + // Process signal connection (for ProfileUpdate signals) + dbus_connection_read_write_dispatch((DBusConnection*)signal_bus_handle, 0); + dbus_connection_read_write_dispatch((DBusConnection*)bus_handle, 0); + + // Small sleep to avoid busy-waiting + usleep(1); // 1us + } + + EVENT_DEBUG("D-Bus: Event loop thread exiting\n"); + return NULL; +} static bool isCachingRequired( ) { @@ -642,30 +1184,52 @@ static bool isCachingRequired( ) // Always check for t2 is ready to accept events. Shutdown target can bring down t2 process at runtime uint32_t t2ReadyStatus; - rbusError_t retVal = RBUS_ERROR_SUCCESS; + T2ERROR retVal = T2ERROR_FAILURE; - retVal = rbus_getUint(bus_handle, T2_OPERATIONAL_STATUS, &t2ReadyStatus); +#if defined(RBUS_SUPPORT_ENABLED) + if(isRbusEnabled) + { + rbusError_t rbusRetVal = rbus_getUint(bus_handle, T2_OPERATIONAL_STATUS, &t2ReadyStatus); + retVal = (rbusRetVal == RBUS_ERROR_SUCCESS) ? T2ERROR_SUCCESS : T2ERROR_FAILURE; + } + else +#endif + if(isDbusEnabled && bus_handle) + { + retVal = dbus_getGetOperationalStatus(T2_OPERATIONAL_STATUS, &t2ReadyStatus); + // retVal = T2ERROR_SUCCESS; // Temporarily bypass D-Bus get for operational status + // t2ReadyStatus = T2_STATE_COMPONENT_READY; // Assume ready for now + EVENT_DEBUG("%s:%d, D-Bus t2ReadyStatus: %u\n", __func__, __LINE__, t2ReadyStatus); + } - if(retVal != RBUS_ERROR_SUCCESS) + if(retVal != T2ERROR_SUCCESS) { + EVENT_ERROR("Unable to get %s\n", T2_OPERATIONAL_STATUS); return true; } else { EVENT_DEBUG("value for %s is : %d\n", T2_OPERATIONAL_STATUS, t2ReadyStatus); - if((t2ReadyStatus & T2_STATE_COMPONENT_READY) == 0) + if((t2ReadyStatus & T2_STATE_READY) == 0) { return true; } } +#if defined(RBUS_SUPPORT_ENABLED) if(!isRbusEnabled) + { + // Fall through to D-Bus handling + } + else { isT2Ready = true; } +#endif if(!isT2Ready) { + EVENT_DEBUG("T2 is not ready yet, subscribe to profile update event/signals \n"); if(componentName && (0 != strcmp(componentName, "telemetry_client"))) { // From other binary applications in rbus mode if t2 daemon is yet to determine state of component specific config from cloud, enable cache @@ -675,15 +1239,64 @@ static bool isCachingRequired( ) } else { - rbusError_t ret = RBUS_ERROR_SUCCESS; - doPopulateEventMarkerList(); - ret = rbusEvent_Subscribe(bus_handle, T2_PROFILE_UPDATED_NOTIFY, rbusEventReceiveHandler, "T2Event", 0); - if(ret != RBUS_ERROR_SUCCESS) +#if defined(RBUS_SUPPORT_ENABLED) + if(isRbusEnabled) + { + rbusError_t ret = RBUS_ERROR_SUCCESS; + doPopulateEventMarkerList(); + ret = rbusEvent_Subscribe(bus_handle, T2_PROFILE_UPDATED_NOTIFY, rbusEventReceiveHandler, "T2Event", 0); + if(ret != RBUS_ERROR_SUCCESS) + { + EVENT_ERROR("Unable to subscribe to event %s with rbus error code : %d\n", T2_PROFILE_UPDATED_NOTIFY, ret); + EVENT_DEBUG("Unable to subscribe to event %s with rbus error code : %d\n", T2_PROFILE_UPDATED_NOTIFY, ret); + } + isT2Ready = true; + } + else +#endif + if(isDbusEnabled && signal_bus_handle) { - EVENT_ERROR("Unable to subscribe to event %s with rbus error code : %d\n", T2_PROFILE_UPDATED_NOTIFY, ret); - EVENT_DEBUG("Unable to subscribe to event %s with rbus error code : %d\n", T2_PROFILE_UPDATED_NOTIFY, ret); + EVENT_DEBUG("D-Bus: Starting ProfileUpdate signal subscription setup\n"); + doPopulateEventMarkerList(); + + // Subscribe to D-Bus ProfileUpdate signal using SIGNAL connection + char rule[512]; + DBusError error; + dbus_error_init(&error); + + snprintf(rule, sizeof(rule), + "type='signal',path='%s',interface='%s',member='ProfileUpdate'", + T2_DBUS_OBJECT_PATH, T2_DBUS_EVENT_INTERFACE_NAME); + + dbus_bus_add_match((DBusConnection*)signal_bus_handle, rule, &error); + + if (dbus_error_is_set(&error)) + { + EVENT_ERROR("Unable to subscribe to ProfileUpdate signal: %s\n", error.message); + dbus_error_free(&error); + } + else + { + dbus_connection_add_filter((DBusConnection*)signal_bus_handle, dbusEventReceiveHandler, NULL, NULL); + EVENT_DEBUG("Now listening for ProfileUpdate signals on interface '%s'\n", T2_DBUS_EVENT_INTERFACE_NAME); + + // Start D-Bus event loop thread to process incoming signals + if (!dbus_event_thread_running) + { + dbus_event_thread_running = true; + if (pthread_create(&dbus_event_thread, NULL, dbus_event_loop_thread, NULL) == 0) + { + pthread_detach(dbus_event_thread); + } + else + { + EVENT_ERROR("D-Bus: Failed to create event loop thread\n"); + dbus_event_thread_running = false; + } + } + } + isT2Ready = true; } - isT2Ready = true; } } else @@ -744,10 +1357,17 @@ void t2_uninit(void) componentName = NULL ; } +#if defined(RBUS_SUPPORT_ENABLED) if(isRbusEnabled) { rBusInterface_Uninit(); } + else +#endif + if(isDbusEnabled) + { + dBusInterface_Uninit(); + } uninitMutex(); } diff --git a/source/commonlib/telemetry_client.c b/source/commonlib/telemetry_client.c index 4acd5040..19460498 100644 --- a/source/commonlib/telemetry_client.c +++ b/source/commonlib/telemetry_client.c @@ -18,6 +18,9 @@ */ #include +#include +#include +#include #include #define COMP_NAME "telemetry_client" @@ -32,3 +35,98 @@ int main(int argc, char *argv[]) return 0; } + +#if 0 +int main(int argc, char *argv[]) +{ + int i = 0, n; + n = (argc < 2) ? 100 : atoi(argv[1]); + // Initialize Telemetry2.0 + t2_init("telemetry_client"); + + while(i <= n) + { + t2_event_d("T2_INFO_Test", i); + i++; + } + t2_uninit(); + printf("Sent %d t2_event_d events.\n", n); + return 0; +} +#endif +#if 0 +// Thread argument structure +typedef struct { + int value; +} thread_arg_t; + +// Thread function that sends telemetry event +void* send_event_thread(void* arg) +{ + thread_arg_t* t_arg = (thread_arg_t*)arg; + int value = t_arg->value; + free(t_arg); + + printf("Thread %ld: Sending T2_INFO_Test=%d\n", (long)pthread_self(), value); + t2_event_d("T2_INFO_Test", value); + printf("Thread %ld: Event sent successfully\n", (long)pthread_self()); + + return NULL; +} + +int main(int argc, char *argv[]) +{ + int i = 0, n; + n = (argc < 2) ? 100 : atoi(argv[1]); + + // Initialize Telemetry2.0 + t2_init("telemetry_client"); + + printf("Starting multi-threaded telemetry test with %d events\n", n); + printf("Each event will be sent from a separate thread\n\n"); + + // Array to store thread IDs + pthread_t* threads = (pthread_t*)malloc((n + 1) * sizeof(pthread_t)); + if (!threads) { + printf("Failed to allocate memory for threads\n"); + t2_uninit(); + return 1; + } + + // Create a thread for each event + while(i <= n) + { + thread_arg_t* arg = (thread_arg_t*)malloc(sizeof(thread_arg_t)); + if (!arg) { + printf("Failed to allocate memory for thread argument\n"); + break; + } + arg->value = i; + + if (pthread_create(&threads[i], NULL, send_event_thread, (void*)arg) != 0) { + printf("Failed to create thread %d\n", i); + free(arg); + break; + } + + i++; + usleep(100); + } + printf("\nAll %d threads created, waiting for completion...\n\n", i); + + // Wait for all threads to complete + for (int j = 0; j < i; j++) { + pthread_join(threads[j], NULL); + } + + free(threads); + + printf("\n===========================================\n"); + printf("All threads completed!\n"); + printf("Sent %d t2_event_d events from %d threads.\n", i, i); + printf("===========================================\n"); + + t2_uninit(); + return 0; +} +#endif \ No newline at end of file diff --git a/source/utils/t2log_wrapper.c b/source/utils/t2log_wrapper.c index d433e149..1aa851fe 100644 --- a/source/utils/t2log_wrapper.c +++ b/source/utils/t2log_wrapper.c @@ -1,3 +1,5 @@ + + /* * If not stated otherwise in this file or this component's LICENSE file the * following copyright and licenses apply: @@ -24,6 +26,8 @@ #include #include #include +#include +#include #ifdef GTEST_ENABLE #include "test/rdk_logger/include/rdk_debug.h" #else @@ -42,6 +46,7 @@ void LOGInit() } +#if 1 void T2Log(unsigned int level, const char *msg, ...) { va_list arg; @@ -92,3 +97,103 @@ void T2Log(unsigned int level, const char *msg, ...) free(pTempChar); } } +#endif +#if 0 + +static pthread_mutex_t loggerMutex = PTHREAD_MUTEX_INITIALIZER; + +/* Convert log level to string */ +static const char* getLogLevelString(unsigned int level) +{ + switch(level) + { + case RDK_LOG_FATAL: return "FATAL"; + case RDK_LOG_ERROR: return "ERROR"; + case RDK_LOG_WARN: return "WARN"; + case RDK_LOG_NOTICE: return "NOTICE"; + case RDK_LOG_INFO: return "INFO"; + case RDK_LOG_DEBUG: return "DEBUG"; + default: return "UNKNOWN"; + } +} + +void T2Log(unsigned int level, const char *msg, ...) +{ + va_list arg; + char *pTempChar = NULL; + int ret = 0; + FILE *logHandle = NULL; + + if (NULL == msg) + { + return; + } + + /* Check if debug logging is enabled for RDK_LOG_DEBUG (level 5) */ + if (level == RDK_LOG_DEBUG) + { + if (access(ENABLE_DEBUG_FLAG, F_OK) == -1) + { + return; + } + } + + /* Compose the log message */ + va_start(arg, msg); + int messageLen = vsnprintf(NULL, 0, msg, arg); + va_end(arg); + + if (messageLen < 1) + { + return; + } + + messageLen++; + pTempChar = (char *)malloc(messageLen); + if (!pTempChar) + { + return; + } + + memset(pTempChar, '\0', messageLen); + va_start(arg, msg); + ret = vsnprintf(pTempChar, messageLen, msg, arg); + va_end(arg); + + if (ret < 0) + { + free(pTempChar); + return; + } + + /* Write to log file with timestamp */ + pthread_mutex_lock(&loggerMutex); + logHandle = fopen("/opt/logs/t2.log", "a+"); + if (logHandle) + { + struct timespec ts; + struct tm timeinfo; + + if (clock_gettime(CLOCK_REALTIME, &ts) == -1) + { + fclose(logHandle); + pthread_mutex_unlock(&loggerMutex); + free(pTempChar); + return; + } + + char timeBuffer[24] = { '\0' }; + long msecs; + + localtime_r(&ts.tv_sec, &timeinfo); + msecs = ts.tv_nsec / 1000000; + strftime(timeBuffer, sizeof(timeBuffer), "%Y-%m-%d %H:%M:%S", &timeinfo); + snprintf(timeBuffer + strlen(timeBuffer), sizeof(timeBuffer) - strlen(timeBuffer), ".%03ld", msecs); + fprintf(logHandle, "%s [%s] : %s", timeBuffer, getLogLevelString(level), pTempChar); + fclose(logHandle); + } + pthread_mutex_unlock(&loggerMutex); + + free(pTempChar); +} +#endif \ No newline at end of file