Commit ef3c4bc989a4774402b89880d1afd54b1b6a1b67

Authored by Stéphane Raimbault
1 parent 9b679b7c

Reduce memory use of TCP PI backend (closes #621)

- allocate exact memory required to store node and service strings
  instead of around 1kb of static memory.
- accept NULL value of service to use default Modbus port number (502)
- unit test updated

The new documentation will be updated in another commit.
src/modbus-tcp-private.h
@@ -27,18 +27,15 @@ typedef struct _modbus_tcp { @@ -27,18 +27,15 @@ typedef struct _modbus_tcp {
27 char ip[16]; 27 char ip[16];
28 } modbus_tcp_t; 28 } modbus_tcp_t;
29 29
30 -#define _MODBUS_TCP_PI_NODE_LENGTH 1025  
31 -#define _MODBUS_TCP_PI_SERVICE_LENGTH 32  
32 -  
33 typedef struct _modbus_tcp_pi { 30 typedef struct _modbus_tcp_pi {
34 /* Transaction ID */ 31 /* Transaction ID */
35 uint16_t t_id; 32 uint16_t t_id;
36 /* TCP port */ 33 /* TCP port */
37 int port; 34 int port;
38 /* Node */ 35 /* Node */
39 - char node[_MODBUS_TCP_PI_NODE_LENGTH]; 36 + char *node;
40 /* Service */ 37 /* Service */
41 - char service[_MODBUS_TCP_PI_SERVICE_LENGTH]; 38 + char *service;
42 } modbus_tcp_pi_t; 39 } modbus_tcp_pi_t;
43 40
44 #endif /* MODBUS_TCP_PRIVATE_H */ 41 #endif /* MODBUS_TCP_PRIVATE_H */
src/modbus-tcp.c
@@ -740,7 +740,20 @@ static int _modbus_tcp_select(modbus_t *ctx, fd_set *rset, struct timeval *tv, i @@ -740,7 +740,20 @@ static int _modbus_tcp_select(modbus_t *ctx, fd_set *rset, struct timeval *tv, i
740 } 740 }
741 741
742 static void _modbus_tcp_free(modbus_t *ctx) { 742 static void _modbus_tcp_free(modbus_t *ctx) {
743 - free(ctx->backend_data); 743 + if (ctx->backend_data) {
  744 + free(ctx->backend_data);
  745 + }
  746 + free(ctx);
  747 +}
  748 +
  749 +static void _modbus_tcp_pi_free(modbus_t *ctx) {
  750 + if (ctx->backend_data) {
  751 + modbus_tcp_pi_t *ctx_tcp_pi = ctx->backend_data;
  752 + free(ctx_tcp_pi->node);
  753 + free(ctx_tcp_pi->service);
  754 + free(ctx->backend_data);
  755 + }
  756 +
744 free(ctx); 757 free(ctx);
745 } 758 }
746 759
@@ -786,7 +799,7 @@ const modbus_backend_t _modbus_tcp_pi_backend = { @@ -786,7 +799,7 @@ const modbus_backend_t _modbus_tcp_pi_backend = {
786 _modbus_tcp_close, 799 _modbus_tcp_close,
787 _modbus_tcp_flush, 800 _modbus_tcp_flush,
788 _modbus_tcp_select, 801 _modbus_tcp_select,
789 - _modbus_tcp_free 802 + _modbus_tcp_pi_free
790 }; 803 };
791 804
792 modbus_t* modbus_new_tcp(const char *ip, int port) 805 modbus_t* modbus_new_tcp(const char *ip, int port)
@@ -858,8 +871,6 @@ modbus_t* modbus_new_tcp_pi(const char *node, const char *service) @@ -858,8 +871,6 @@ modbus_t* modbus_new_tcp_pi(const char *node, const char *service)
858 { 871 {
859 modbus_t *ctx; 872 modbus_t *ctx;
860 modbus_tcp_pi_t *ctx_tcp_pi; 873 modbus_tcp_pi_t *ctx_tcp_pi;
861 - size_t dest_size;  
862 - size_t ret_size;  
863 874
864 ctx = (modbus_t *)malloc(sizeof(modbus_t)); 875 ctx = (modbus_t *)malloc(sizeof(modbus_t));
865 if (ctx == NULL) { 876 if (ctx == NULL) {
@@ -879,47 +890,32 @@ modbus_t* modbus_new_tcp_pi(const char *node, const char *service) @@ -879,47 +890,32 @@ modbus_t* modbus_new_tcp_pi(const char *node, const char *service)
879 return NULL; 890 return NULL;
880 } 891 }
881 ctx_tcp_pi = (modbus_tcp_pi_t *)ctx->backend_data; 892 ctx_tcp_pi = (modbus_tcp_pi_t *)ctx->backend_data;
  893 + ctx_tcp_pi->node = NULL;
  894 + ctx_tcp_pi->service = NULL;
882 895
883 - if (node == NULL) {  
884 - /* The node argument can be empty to indicate any hosts */  
885 - ctx_tcp_pi->node[0] = 0;  
886 - } else {  
887 - dest_size = sizeof(char) * _MODBUS_TCP_PI_NODE_LENGTH;  
888 - ret_size = strlcpy(ctx_tcp_pi->node, node, dest_size);  
889 - if (ret_size == 0) {  
890 - fprintf(stderr, "The node string is empty\n");  
891 - modbus_free(ctx);  
892 - errno = EINVAL;  
893 - return NULL;  
894 - }  
895 -  
896 - if (ret_size >= dest_size) {  
897 - fprintf(stderr, "The node string has been truncated\n");  
898 - modbus_free(ctx);  
899 - errno = EINVAL;  
900 - return NULL;  
901 - }  
902 - }  
903 -  
904 - if (service != NULL) {  
905 - dest_size = sizeof(char) * _MODBUS_TCP_PI_SERVICE_LENGTH;  
906 - ret_size = strlcpy(ctx_tcp_pi->service, service, dest_size); 896 + if (node != NULL) {
  897 + ctx_tcp_pi->node = strdup(node);
907 } else { 898 } else {
908 - /* Empty service is not allowed, error caught below. */  
909 - ret_size = 0; 899 + /* The node argument can be empty to indicate any hosts */
  900 + ctx_tcp_pi->node = strdup("");
910 } 901 }
911 902
912 - if (ret_size == 0) {  
913 - fprintf(stderr, "The service string is empty\n"); 903 + if (ctx_tcp_pi->node == NULL) {
914 modbus_free(ctx); 904 modbus_free(ctx);
915 - errno = EINVAL; 905 + errno = ENOMEM;
916 return NULL; 906 return NULL;
917 } 907 }
918 908
919 - if (ret_size >= dest_size) {  
920 - fprintf(stderr, "The service string has been truncated\n"); 909 + if (service != NULL && service[0] != '\0') {
  910 + ctx_tcp_pi->service = strdup(service);
  911 + } else {
  912 + /* Default Modbus port number */
  913 + ctx_tcp_pi->service = strdup("502");
  914 + }
  915 +
  916 + if (ctx_tcp_pi->service == NULL) {
921 modbus_free(ctx); 917 modbus_free(ctx);
922 - errno = EINVAL; 918 + errno = ENOMEM;
923 return NULL; 919 return NULL;
924 } 920 }
925 921
tests/unit-test-client.c
@@ -681,9 +681,6 @@ int main(int argc, char *argv[]) @@ -681,9 +681,6 @@ int main(int argc, char *argv[])
681 ctx = modbus_new_rtu("/dev/dummy", 0, 'A', 0, 0); 681 ctx = modbus_new_rtu("/dev/dummy", 0, 'A', 0, 0);
682 ASSERT_TRUE(ctx == NULL && errno == EINVAL, ""); 682 ASSERT_TRUE(ctx == NULL && errno == EINVAL, "");
683 683
684 - ctx = modbus_new_tcp_pi(NULL, NULL);  
685 - ASSERT_TRUE(ctx == NULL && errno == EINVAL, "");  
686 -  
687 printf("\nALL TESTS PASS WITH SUCCESS.\n"); 684 printf("\nALL TESTS PASS WITH SUCCESS.\n");
688 success = TRUE; 685 success = TRUE;
689 686