From 2dd698cc32b4eb16627bddca459478bb0a196afb Mon Sep 17 00:00:00 2001 From: Rainer Poisel Date: Thu, 22 Dec 2016 19:39:15 +0000 Subject: [PATCH 1/6] Allow usage of alternative log facilities --- configure.ac | 2 +- src/Makefile.am | 4 ++- src/modbus-log.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++ src/modbus-log.h | 19 +++++++++++++++ src/modbus-rtu.c | 48 ++++++++++++++++++------------------ src/modbus-tcp.c | 34 +++++++++++++------------- src/modbus.c | 48 ++++++++++++++++++------------------ src/modbus.h | 2 ++ 8 files changed, 153 insertions(+), 67 deletions(-) create mode 100644 src/modbus-log.c create mode 100644 src/modbus-log.h diff --git a/configure.ac b/configure.ac index a568e479f..009e78ebe 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ # m4_define([libmodbus_version_major], [3]) m4_define([libmodbus_version_minor], [1]) -m4_define([libmodbus_version_micro], [4]) +m4_define([libmodbus_version_micro], [5]) m4_define([libmodbus_release_status], [m4_if(m4_eval(libmodbus_version_minor % 2), [1], [snapshot], [release])]) diff --git a/src/Makefile.am b/src/Makefile.am index 551fe4328..7eda6ba85 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -14,6 +14,8 @@ libmodbus_la_SOURCES = \ modbus.h \ modbus-data.c \ modbus-private.h \ + modbus-log.c \ + modbus-log.h \ modbus-rtu.c \ modbus-rtu.h \ modbus-rtu-private.h \ @@ -35,7 +37,7 @@ endif # Header files to install libmodbusincludedir = $(includedir)/modbus -libmodbusinclude_HEADERS = modbus.h modbus-version.h modbus-rtu.h modbus-tcp.h +libmodbusinclude_HEADERS = modbus.h modbus-version.h modbus-log.h modbus-rtu.h modbus-tcp.h DISTCLEANFILES = modbus-version.h EXTRA_DIST += modbus-version.h.in diff --git a/src/modbus-log.c b/src/modbus-log.c new file mode 100644 index 000000000..c4ec11185 --- /dev/null +++ b/src/modbus-log.c @@ -0,0 +1,63 @@ +#include "modbus-log.h" + +#include +#include + +static void* modbus_out_user_data = NULL; +static void* modbus_error_user_data = NULL; +static modbus_stream_handler_t modbus_stream_handler = (modbus_stream_handler_t) vfprintf; + +MODBUS_API void modbus_set_out_user_data(void* out_user_data) +{ + modbus_out_user_data = out_user_data; +} + +MODBUS_API void modbus_set_error_user_data(void* error_user_data) +{ + modbus_error_user_data = error_user_data; +} + +MODBUS_API void modbus_set_trace_handler(modbus_stream_handler_t handler) +{ + modbus_stream_handler = handler; +} + +MODBUS_API int modbus_trace(const char* format, ...) +{ + int result; + va_list argp; + va_start(argp, format); + + result = modbus_vtrace(format, argp); + + va_end(argp); + return result; +} + +MODBUS_API int modbus_vtrace(const char* format, va_list ap) +{ + if (!modbus_out_user_data) { + modbus_out_user_data = stdout; + } + return modbus_stream_handler(modbus_out_user_data, format, ap); +} + +MODBUS_API int modbus_trace_error(const char* format, ...) +{ + int result; + va_list argp; + va_start(argp, format); + + result = modbus_vtrace_error(format, argp); + + va_end(argp); + return result; +} + +MODBUS_API int modbus_vtrace_error(const char* format, va_list ap) +{ + if (!modbus_error_user_data) { + modbus_error_user_data = stderr; + } + return modbus_stream_handler(modbus_error_user_data, format, ap); +} diff --git a/src/modbus-log.h b/src/modbus-log.h new file mode 100644 index 000000000..8ca58c9bf --- /dev/null +++ b/src/modbus-log.h @@ -0,0 +1,19 @@ +#ifndef MODBUS_LOG_H +#define MODBUS_LOG_H + +#include "modbus.h" + +#include + +MODBUS_API void modbus_set_out_user_data(void* out_user_data); +MODBUS_API void modbus_set_error_user_data(void* error_user_data); + +typedef int (*modbus_stream_handler_t)(void *user, const char *format, va_list ap); +MODBUS_API void modbus_set_trace_handler(modbus_stream_handler_t handler); + +MODBUS_API int modbus_trace(const char* format, ...); +MODBUS_API int modbus_vtrace(const char* format, va_list ap); +MODBUS_API int modbus_trace_error(const char* format, ...); +MODBUS_API int modbus_vtrace_error(const char* format, va_list ap); + +#endif /* MODBUS_LOG_H */ diff --git a/src/modbus-rtu.c b/src/modbus-rtu.c index cb2fb5027..06ec19028 100644 --- a/src/modbus-rtu.c +++ b/src/modbus-rtu.c @@ -280,7 +280,7 @@ static ssize_t _modbus_rtu_send(modbus_t *ctx, const uint8_t *req, int req_lengt ssize_t size; if (ctx->debug) { - fprintf(stderr, "Sending request using RTS signal\n"); + modbus_trace_error("Sending request using RTS signal\n"); } ctx_rtu->set_rts(ctx, ctx_rtu->rts == MODBUS_RTU_RTS_UP); @@ -312,7 +312,7 @@ static int _modbus_rtu_receive(modbus_t *ctx, uint8_t *req) ctx_rtu->confirmation_to_ignore = FALSE; rc = 0; if (ctx->debug) { - printf("Confirmation to ignore\n"); + modbus_trace("Confirmation to ignore\n"); } } else { rc = _modbus_receive_msg(ctx, req, MSG_INDICATION); @@ -342,7 +342,7 @@ static int _modbus_rtu_pre_check_confirmation(modbus_t *ctx, const uint8_t *req, * request) */ if (req[0] != rsp[0] && req[0] != MODBUS_BROADCAST_ADDRESS) { if (ctx->debug) { - fprintf(stderr, + modbus_trace_error( "The responding slave %d isn't the requested slave %d\n", rsp[0], req[0]); } @@ -367,7 +367,7 @@ static int _modbus_rtu_check_integrity(modbus_t *ctx, uint8_t *msg, * CRC computing. */ if (slave != ctx->slave && slave != MODBUS_BROADCAST_ADDRESS) { if (ctx->debug) { - printf("Request for slave %d ignored (not %d)\n", slave, ctx->slave); + modbus_trace("Request for slave %d ignored (not %d)\n", slave, ctx->slave); } /* Following call to check_confirmation handles this error */ return 0; @@ -381,7 +381,7 @@ static int _modbus_rtu_check_integrity(modbus_t *ctx, uint8_t *msg, return msg_length; } else { if (ctx->debug) { - fprintf(stderr, "ERROR CRC received 0x%0X != CRC calculated 0x%0X\n", + modbus_trace_error("ERROR CRC received 0x%0X != CRC calculated 0x%0X\n", crc_received, crc_calculated); } @@ -406,7 +406,7 @@ static int _modbus_rtu_connect(modbus_t *ctx) modbus_rtu_t *ctx_rtu = ctx->backend_data; if (ctx->debug) { - printf("Opening %s at %d bauds (%c, %d, %d)\n", + modbus_trace("Opening %s at %d bauds (%c, %d, %d)\n", ctx_rtu->device, ctx_rtu->baud, ctx_rtu->parity, ctx_rtu->data_bit, ctx_rtu->stop_bit); } @@ -430,7 +430,7 @@ static int _modbus_rtu_connect(modbus_t *ctx) /* Error checking */ if (ctx_rtu->w_ser.fd == INVALID_HANDLE_VALUE) { if (ctx->debug) { - fprintf(stderr, "ERROR Can't open the device %s (LastError %d)\n", + modbus_trace_error("ERROR Can't open the device %s (LastError %d)\n", ctx_rtu->device, (int)GetLastError()); } return -1; @@ -440,7 +440,7 @@ static int _modbus_rtu_connect(modbus_t *ctx) ctx_rtu->old_dcb.DCBlength = sizeof(DCB); if (!GetCommState(ctx_rtu->w_ser.fd, &ctx_rtu->old_dcb)) { if (ctx->debug) { - fprintf(stderr, "ERROR Error getting configuration (LastError %d)\n", + modbus_trace_error("ERROR Error getting configuration (LastError %d)\n", (int)GetLastError()); } CloseHandle(ctx_rtu->w_ser.fd); @@ -511,7 +511,7 @@ static int _modbus_rtu_connect(modbus_t *ctx) default: dcb.BaudRate = CBR_9600; if (ctx->debug) { - fprintf(stderr, "WARNING Unknown baud rate %d for %s (B9600 used)\n", + modbus_trace_error("WARNING Unknown baud rate %d for %s (B9600 used)\n", ctx_rtu->baud, ctx_rtu->device); } } @@ -568,7 +568,7 @@ static int _modbus_rtu_connect(modbus_t *ctx) /* Setup port */ if (!SetCommState(ctx_rtu->w_ser.fd, &dcb)) { if (ctx->debug) { - fprintf(stderr, "ERROR Error setting new configuration (LastError %d)\n", + modbus_trace_error("ERROR Error setting new configuration (LastError %d)\n", (int)GetLastError()); } CloseHandle(ctx_rtu->w_ser.fd); @@ -591,7 +591,7 @@ static int _modbus_rtu_connect(modbus_t *ctx) ctx->s = open(ctx_rtu->device, flags); if (ctx->s == -1) { if (ctx->debug) { - fprintf(stderr, "ERROR Can't open the device %s (%s)\n", + modbus_trace_error("ERROR Can't open the device %s (%s)\n", ctx_rtu->device, strerror(errno)); } return -1; @@ -706,7 +706,7 @@ static int _modbus_rtu_connect(modbus_t *ctx) default: speed = B9600; if (ctx->debug) { - fprintf(stderr, + modbus_trace_error( "WARNING Unknown baud rate %d for %s (B9600 used)\n", ctx_rtu->baud, ctx_rtu->device); } @@ -932,7 +932,7 @@ int modbus_rtu_set_serial_mode(modbus_t *ctx, int mode) } #else if (ctx->debug) { - fprintf(stderr, "This function isn't supported on your platform\n"); + modbus_trace_error("This function isn't supported on your platform\n"); } errno = ENOTSUP; return -1; @@ -957,7 +957,7 @@ int modbus_rtu_get_serial_mode(modbus_t *ctx) return ctx_rtu->serial_mode; #else if (ctx->debug) { - fprintf(stderr, "This function isn't supported on your platform\n"); + modbus_trace_error("This function isn't supported on your platform\n"); } errno = ENOTSUP; return -1; @@ -981,7 +981,7 @@ int modbus_rtu_get_rts(modbus_t *ctx) return ctx_rtu->rts; #else if (ctx->debug) { - fprintf(stderr, "This function isn't supported on your platform\n"); + modbus_trace_error("This function isn't supported on your platform\n"); } errno = ENOTSUP; return -1; @@ -1017,7 +1017,7 @@ int modbus_rtu_set_rts(modbus_t *ctx, int mode) } #else if (ctx->debug) { - fprintf(stderr, "This function isn't supported on your platform\n"); + modbus_trace_error("This function isn't supported on your platform\n"); } errno = ENOTSUP; return -1; @@ -1042,7 +1042,7 @@ int modbus_rtu_set_custom_rts(modbus_t *ctx, void (*set_rts) (modbus_t *ctx, int return 0; #else if (ctx->debug) { - fprintf(stderr, "This function isn't supported on your platform\n"); + modbus_trace_error("This function isn't supported on your platform\n"); } errno = ENOTSUP; return -1; @@ -1067,7 +1067,7 @@ int modbus_rtu_get_rts_delay(modbus_t *ctx) return ctx_rtu->rts_delay; #else if (ctx->debug) { - fprintf(stderr, "This function isn't supported on your platform\n"); + modbus_trace_error("This function isn't supported on your platform\n"); } errno = ENOTSUP; return -1; @@ -1093,7 +1093,7 @@ int modbus_rtu_set_rts_delay(modbus_t *ctx, int us) return 0; #else if (ctx->debug) { - fprintf(stderr, "This function isn't supported on your platform\n"); + modbus_trace_error("This function isn't supported on your platform\n"); } errno = ENOTSUP; return -1; @@ -1112,12 +1112,12 @@ static void _modbus_rtu_close(modbus_t *ctx) #if defined(_WIN32) /* Revert settings */ if (!SetCommState(ctx_rtu->w_ser.fd, &ctx_rtu->old_dcb) && ctx->debug) { - fprintf(stderr, "ERROR Couldn't revert to configuration (LastError %d)\n", + modbus_trace_error("ERROR Couldn't revert to configuration (LastError %d)\n", (int)GetLastError()); } if (!CloseHandle(ctx_rtu->w_ser.fd) && ctx->debug) { - fprintf(stderr, "ERROR Error while closing handle (LastError %d)\n", + modbus_trace_error("ERROR Error while closing handle (LastError %d)\n", (int)GetLastError()); } #else @@ -1159,7 +1159,7 @@ static int _modbus_rtu_select(modbus_t *ctx, fd_set *rset, while ((s_rc = select(ctx->s+1, rset, NULL, NULL, tv)) == -1) { if (errno == EINTR) { if (ctx->debug) { - fprintf(stderr, "A non blocked signal was caught\n"); + modbus_trace_error("A non blocked signal was caught\n"); } /* Necessary after an error */ FD_ZERO(rset); @@ -1216,14 +1216,14 @@ modbus_t* modbus_new_rtu(const char *device, /* Check device argument */ if (device == NULL || *device == 0) { - fprintf(stderr, "The device string is empty\n"); + modbus_trace_error("The device string is empty\n"); errno = EINVAL; return NULL; } /* Check baud argument */ if (baud == 0) { - fprintf(stderr, "The baud rate value must not be zero\n"); + modbus_trace_error("The baud rate value must not be zero\n"); errno = EINVAL; return NULL; } diff --git a/src/modbus-tcp.c b/src/modbus-tcp.c index cda4c67c4..78033b155 100644 --- a/src/modbus-tcp.c +++ b/src/modbus-tcp.c @@ -65,7 +65,7 @@ static int _modbus_tcp_init_win32(void) WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { - fprintf(stderr, "WSAStartup() returned error code %d\n", + modbus_trace_error("WSAStartup() returned error code %d\n", (unsigned int)GetLastError()); errno = EIO; return -1; @@ -191,7 +191,7 @@ static int _modbus_tcp_pre_check_confirmation(modbus_t *ctx, const uint8_t *req, /* Check transaction ID */ if (req[0] != rsp[0] || req[1] != rsp[1]) { if (ctx->debug) { - fprintf(stderr, "Invalid transaction ID received 0x%X (not 0x%X)\n", + modbus_trace_error("Invalid transaction ID received 0x%X (not 0x%X)\n", (rsp[0] << 8) + rsp[1], (req[0] << 8) + req[1]); } errno = EMBBADDATA; @@ -201,7 +201,7 @@ static int _modbus_tcp_pre_check_confirmation(modbus_t *ctx, const uint8_t *req, /* Check protocol ID */ if (rsp[2] != 0x0 && rsp[3] != 0x0) { if (ctx->debug) { - fprintf(stderr, "Invalid protocol ID received 0x%X (not 0x0)\n", + modbus_trace_error("Invalid protocol ID received 0x%X (not 0x0)\n", (rsp[2] << 8) + rsp[3]); } errno = EMBBADDATA; @@ -335,7 +335,7 @@ static int _modbus_tcp_connect(modbus_t *ctx) } if (ctx->debug) { - printf("Connecting to %s:%d\n", ctx_tcp->ip, ctx_tcp->port); + modbus_trace("Connecting to %s:%d\n", ctx_tcp->ip, ctx_tcp->port); } addr.sin_family = AF_INET; @@ -381,7 +381,7 @@ static int _modbus_tcp_pi_connect(modbus_t *ctx) &ai_hints, &ai_list); if (rc != 0) { if (ctx->debug) { - fprintf(stderr, "Error returned by getaddrinfo: %s\n", gai_strerror(rc)); + modbus_trace_error("Error returned by getaddrinfo: %s\n", gai_strerror(rc)); } errno = ECONNREFUSED; return -1; @@ -407,7 +407,7 @@ static int _modbus_tcp_pi_connect(modbus_t *ctx) _modbus_tcp_set_ipv4_options(s); if (ctx->debug) { - printf("Connecting to [%s]:%s\n", ctx_tcp_pi->node, ctx_tcp_pi->service); + modbus_trace("Connecting to [%s]:%s\n", ctx_tcp_pi->node, ctx_tcp_pi->service); } rc = _connect(s, ai_ptr->ai_addr, ai_ptr->ai_addrlen, &ctx->response_timeout); @@ -585,7 +585,7 @@ int modbus_tcp_pi_listen(modbus_t *ctx, int nb_connection) rc = getaddrinfo(node, service, &ai_hints, &ai_list); if (rc != 0) { if (ctx->debug) { - fprintf(stderr, "Error returned by getaddrinfo: %s\n", gai_strerror(rc)); + modbus_trace_error("Error returned by getaddrinfo: %s\n", gai_strerror(rc)); } errno = ECONNREFUSED; return -1; @@ -668,7 +668,7 @@ int modbus_tcp_accept(modbus_t *ctx, int *s) } if (ctx->debug) { - printf("The client connection from %s is accepted\n", + modbus_trace("The client connection from %s is accepted\n", inet_ntoa(addr.sin_addr)); } @@ -698,7 +698,7 @@ int modbus_tcp_pi_accept(modbus_t *ctx, int *s) } if (ctx->debug) { - printf("The client connection is accepted.\n"); + modbus_trace("The client connection is accepted.\n"); } return ctx->s; @@ -710,7 +710,7 @@ static int _modbus_tcp_select(modbus_t *ctx, fd_set *rset, struct timeval *tv, i while ((s_rc = select(ctx->s+1, rset, NULL, NULL, tv)) == -1) { if (errno == EINTR) { if (ctx->debug) { - fprintf(stderr, "A non blocked signal was caught\n"); + modbus_trace_error("A non blocked signal was caught\n"); } /* Necessary after an error */ FD_ZERO(rset); @@ -793,7 +793,7 @@ modbus_t* modbus_new_tcp(const char *ip, int port) sa.sa_handler = SIG_IGN; if (sigaction(SIGPIPE, &sa, NULL) < 0) { /* The debug flag can't be set here... */ - fprintf(stderr, "Coud not install SIGPIPE handler.\n"); + modbus_trace_error("Coud not install SIGPIPE handler.\n"); return NULL; } #endif @@ -813,14 +813,14 @@ modbus_t* modbus_new_tcp(const char *ip, int port) dest_size = sizeof(char) * 16; ret_size = strlcpy(ctx_tcp->ip, ip, dest_size); if (ret_size == 0) { - fprintf(stderr, "The IP string is empty\n"); + modbus_trace_error("The IP string is empty\n"); modbus_free(ctx); errno = EINVAL; return NULL; } if (ret_size >= dest_size) { - fprintf(stderr, "The IP string has been truncated\n"); + modbus_trace_error("The IP string has been truncated\n"); modbus_free(ctx); errno = EINVAL; return NULL; @@ -860,14 +860,14 @@ modbus_t* modbus_new_tcp_pi(const char *node, const char *service) dest_size = sizeof(char) * _MODBUS_TCP_PI_NODE_LENGTH; ret_size = strlcpy(ctx_tcp_pi->node, node, dest_size); if (ret_size == 0) { - fprintf(stderr, "The node string is empty\n"); + modbus_trace_error("The node string is empty\n"); modbus_free(ctx); errno = EINVAL; return NULL; } if (ret_size >= dest_size) { - fprintf(stderr, "The node string has been truncated\n"); + modbus_trace_error("The node string has been truncated\n"); modbus_free(ctx); errno = EINVAL; return NULL; @@ -883,14 +883,14 @@ modbus_t* modbus_new_tcp_pi(const char *node, const char *service) } if (ret_size == 0) { - fprintf(stderr, "The service string is empty\n"); + modbus_trace_error("The service string is empty\n"); modbus_free(ctx); errno = EINVAL; return NULL; } if (ret_size >= dest_size) { - fprintf(stderr, "The service string has been truncated\n"); + modbus_trace_error("The service string has been truncated\n"); modbus_free(ctx); errno = EINVAL; return NULL; diff --git a/src/modbus.c b/src/modbus.c index f117fd2c4..5c4438be7 100644 --- a/src/modbus.c +++ b/src/modbus.c @@ -81,11 +81,11 @@ const char *modbus_strerror(int errnum) { void _error_print(modbus_t *ctx, const char *context) { if (ctx->debug) { - fprintf(stderr, "ERROR %s", modbus_strerror(errno)); + modbus_trace_error("ERROR %s", modbus_strerror(errno)); if (context != NULL) { - fprintf(stderr, ": %s\n", context); + modbus_trace_error(": %s\n", context); } else { - fprintf(stderr, "\n"); + modbus_trace_error("\n"); } } } @@ -120,7 +120,7 @@ int modbus_flush(modbus_t *ctx) rc = ctx->backend->flush(ctx); if (rc != -1 && ctx->debug) { /* Not all backends are able to return the number of bytes flushed */ - printf("Bytes flushed (%d)\n", rc); + modbus_trace("Bytes flushed (%d)\n", rc); } return rc; } @@ -172,8 +172,8 @@ static int send_msg(modbus_t *ctx, uint8_t *msg, int msg_length) if (ctx->debug) { for (i = 0; i < msg_length; i++) - printf("[%.2X]", msg[i]); - printf("\n"); + modbus_trace("[%.2X]", msg[i]); + modbus_trace("\n"); } /* In recovery mode, the write command will be issued until to be @@ -349,9 +349,9 @@ int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type) if (ctx->debug) { if (msg_type == MSG_INDICATION) { - printf("Waiting for a indication...\n"); + modbus_trace("Waiting for a indication...\n"); } else { - printf("Waiting for a confirmation...\n"); + modbus_trace("Waiting for a confirmation...\n"); } } @@ -418,7 +418,7 @@ int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type) if (ctx->debug) { int i; for (i=0; i < rc; i++) - printf("<%.2X>", msg[msg_length + i]); + modbus_trace("<%.2X>", msg[msg_length + i]); } /* Sums bytes received */ @@ -466,7 +466,7 @@ int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type) } if (ctx->debug) - printf("\n"); + modbus_trace("\n"); return ctx->backend->check_integrity(ctx, msg, msg_length); } @@ -552,7 +552,7 @@ static int check_confirmation(modbus_t *ctx, uint8_t *req, /* Check function code */ if (function != req[offset]) { if (ctx->debug) { - fprintf(stderr, + modbus_trace_error( "Received function not corresponding to the request (0x%X != 0x%X)\n", function, req[offset]); } @@ -601,7 +601,7 @@ static int check_confirmation(modbus_t *ctx, uint8_t *req, rc = rsp_nb_value; } else { if (ctx->debug) { - fprintf(stderr, + modbus_trace_error( "Quantity not corresponding to the request (%d != %d)\n", rsp_nb_value, req_nb_value); } @@ -616,7 +616,7 @@ static int check_confirmation(modbus_t *ctx, uint8_t *req, } } else { if (ctx->debug) { - fprintf(stderr, + modbus_trace_error( "Message length not corresponding to the computed length (%d != %d)\n", rsp_length, rsp_length_computed); } @@ -670,7 +670,7 @@ static int response_exception(modbus_t *ctx, sft_t *sft, va_list ap; va_start(ap, template); - vfprintf(stderr, template, ap); + modbus_vtrace_error(template, ap); va_end(ap); } @@ -909,7 +909,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, break; case MODBUS_FC_READ_EXCEPTION_STATUS: if (ctx->debug) { - fprintf(stderr, "FIXME Not implemented\n"); + modbus_trace_error("FIXME Not implemented\n"); } errno = ENOPROTOOPT; return -1; @@ -1083,7 +1083,7 @@ int modbus_read_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest) if (nb > MODBUS_MAX_READ_BITS) { if (ctx->debug) { - fprintf(stderr, + modbus_trace_error( "ERROR Too many bits requested (%d > %d)\n", nb, MODBUS_MAX_READ_BITS); } @@ -1112,7 +1112,7 @@ int modbus_read_input_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest) if (nb > MODBUS_MAX_READ_BITS) { if (ctx->debug) { - fprintf(stderr, + modbus_trace_error( "ERROR Too many discrete inputs requested (%d > %d)\n", nb, MODBUS_MAX_READ_BITS); } @@ -1139,7 +1139,7 @@ static int read_registers(modbus_t *ctx, int function, int addr, int nb, if (nb > MODBUS_MAX_READ_REGISTERS) { if (ctx->debug) { - fprintf(stderr, + modbus_trace_error( "ERROR Too many registers requested (%d > %d)\n", nb, MODBUS_MAX_READ_REGISTERS); } @@ -1187,7 +1187,7 @@ int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest) if (nb > MODBUS_MAX_READ_REGISTERS) { if (ctx->debug) { - fprintf(stderr, + modbus_trace_error( "ERROR Too many registers requested (%d > %d)\n", nb, MODBUS_MAX_READ_REGISTERS); } @@ -1212,7 +1212,7 @@ int modbus_read_input_registers(modbus_t *ctx, int addr, int nb, } if (nb > MODBUS_MAX_READ_REGISTERS) { - fprintf(stderr, + modbus_trace_error( "ERROR Too many input registers requested (%d > %d)\n", nb, MODBUS_MAX_READ_REGISTERS); errno = EMBMDATA; @@ -1296,7 +1296,7 @@ int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *src) if (nb > MODBUS_MAX_WRITE_BITS) { if (ctx->debug) { - fprintf(stderr, "ERROR Writing too many bits (%d > %d)\n", + modbus_trace_error("ERROR Writing too many bits (%d > %d)\n", nb, MODBUS_MAX_WRITE_BITS); } errno = EMBMDATA; @@ -1357,7 +1357,7 @@ int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *src) if (nb > MODBUS_MAX_WRITE_REGISTERS) { if (ctx->debug) { - fprintf(stderr, + modbus_trace_error( "ERROR Trying to write to too many registers (%d > %d)\n", nb, MODBUS_MAX_WRITE_REGISTERS); } @@ -1449,7 +1449,7 @@ int modbus_write_and_read_registers(modbus_t *ctx, if (write_nb > MODBUS_MAX_WR_WRITE_REGISTERS) { if (ctx->debug) { - fprintf(stderr, + modbus_trace_error( "ERROR Too many registers to write (%d > %d)\n", write_nb, MODBUS_MAX_WR_WRITE_REGISTERS); } @@ -1459,7 +1459,7 @@ int modbus_write_and_read_registers(modbus_t *ctx, if (read_nb > MODBUS_MAX_WR_READ_REGISTERS) { if (ctx->debug) { - fprintf(stderr, + modbus_trace_error( "ERROR Too many registers requested (%d > %d)\n", read_nb, MODBUS_MAX_WR_READ_REGISTERS); } diff --git a/src/modbus.h b/src/modbus.h index f9f7449c4..57eb7dbf8 100644 --- a/src/modbus.h +++ b/src/modbus.h @@ -285,6 +285,8 @@ MODBUS_API void modbus_set_float_cdab(float f, uint16_t *dest); #include "modbus-tcp.h" #include "modbus-rtu.h" +#include "modbus-log.h" + MODBUS_END_DECLS #endif /* MODBUS_H */ From 3b0576de631c4d3253adbb3448389ca7e03fb8d6 Mon Sep 17 00:00:00 2001 From: Martin Wagner Date: Mon, 13 Mar 2023 08:36:06 +0100 Subject: [PATCH 2/6] Logging now works on a set of per-instance variables so log facilities can now differenciate the origin of a message --- src/modbus-log.c | 63 ++++++++++++++++++++++++++-------------- src/modbus-log.h | 14 ++++----- src/modbus-private.h | 4 +++ src/modbus-rtu.c | 68 +++++++++++++++++++++++--------------------- src/modbus-tcp.c | 47 +++++++++++++++--------------- src/modbus.c | 54 +++++++++++++++++++---------------- 6 files changed, 140 insertions(+), 110 deletions(-) diff --git a/src/modbus-log.c b/src/modbus-log.c index c4ec11185..1e95f3d3a 100644 --- a/src/modbus-log.c +++ b/src/modbus-log.c @@ -1,63 +1,82 @@ #include "modbus-log.h" +#include "modbus-private.h" +#include "modbus.h" +#include #include #include -static void* modbus_out_user_data = NULL; -static void* modbus_error_user_data = NULL; -static modbus_stream_handler_t modbus_stream_handler = (modbus_stream_handler_t) vfprintf; - -MODBUS_API void modbus_set_out_user_data(void* out_user_data) +MODBUS_API void modbus_set_out_user_data(modbus_t *ctx, void* out_user_data) { - modbus_out_user_data = out_user_data; + if (ctx == NULL) { + errno = EINVAL; + return; + } + ctx->out_user_data = out_user_data; } -MODBUS_API void modbus_set_error_user_data(void* error_user_data) +MODBUS_API void modbus_set_error_user_data(modbus_t *ctx, void* error_user_data) { - modbus_error_user_data = error_user_data; + if (ctx == NULL) { + errno = EINVAL; + return; + } + ctx->error_user_data = error_user_data; } -MODBUS_API void modbus_set_trace_handler(modbus_stream_handler_t handler) +MODBUS_API void modbus_set_trace_handler(modbus_t *ctx, modbus_stream_handler_t handler) { - modbus_stream_handler = handler; + if (ctx == NULL) { + errno = EINVAL; + return; + } + ctx->stream_handler = handler; } -MODBUS_API int modbus_trace(const char* format, ...) +MODBUS_API int modbus_trace(modbus_t *ctx, const char* format, ...) { int result; va_list argp; va_start(argp, format); - result = modbus_vtrace(format, argp); + result = modbus_vtrace(ctx, format, argp); va_end(argp); return result; } -MODBUS_API int modbus_vtrace(const char* format, va_list ap) +MODBUS_API int modbus_vtrace(modbus_t *ctx, const char* format, va_list ap) { - if (!modbus_out_user_data) { - modbus_out_user_data = stdout; + if (ctx == NULL || ctx->stream_handler == NULL) { + errno = EINVAL; + return -1; + } + if (!ctx->out_user_data) { + ctx->out_user_data = stdout; } - return modbus_stream_handler(modbus_out_user_data, format, ap); + return ctx->stream_handler(ctx->out_user_data, format, ap); } -MODBUS_API int modbus_trace_error(const char* format, ...) +MODBUS_API int modbus_trace_error(modbus_t *ctx, const char* format, ...) { int result; va_list argp; va_start(argp, format); - result = modbus_vtrace_error(format, argp); + result = modbus_vtrace_error(ctx, format, argp); va_end(argp); return result; } -MODBUS_API int modbus_vtrace_error(const char* format, va_list ap) +MODBUS_API int modbus_vtrace_error(modbus_t *ctx, const char* format, va_list ap) { - if (!modbus_error_user_data) { - modbus_error_user_data = stderr; + if (ctx == NULL || ctx->stream_handler == NULL) { + errno = EINVAL; + return -1; + } + if (!ctx->error_user_data) { + ctx->error_user_data = stderr; } - return modbus_stream_handler(modbus_error_user_data, format, ap); + return ctx->stream_handler(ctx->error_user_data, format, ap); } diff --git a/src/modbus-log.h b/src/modbus-log.h index 8ca58c9bf..37e622cf4 100644 --- a/src/modbus-log.h +++ b/src/modbus-log.h @@ -5,15 +5,15 @@ #include -MODBUS_API void modbus_set_out_user_data(void* out_user_data); -MODBUS_API void modbus_set_error_user_data(void* error_user_data); +MODBUS_API void modbus_set_out_user_data(modbus_t *ctx, void* out_user_data); +MODBUS_API void modbus_set_error_user_data(modbus_t *ctx, void* error_user_data); typedef int (*modbus_stream_handler_t)(void *user, const char *format, va_list ap); -MODBUS_API void modbus_set_trace_handler(modbus_stream_handler_t handler); +MODBUS_API void modbus_set_trace_handler(modbus_t *ctx, modbus_stream_handler_t handler); -MODBUS_API int modbus_trace(const char* format, ...); -MODBUS_API int modbus_vtrace(const char* format, va_list ap); -MODBUS_API int modbus_trace_error(const char* format, ...); -MODBUS_API int modbus_vtrace_error(const char* format, va_list ap); +MODBUS_API int modbus_trace(modbus_t *ctx, const char* format, ...); +MODBUS_API int modbus_vtrace(modbus_t *ctx, const char* format, va_list ap); +MODBUS_API int modbus_trace_error(modbus_t *ctx, const char* format, ...); +MODBUS_API int modbus_vtrace_error(modbus_t *ctx, const char* format, va_list ap); #endif /* MODBUS_LOG_H */ diff --git a/src/modbus-private.h b/src/modbus-private.h index 6cd342482..590e19eb5 100644 --- a/src/modbus-private.h +++ b/src/modbus-private.h @@ -106,6 +106,10 @@ struct _modbus { struct timeval indication_timeout; const modbus_backend_t *backend; void *backend_data; + /* redirect for logging */ + void* out_user_data; + void* error_user_data; + modbus_stream_handler_t stream_handler; }; void _modbus_init_common(modbus_t *ctx); diff --git a/src/modbus-rtu.c b/src/modbus-rtu.c index 2524446a0..0cebcf964 100644 --- a/src/modbus-rtu.c +++ b/src/modbus-rtu.c @@ -267,7 +267,7 @@ static ssize_t _modbus_rtu_send(modbus_t *ctx, const uint8_t *req, int req_lengt ssize_t size; if (ctx->debug) { - modbus_trace_error("Sending request using RTS signal\n"); + modbus_trace_error(ctx, "Sending request using RTS signal\n"); } ctx_rtu->set_rts(ctx, ctx_rtu->rts == MODBUS_RTU_RTS_UP); @@ -299,7 +299,7 @@ static int _modbus_rtu_receive(modbus_t *ctx, uint8_t *req) ctx_rtu->confirmation_to_ignore = FALSE; rc = 0; if (ctx->debug) { - modbus_trace("Confirmation to ignore\n"); + modbus_trace(ctx, "Confirmation to ignore\n"); } } else { rc = _modbus_receive_msg(ctx, req, MSG_INDICATION); @@ -331,7 +331,7 @@ static int _modbus_rtu_pre_check_confirmation(modbus_t *ctx, * request) */ if (req[0] != rsp[0] && req[0] != MODBUS_BROADCAST_ADDRESS) { if (ctx->debug) { - modbus_trace_error( + modbus_trace_error(ctx, "The responding slave %d isn't the requested slave %d\n", rsp[0], req[0]); @@ -356,7 +356,7 @@ static int _modbus_rtu_check_integrity(modbus_t *ctx, uint8_t *msg, const int ms * CRC computing. */ if (slave != ctx->slave && slave != MODBUS_BROADCAST_ADDRESS) { if (ctx->debug) { - modbus_trace("Request for slave %d ignored (not %d)\n", slave, ctx->slave); + modbus_trace(ctx, "Request for slave %d ignored (not %d)\n", slave, ctx->slave); } /* Following call to check_confirmation handles this error */ return 0; @@ -370,7 +370,7 @@ static int _modbus_rtu_check_integrity(modbus_t *ctx, uint8_t *msg, const int ms return msg_length; } else { if (ctx->debug) { - modbus_trace_error( + modbus_trace_error(ctx, "ERROR CRC received 0x%0X != CRC calculated 0x%0X\n", crc_received, crc_calculated); @@ -392,7 +392,7 @@ static int _modbus_rtu_connect(modbus_t *ctx) modbus_rtu_t *ctx_rtu = ctx->backend_data; if (ctx->debug) { - modbus_trace("Opening %s at %d bauds (%c, %d, %d)\n", + modbus_trace(ctx, "Opening %s at %d bauds (%c, %d, %d)\n", ctx_rtu->device, ctx_rtu->baud, ctx_rtu->parity, @@ -413,7 +413,7 @@ static int _modbus_rtu_connect(modbus_t *ctx) /* Error checking */ if (ctx_rtu->w_ser.fd == INVALID_HANDLE_VALUE) { if (ctx->debug) { - modbus_trace_error( + modbus_trace_error(ctx, "ERROR Can't open the device %s (LastError %d)\n", ctx_rtu->device, (int) GetLastError()); @@ -425,7 +425,7 @@ static int _modbus_rtu_connect(modbus_t *ctx) ctx_rtu->old_dcb.DCBlength = sizeof(DCB); if (!GetCommState(ctx_rtu->w_ser.fd, &ctx_rtu->old_dcb)) { if (ctx->debug) { - modbus_trace_error( + modbus_trace_error(ctx, "ERROR Error getting configuration (LastError %d)\n", (int)GetLastError()); } @@ -492,7 +492,7 @@ static int _modbus_rtu_connect(modbus_t *ctx) /* Setup port */ if (!SetCommState(ctx_rtu->w_ser.fd, &dcb)) { if (ctx->debug) { - modbus_trace_error( + modbus_trace_error(ctx, "ERROR Error setting new configuration (LastError %d)\n", (int)GetLastError()); } @@ -505,7 +505,7 @@ static int _modbus_rtu_connect(modbus_t *ctx) } #else -static speed_t _get_termios_speed(int baud, int debug) +static speed_t _get_termios_speed(modbus_t *ctx, int baud) { speed_t speed; @@ -609,8 +609,8 @@ static speed_t _get_termios_speed(int baud, int debug) #endif default: speed = B9600; - if (debug) { - modbus_trace_error("WARNING Unknown baud rate %d (B9600 used)\n", baud); + if (ctx->debug) { + modbus_trace_error(ctx, "WARNING Unknown baud rate %d (B9600 used)\n", baud); } } @@ -626,7 +626,7 @@ static int _modbus_rtu_connect(modbus_t *ctx) modbus_rtu_t *ctx_rtu = ctx->backend_data; if (ctx->debug) { - modbus_trace("Opening %s at %d bauds (%c, %d, %d)\n", + modbus_trace(ctx, "Opening %s at %d bauds (%c, %d, %d)\n", ctx_rtu->device, ctx_rtu->baud, ctx_rtu->parity, @@ -649,7 +649,7 @@ static int _modbus_rtu_connect(modbus_t *ctx) ctx->s = open(ctx_rtu->device, flags); if (ctx->s < 0) { if (ctx->debug) { - modbus_trace_error( + modbus_trace_error(ctx, "ERROR Can't open the device %s (%s)\n", ctx_rtu->device, strerror(errno)); @@ -677,7 +677,7 @@ static int _modbus_rtu_connect(modbus_t *ctx) if (9600 == B9600) { speed = ctx_rtu->baud; } else { - speed = _get_termios_speed(ctx_rtu->baud, ctx->debug); + speed = _get_termios_speed(ctx, ctx_rtu->baud); } if ((cfsetispeed(&tios, speed) < 0) || (cfsetospeed(&tios, speed) < 0)) { @@ -919,7 +919,7 @@ int modbus_rtu_set_serial_mode(modbus_t *ctx, int mode) } #else if (ctx->debug) { - modbus_trace_error("This function isn't supported on your platform\n"); + modbus_trace_error(ctx, "This function isn't supported on your platform\n"); } errno = ENOTSUP; return -1; @@ -944,7 +944,7 @@ int modbus_rtu_get_serial_mode(modbus_t *ctx) return ctx_rtu->serial_mode; #else if (ctx->debug) { - modbus_trace_error("This function isn't supported on your platform\n"); + modbus_trace_error(ctx, "This function isn't supported on your platform\n"); } errno = ENOTSUP; return -1; @@ -968,7 +968,7 @@ int modbus_rtu_get_rts(modbus_t *ctx) return ctx_rtu->rts; #else if (ctx->debug) { - modbus_trace_error("This function isn't supported on your platform\n"); + modbus_trace_error(ctx, "This function isn't supported on your platform\n"); } errno = ENOTSUP; return -1; @@ -1004,7 +1004,7 @@ int modbus_rtu_set_rts(modbus_t *ctx, int mode) } #else if (ctx->debug) { - modbus_trace_error("This function isn't supported on your platform\n"); + modbus_trace_error(ctx, "This function isn't supported on your platform\n"); } errno = ENOTSUP; return -1; @@ -1029,7 +1029,7 @@ int modbus_rtu_set_custom_rts(modbus_t *ctx, void (*set_rts)(modbus_t *ctx, int return 0; #else if (ctx->debug) { - modbus_trace_error("This function isn't supported on your platform\n"); + modbus_trace_error(ctx, "This function isn't supported on your platform\n"); } errno = ENOTSUP; return -1; @@ -1054,7 +1054,7 @@ int modbus_rtu_get_rts_delay(modbus_t *ctx) return ctx_rtu->rts_delay; #else if (ctx->debug) { - modbus_trace_error("This function isn't supported on your platform\n"); + modbus_trace_error(ctx, "This function isn't supported on your platform\n"); } errno = ENOTSUP; return -1; @@ -1080,7 +1080,7 @@ int modbus_rtu_set_rts_delay(modbus_t *ctx, int us) return 0; #else if (ctx->debug) { - modbus_trace_error("This function isn't supported on your platform\n"); + modbus_trace_error(ctx, "This function isn't supported on your platform\n"); } errno = ENOTSUP; return -1; @@ -1099,13 +1099,13 @@ static void _modbus_rtu_close(modbus_t *ctx) #if defined(_WIN32) /* Revert settings */ if (!SetCommState(ctx_rtu->w_ser.fd, &ctx_rtu->old_dcb) && ctx->debug) { - modbus_trace_error( + modbus_trace_error(ctx, "ERROR Couldn't revert to configuration (LastError %d)\n", (int)GetLastError()); } if (!CloseHandle(ctx_rtu->w_ser.fd) && ctx->debug) { - modbus_trace_error( + modbus_trace_error(ctx, "ERROR Error while closing handle (LastError %d)\n", (int)GetLastError()); } @@ -1148,7 +1148,7 @@ _modbus_rtu_select(modbus_t *ctx, fd_set *rset, struct timeval *tv, int length_t while ((s_rc = select(ctx->s + 1, rset, NULL, NULL, tv)) == -1) { if (errno == EINTR) { if (ctx->debug) { - modbus_trace_error("A non blocked signal was caught\n"); + modbus_trace_error(ctx, "A non blocked signal was caught\n"); } /* Necessary after an error */ FD_ZERO(rset); @@ -1210,26 +1210,28 @@ modbus_new_rtu(const char *device, int baud, char parity, int data_bit, int stop modbus_t *ctx; modbus_rtu_t *ctx_rtu; + ctx = (modbus_t *) malloc(sizeof(modbus_t)); + if (ctx == NULL) { + return NULL; + } + _modbus_init_common(ctx); + /* Check device argument */ if (device == NULL || *device == 0) { - modbus_trace_error("The device string is empty\n"); + modbus_trace_error(ctx, "The device string is empty\n"); + modbus_free(ctx); errno = EINVAL; return NULL; } /* Check baud argument */ if (baud == 0) { - modbus_trace_error("The baud rate value must not be zero\n"); + modbus_trace_error(ctx, "The baud rate value must not be zero\n"); + modbus_free(ctx); errno = EINVAL; return NULL; } - ctx = (modbus_t *) malloc(sizeof(modbus_t)); - if (ctx == NULL) { - return NULL; - } - - _modbus_init_common(ctx); ctx->backend = &_modbus_rtu_backend; ctx->backend_data = (modbus_rtu_t *) malloc(sizeof(modbus_rtu_t)); if (ctx->backend_data == NULL) { diff --git a/src/modbus-tcp.c b/src/modbus-tcp.c index 532d407d0..b10346389 100644 --- a/src/modbus-tcp.c +++ b/src/modbus-tcp.c @@ -68,7 +68,7 @@ static int _modbus_tcp_init_win32(void) WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { - modbus_trace_error( + modbus_trace_error(ctx, "WSAStartup() returned error code %d\n", (unsigned int)GetLastError()); errno = EIO; @@ -200,7 +200,7 @@ static int _modbus_tcp_pre_check_confirmation(modbus_t *ctx, /* Check transaction ID */ if (req[0] != rsp[0] || req[1] != rsp[1]) { if (ctx->debug) { - modbus_trace_error( + modbus_trace_error(ctx, "Invalid transaction ID received 0x%X (not 0x%X)\n", (rsp[0] << 8) + rsp[1], (req[0] << 8) + req[1]); @@ -213,7 +213,7 @@ static int _modbus_tcp_pre_check_confirmation(modbus_t *ctx, protocol_id = (rsp[2] << 8) + rsp[3]; if (protocol_id != 0x0) { if (ctx->debug) { - modbus_trace_error("Invalid protocol ID received 0x%X (not 0x0)\n", protocol_id); + modbus_trace_error(ctx, "Invalid protocol ID received 0x%X (not 0x0)\n", protocol_id); } errno = EMBBADDATA; return -1; @@ -346,7 +346,7 @@ static int _modbus_tcp_connect(modbus_t *ctx) } if (ctx->debug) { - modbus_trace("Connecting to %s:%d\n", ctx_tcp->ip, ctx_tcp->port); + modbus_trace(ctx, "Connecting to %s:%d\n", ctx_tcp->ip, ctx_tcp->port); } addr.sin_family = AF_INET; @@ -354,7 +354,7 @@ static int _modbus_tcp_connect(modbus_t *ctx) rc = inet_pton(addr.sin_family, ctx_tcp->ip, &(addr.sin_addr)); if (rc <= 0) { if (ctx->debug) { - modbus_trace_error("Invalid IP address: %s\n", ctx_tcp->ip); + modbus_trace_error(ctx, "Invalid IP address: %s\n", ctx_tcp->ip); } close(ctx->s); ctx->s = -1; @@ -401,7 +401,7 @@ static int _modbus_tcp_pi_connect(modbus_t *ctx) rc = getaddrinfo(ctx_tcp_pi->node, ctx_tcp_pi->service, &ai_hints, &ai_list); if (rc != 0) { if (ctx->debug) { - modbus_trace_error("Error returned by getaddrinfo: %s\n", gai_strerror(rc)); + modbus_trace_error(ctx, "Error returned by getaddrinfo: %s\n", gai_strerror(rc)); } errno = ECONNREFUSED; return -1; @@ -427,7 +427,7 @@ static int _modbus_tcp_pi_connect(modbus_t *ctx) _modbus_tcp_set_ipv4_options(s); if (ctx->debug) { - modbus_trace("Connecting to [%s]:%s\n", ctx_tcp_pi->node, ctx_tcp_pi->service); + modbus_trace(ctx, "Connecting to [%s]:%s\n", ctx_tcp_pi->node, ctx_tcp_pi->service); } rc = _connect(s, ai_ptr->ai_addr, ai_ptr->ai_addrlen, &ctx->response_timeout); @@ -554,7 +554,7 @@ int modbus_tcp_listen(modbus_t *ctx, int nb_connection) rc = inet_pton(addr.sin_family, ctx_tcp->ip, &(addr.sin_addr)); if (rc <= 0) { if (ctx->debug) { - modbus_trace_error("Invalid IP address: %s\n", ctx_tcp->ip); + modbus_trace_error(ctx, "Invalid IP address: %s\n", ctx_tcp->ip); } close(new_s); return -1; @@ -626,7 +626,7 @@ int modbus_tcp_pi_listen(modbus_t *ctx, int nb_connection) rc = getaddrinfo(node, service, &ai_hints, &ai_list); if (rc != 0) { if (ctx->debug) { - modbus_trace_error("Error returned by getaddrinfo: %s\n", gai_strerror(rc)); + modbus_trace_error(ctx, "Error returned by getaddrinfo: %s\n", gai_strerror(rc)); } errno = ECONNREFUSED; return -1; @@ -715,9 +715,9 @@ int modbus_tcp_accept(modbus_t *ctx, int *s) if (ctx->debug) { char buf[INET_ADDRSTRLEN]; if (inet_ntop(AF_INET, &(addr.sin_addr), buf, INET_ADDRSTRLEN) == NULL) { - modbus_trace_error("Client connection accepted from unparsable IP.\n"); + modbus_trace_error(ctx, "Client connection accepted from unparsable IP.\n"); } else { - modbus_trace("Client connection accepted from %s.\n", buf); + modbus_trace(ctx, "Client connection accepted from %s.\n", buf); } } @@ -749,9 +749,9 @@ int modbus_tcp_pi_accept(modbus_t *ctx, int *s) if (ctx->debug) { char buf[INET6_ADDRSTRLEN]; if (inet_ntop(AF_INET6, &(addr.sin6_addr), buf, INET6_ADDRSTRLEN) == NULL) { - modbus_trace_error("Client connection accepted from unparsable IP.\n"); + modbus_trace_error(ctx, "Client connection accepted from unparsable IP.\n"); } else { - modbus_trace("Client connection accepted from %s.\n", buf); + modbus_trace(ctx, "Client connection accepted from %s.\n", buf); } } @@ -765,7 +765,7 @@ _modbus_tcp_select(modbus_t *ctx, fd_set *rset, struct timeval *tv, int length_t while ((s_rc = select(ctx->s + 1, rset, NULL, NULL, tv)) == -1) { if (errno == EINTR) { if (ctx->debug) { - modbus_trace_error("A non blocked signal was caught\n"); + modbus_trace_error(ctx, "A non blocked signal was caught\n"); } /* Necessary after an error */ FD_ZERO(rset); @@ -859,6 +859,12 @@ modbus_t *modbus_new_tcp(const char *ip, int port) size_t dest_size; size_t ret_size; + ctx = (modbus_t *) malloc(sizeof(modbus_t)); + if (ctx == NULL) { + return NULL; + } + _modbus_init_common(ctx); + #if defined(OS_BSD) /* MSG_NOSIGNAL is unsupported on *BSD so we install an ignore handler for SIGPIPE. */ @@ -867,17 +873,12 @@ modbus_t *modbus_new_tcp(const char *ip, int port) sa.sa_handler = SIG_IGN; if (sigaction(SIGPIPE, &sa, NULL) < 0) { /* The debug flag can't be set here... */ - modbus_trace_error("Could not install SIGPIPE handler.\n"); + modbus_trace_error(ctx, "Could not install SIGPIPE handler.\n"); + modbus_free(ctx); return NULL; } #endif - ctx = (modbus_t *) malloc(sizeof(modbus_t)); - if (ctx == NULL) { - return NULL; - } - _modbus_init_common(ctx); - /* Could be changed after to reach a remote serial Modbus device */ ctx->slave = MODBUS_TCP_SLAVE; @@ -895,14 +896,14 @@ modbus_t *modbus_new_tcp(const char *ip, int port) dest_size = sizeof(char) * 16; ret_size = strlcpy(ctx_tcp->ip, ip, dest_size); if (ret_size == 0) { - modbus_trace_error("The IP string is empty\n"); + modbus_trace_error(ctx, "The IP string is empty\n"); modbus_free(ctx); errno = EINVAL; return NULL; } if (ret_size >= dest_size) { - modbus_trace_error("The IP string has been truncated\n"); + modbus_trace_error(ctx, "The IP string has been truncated\n"); modbus_free(ctx); errno = EINVAL; return NULL; diff --git a/src/modbus.c b/src/modbus.c index ab35c2ac7..c4af9a564 100644 --- a/src/modbus.c +++ b/src/modbus.c @@ -82,11 +82,11 @@ const char *modbus_strerror(int errnum) void _error_print(modbus_t *ctx, const char *context) { if (ctx->debug) { - modbus_trace_error("ERROR %s", modbus_strerror(errno)); + modbus_trace_error(ctx, "ERROR %s", modbus_strerror(errno)); if (context != NULL) { - modbus_trace_error(": %s\n", context); + modbus_trace_error(ctx, ": %s\n", context); } else { - modbus_trace_error("\n"); + modbus_trace_error(ctx, "\n"); } } } @@ -120,7 +120,7 @@ int modbus_flush(modbus_t *ctx) rc = ctx->backend->flush(ctx); if (rc != -1 && ctx->debug) { /* Not all backends are able to return the number of bytes flushed */ - modbus_trace("Bytes flushed (%d)\n", rc); + modbus_trace(ctx, "Bytes flushed (%d)\n", rc); } return rc; } @@ -171,8 +171,8 @@ static int send_msg(modbus_t *ctx, uint8_t *msg, int msg_length) if (ctx->debug) { for (i = 0; i < msg_length; i++) - modbus_trace("[%.2X]", msg[i]); - modbus_trace("\n"); + modbus_trace(ctx, "[%.2X]", msg[i]); + modbus_trace(ctx, "\n"); } /* In recovery mode, the write command will be issued until to be @@ -362,15 +362,15 @@ int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type) if (ctx->debug) { if (msg_type == MSG_INDICATION) { - modbus_trace("Waiting for an indication...\n"); + modbus_trace(ctx, "Waiting for an indication...\n"); } else { - modbus_trace("Waiting for a confirmation...\n"); + modbus_trace(ctx, "Waiting for a confirmation...\n"); } } if (!ctx->backend->is_connected(ctx)) { if (ctx->debug) { - modbus_trace_error("ERROR The connection is not established.\n"); + modbus_trace_error(ctx, "ERROR The connection is not established.\n"); } return -1; } @@ -470,7 +470,7 @@ int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type) if (ctx->debug) { int i; for (i=0; i < rc; i++) - modbus_trace("<%.2X>", msg[msg_length + i]); + modbus_trace(ctx, "<%.2X>", msg[msg_length + i]); } /* Sums bytes received */ @@ -516,7 +516,7 @@ int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type) } if (ctx->debug) - modbus_trace("\n"); + modbus_trace(ctx, "\n"); return ctx->backend->check_integrity(ctx, msg, msg_length); } @@ -603,7 +603,7 @@ static int check_confirmation(modbus_t *ctx, uint8_t *req, uint8_t *rsp, int rsp /* Check function code */ if (function != req[offset]) { if (ctx->debug) { - modbus_trace_error( + modbus_trace_error(ctx, "Received function not corresponding to the request (0x%X != 0x%X)\n", function, req[offset]); @@ -675,7 +675,7 @@ static int check_confirmation(modbus_t *ctx, uint8_t *req, uint8_t *rsp, int rsp rc = rsp_nb_value; } else { if (ctx->debug) { - modbus_trace_error( + modbus_trace_error(ctx, "Received data not corresponding to the request (%d != %d)\n", rsp_nb_value, req_nb_value); @@ -691,7 +691,7 @@ static int check_confirmation(modbus_t *ctx, uint8_t *req, uint8_t *rsp, int rsp } } else { if (ctx->debug) { - modbus_trace_error( + modbus_trace_error(ctx, "Message length not corresponding to the computed length (%d != %d)\n", rsp_length, rsp_length_computed); @@ -748,7 +748,7 @@ static int response_exception(modbus_t *ctx, va_list ap; va_start(ap, template); - modbus_vtrace_error(template, ap); + modbus_vtrace_error(ctx, template, ap); va_end(ap); } @@ -1029,7 +1029,7 @@ int modbus_reply(modbus_t *ctx, } break; case MODBUS_FC_READ_EXCEPTION_STATUS: if (ctx->debug) { - modbus_trace_error("FIXME Not implemented\n"); + modbus_trace_error(ctx, "FIXME Not implemented\n"); } errno = ENOPROTOOPT; return -1; @@ -1224,7 +1224,7 @@ int modbus_read_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest) if (nb > MODBUS_MAX_READ_BITS) { if (ctx->debug) { - modbus_trace_error( + modbus_trace_error(ctx, "ERROR Too many bits requested (%d > %d)\n", nb, MODBUS_MAX_READ_BITS); @@ -1253,7 +1253,7 @@ int modbus_read_input_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest) if (nb > MODBUS_MAX_READ_BITS) { if (ctx->debug) { - modbus_trace_error( + modbus_trace_error(ctx, "ERROR Too many discrete inputs requested (%d > %d)\n", nb, MODBUS_MAX_READ_BITS); @@ -1280,7 +1280,7 @@ static int read_registers(modbus_t *ctx, int function, int addr, int nb, uint16_ if (nb > MODBUS_MAX_READ_REGISTERS) { if (ctx->debug) { - modbus_trace_error( + modbus_trace_error(ctx, "ERROR Too many registers requested (%d > %d)\n", nb, MODBUS_MAX_READ_REGISTERS); @@ -1328,7 +1328,7 @@ int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest) if (nb > MODBUS_MAX_READ_REGISTERS) { if (ctx->debug) { - modbus_trace_error( + modbus_trace_error(ctx, "ERROR Too many registers requested (%d > %d)\n", nb, MODBUS_MAX_READ_REGISTERS); @@ -1352,7 +1352,7 @@ int modbus_read_input_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest) } if (nb > MODBUS_MAX_READ_REGISTERS) { - modbus_trace_error( + modbus_trace_error(ctx, "ERROR Too many input registers requested (%d > %d)\n", nb, MODBUS_MAX_READ_REGISTERS); @@ -1435,7 +1435,7 @@ int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *src) if (nb > MODBUS_MAX_WRITE_BITS) { if (ctx->debug) { - modbus_trace_error( + modbus_trace_error(ctx, "ERROR Writing too many bits (%d > %d)\n", nb, MODBUS_MAX_WRITE_BITS); @@ -1496,7 +1496,7 @@ int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *src) if (nb > MODBUS_MAX_WRITE_REGISTERS) { if (ctx->debug) { - modbus_trace_error( + modbus_trace_error(ctx, "ERROR Trying to write to too many registers (%d > %d)\n", nb, MODBUS_MAX_WRITE_REGISTERS); @@ -1592,7 +1592,7 @@ int modbus_write_and_read_registers(modbus_t *ctx, if (write_nb > MODBUS_MAX_WR_WRITE_REGISTERS) { if (ctx->debug) { - modbus_trace_error( + modbus_trace_error(ctx, "ERROR Too many registers to write (%d > %d)\n", write_nb, MODBUS_MAX_WR_WRITE_REGISTERS); @@ -1603,7 +1603,7 @@ int modbus_write_and_read_registers(modbus_t *ctx, if (read_nb > MODBUS_MAX_WR_READ_REGISTERS) { if (ctx->debug) { - modbus_trace_error( + modbus_trace_error(ctx, "ERROR Too many registers requested (%d > %d)\n", read_nb, MODBUS_MAX_WR_READ_REGISTERS); @@ -1711,6 +1711,10 @@ void _modbus_init_common(modbus_t *ctx) ctx->indication_timeout.tv_sec = 0; ctx->indication_timeout.tv_usec = 0; + + ctx->out_user_data = stdout; + ctx->error_user_data = stderr; + ctx->stream_handler = (modbus_stream_handler_t) vfprintf; } /* Define the slave number */ From faead6a56055422fceba63cfaa2b518e96a3d08e Mon Sep 17 00:00:00 2001 From: Martin Wagner Date: Mon, 13 Mar 2023 09:15:41 +0100 Subject: [PATCH 3/6] Fix some logging prints to new logging --- src/modbus-tcp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/modbus-tcp.c b/src/modbus-tcp.c index b10346389..d976f4b8e 100644 --- a/src/modbus-tcp.c +++ b/src/modbus-tcp.c @@ -644,7 +644,7 @@ int modbus_tcp_pi_listen(modbus_t *ctx, int nb_connection) s = socket(ai_ptr->ai_family, flags, ai_ptr->ai_protocol); if (s < 0) { if (ctx->debug) { - perror("socket"); + modbus_trace_error(ctx, "socket: %s\n", strerror(errno)); } continue; } else { @@ -654,7 +654,7 @@ int modbus_tcp_pi_listen(modbus_t *ctx, int nb_connection) if (rc != 0) { close(s); if (ctx->debug) { - perror("setsockopt"); + modbus_trace_error(ctx, "setsockopt: %s\n", strerror(errno)); } continue; } @@ -664,7 +664,7 @@ int modbus_tcp_pi_listen(modbus_t *ctx, int nb_connection) if (rc != 0) { close(s); if (ctx->debug) { - perror("bind"); + modbus_trace_error(ctx, "bind: %s\n", strerror(errno)); } continue; } @@ -673,7 +673,7 @@ int modbus_tcp_pi_listen(modbus_t *ctx, int nb_connection) if (rc != 0) { close(s); if (ctx->debug) { - perror("listen"); + modbus_trace_error(ctx, "listen: %s\n", strerror(errno)); } continue; } From 72e3724459bf37d6c7a4eccca470790ce9787f82 Mon Sep 17 00:00:00 2001 From: Martin Wagner Date: Tue, 14 Mar 2023 09:37:43 +0100 Subject: [PATCH 4/6] Fix windows cross build --- src/modbus-tcp.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/modbus-tcp.c b/src/modbus-tcp.c index d976f4b8e..7fa649ecb 100644 --- a/src/modbus-tcp.c +++ b/src/modbus-tcp.c @@ -62,7 +62,7 @@ #include "modbus-tcp.h" #ifdef OS_WIN32 -static int _modbus_tcp_init_win32(void) +static int _modbus_tcp_init_win32(modbus_t *ctx) { /* Initialise Windows Socket API */ WSADATA wsaData; @@ -320,7 +320,7 @@ static int _modbus_tcp_connect(modbus_t *ctx) int flags = SOCK_STREAM; #ifdef OS_WIN32 - if (_modbus_tcp_init_win32() == -1) { + if (_modbus_tcp_init_win32(ctx) == -1) { return -1; } #endif @@ -382,7 +382,7 @@ static int _modbus_tcp_pi_connect(modbus_t *ctx) modbus_tcp_pi_t *ctx_tcp_pi = ctx->backend_data; #ifdef OS_WIN32 - if (_modbus_tcp_init_win32() == -1) { + if (_modbus_tcp_init_win32(ctx) == -1) { return -1; } #endif @@ -519,7 +519,7 @@ int modbus_tcp_listen(modbus_t *ctx, int nb_connection) ctx_tcp = ctx->backend_data; #ifdef OS_WIN32 - if (_modbus_tcp_init_win32() == -1) { + if (_modbus_tcp_init_win32(ctx) == -1) { return -1; } #endif @@ -593,7 +593,7 @@ int modbus_tcp_pi_listen(modbus_t *ctx, int nb_connection) ctx_tcp_pi = ctx->backend_data; #ifdef OS_WIN32 - if (_modbus_tcp_init_win32() == -1) { + if (_modbus_tcp_init_win32(ctx) == -1) { return -1; } #endif From acacb7dc0a41b9feff39a190dc0b88c10aaf3aa5 Mon Sep 17 00:00:00 2001 From: Martin Wagner Date: Tue, 14 Mar 2023 10:34:21 +0100 Subject: [PATCH 5/6] add extended debug log docs --- docs/index.md | 10 +++++++ docs/modbus_set_error_user_data.md | 32 ++++++++++++++++++++++ docs/modbus_set_out_user_data.md | 32 ++++++++++++++++++++++ docs/modbus_set_trace_handler.md | 44 ++++++++++++++++++++++++++++++ 4 files changed, 118 insertions(+) create mode 100644 docs/modbus_set_error_user_data.md create mode 100644 docs/modbus_set_out_user_data.md create mode 100644 docs/modbus_set_trace_handler.md diff --git a/docs/index.md b/docs/index.md index 89fcbbba8..d8d8cfbed 100644 --- a/docs/index.md +++ b/docs/index.md @@ -249,6 +249,16 @@ The *modbus_strerror()* function is provided to translate libmodbus-specific error codes into error message strings; for details refer to [modbus_strerror](modbus_strerror.md). +## Extended debug + +By default, the debug output created by enabling [modbus_set_debug](modbus_set_debug.md) +is written to stdout/stderr. With the following functions those can be redirected +to files or a callback. + +- [modbus_set_out_user_data](modbus_set_out_user_data.md) +- [modbus_set_error_user_data](modbus_set_error_user_data.md) +- [modbus_set_trace_handler](modbus_set_trace_handler.md) + ## Miscellaneous To deviate from the Modbus standard, you can enable or disable quirks with: diff --git a/docs/modbus_set_error_user_data.md b/docs/modbus_set_error_user_data.md new file mode 100644 index 000000000..113f3dbe7 --- /dev/null +++ b/docs/modbus_set_error_user_data.md @@ -0,0 +1,32 @@ +# modbus_set_error_user_data + +## Name + +modbus_set_error_user_data - set file stream to write log output + +## Synopsis + +```c +void modbus_set_error_user_data(modbus_t *ctx, void* out_user_data); +``` + +## Description + +The *modbus_set_error_user_data()* changes where log output is written +to when enabled with [modbus_set_debug](modbus_set_debug.md). Defaults +to stderr when not set. + + +## Example + +```c +FILE *fp; +fp = fopen("error.txt", "w"); +modbus_set_error_user_data(ctx, fp); +modbus_set_debug(ctx, 1) +``` + +## See also + +- [modbus_set_out_user_data](modbus_set_out_user_data.md) +- [modbus_set_trace_handler](modbus_set_trace_handler.md) diff --git a/docs/modbus_set_out_user_data.md b/docs/modbus_set_out_user_data.md new file mode 100644 index 000000000..2e3b024cf --- /dev/null +++ b/docs/modbus_set_out_user_data.md @@ -0,0 +1,32 @@ +# modbus_set_out_user_data + +## Name + +modbus_set_out_user_data - set file stream to write log output + +## Synopsis + +```c +void modbus_set_out_user_data(modbus_t *ctx, void* out_user_data); +``` + +## Description + +The *modbus_set_out_user_data()* changes where log output is written +to when enabled with [modbus_set_debug](modbus_set_debug.md). Defaults +to stdout when not set. + + +## Example + +```c +FILE *fp; +fp = fopen("output.txt", "w"); +modbus_set_out_user_data(ctx, fp); +modbus_set_debug(ctx, 1) +``` + +## See also + +- [modbus_set_error_user_data](modbus_set_error_user_data.md) +- [modbus_set_trace_handler](modbus_set_trace_handler.md) diff --git a/docs/modbus_set_trace_handler.md b/docs/modbus_set_trace_handler.md new file mode 100644 index 000000000..1c732b42e --- /dev/null +++ b/docs/modbus_set_trace_handler.md @@ -0,0 +1,44 @@ +# modbus_set_trace_handler + +## Name + +modbus_set_trace_handler - call method when log data is written + +## Synopsis + +```c +typedef int (*modbus_stream_handler_t)(void *user, const char *format, va_list ap); +void modbus_set_trace_handler(modbus_t *ctx, modbus_stream_handler_t handler); +``` + +## Description + +The *modbus_set_trace_handler()* sets a callback. When log data is written, the +callback is called. A log message is finalized with a '\n' as last character. +Defaults to vfprintf when not set. + + +## Example + +```c++ +class Test { + public: + static int log_callback(void *user, const char *format, va_list ap) + { + auto *inst = reinterpret_cast(user); + //call methods + } + void setup() + { + modbus_set_out_user_data(reinterpret_cast(this)); + modbus_set_error_user_data(reinterpret_cast(this)); + modbus_set_trace_handler(log_callback); + modbus_set_debug(true); + } +} +``` + +## See also + +- [modbus_set_out_user_data](modbus_set_out_user_data.md) +- [modbus_set_error_user_data](modbus_set_error_user_data.md) From b9c26e98b409b5943482e71a4a15425b92f64240 Mon Sep 17 00:00:00 2001 From: Martin Wagner Date: Wed, 17 Jul 2024 16:16:54 +0200 Subject: [PATCH 6/6] Fix: use modbus_free only after object is fully initialised... fixes double-free crash in unit-test server/client --- src/modbus-rtu.c | 4 ++-- src/modbus-tcp.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modbus-rtu.c b/src/modbus-rtu.c index 0cebcf964..e3d43919d 100644 --- a/src/modbus-rtu.c +++ b/src/modbus-rtu.c @@ -1219,7 +1219,7 @@ modbus_new_rtu(const char *device, int baud, char parity, int data_bit, int stop /* Check device argument */ if (device == NULL || *device == 0) { modbus_trace_error(ctx, "The device string is empty\n"); - modbus_free(ctx); + free(ctx); errno = EINVAL; return NULL; } @@ -1227,7 +1227,7 @@ modbus_new_rtu(const char *device, int baud, char parity, int data_bit, int stop /* Check baud argument */ if (baud == 0) { modbus_trace_error(ctx, "The baud rate value must not be zero\n"); - modbus_free(ctx); + free(ctx); errno = EINVAL; return NULL; } diff --git a/src/modbus-tcp.c b/src/modbus-tcp.c index 7fa649ecb..2418fca9d 100644 --- a/src/modbus-tcp.c +++ b/src/modbus-tcp.c @@ -874,7 +874,7 @@ modbus_t *modbus_new_tcp(const char *ip, int port) if (sigaction(SIGPIPE, &sa, NULL) < 0) { /* The debug flag can't be set here... */ modbus_trace_error(ctx, "Could not install SIGPIPE handler.\n"); - modbus_free(ctx); + free(ctx); return NULL; } #endif