Commit 8dc21ddaf51bace2030f5f06b51754eb4de6e87d
1 parent
e90f906b
TCP - Socket in non blocking mode by default
Original patch for new connect function by Thomas Stalder.
Showing
4 changed files
with
55 additions
and
21 deletions
src/modbus-private.h
| @@ -109,7 +109,7 @@ typedef struct _modbus_backend { | @@ -109,7 +109,7 @@ typedef struct _modbus_backend { | ||
| 109 | int (*connect) (modbus_t *ctx); | 109 | int (*connect) (modbus_t *ctx); |
| 110 | void (*close) (modbus_t *ctx); | 110 | void (*close) (modbus_t *ctx); |
| 111 | int (*flush) (modbus_t *ctx); | 111 | int (*flush) (modbus_t *ctx); |
| 112 | - int (*select) (modbus_t *ctx, fd_set *rfds, struct timeval *tv, int msg_length); | 112 | + int (*select) (modbus_t *ctx, fd_set *rset, struct timeval *tv, int msg_length); |
| 113 | } modbus_backend_t; | 113 | } modbus_backend_t; |
| 114 | 114 | ||
| 115 | struct _modbus { | 115 | struct _modbus { |
src/modbus-rtu.c
| @@ -945,7 +945,7 @@ int _modbus_rtu_flush(modbus_t *ctx) | @@ -945,7 +945,7 @@ int _modbus_rtu_flush(modbus_t *ctx) | ||
| 945 | #endif | 945 | #endif |
| 946 | } | 946 | } |
| 947 | 947 | ||
| 948 | -int _modbus_rtu_select(modbus_t *ctx, fd_set *rfds, | 948 | +int _modbus_rtu_select(modbus_t *ctx, fd_set *rset, |
| 949 | struct timeval *tv, int length_to_read) | 949 | struct timeval *tv, int length_to_read) |
| 950 | { | 950 | { |
| 951 | int s_rc; | 951 | int s_rc; |
| @@ -961,14 +961,14 @@ int _modbus_rtu_select(modbus_t *ctx, fd_set *rfds, | @@ -961,14 +961,14 @@ int _modbus_rtu_select(modbus_t *ctx, fd_set *rfds, | ||
| 961 | return -1; | 961 | return -1; |
| 962 | } | 962 | } |
| 963 | #else | 963 | #else |
| 964 | - while ((s_rc = select(ctx->s+1, rfds, NULL, NULL, tv)) == -1) { | 964 | + while ((s_rc = select(ctx->s+1, rset, NULL, NULL, tv)) == -1) { |
| 965 | if (errno == EINTR) { | 965 | if (errno == EINTR) { |
| 966 | if (ctx->debug) { | 966 | if (ctx->debug) { |
| 967 | fprintf(stderr, "A non blocked signal was caught\n"); | 967 | fprintf(stderr, "A non blocked signal was caught\n"); |
| 968 | } | 968 | } |
| 969 | /* Necessary after an error */ | 969 | /* Necessary after an error */ |
| 970 | - FD_ZERO(rfds); | ||
| 971 | - FD_SET(ctx->s, rfds); | 970 | + FD_ZERO(rset); |
| 971 | + FD_SET(ctx->s, rset); | ||
| 972 | } else { | 972 | } else { |
| 973 | return -1; | 973 | return -1; |
| 974 | } | 974 | } |
src/modbus-tcp.c
| @@ -238,10 +238,37 @@ static int _modbus_tcp_set_ipv4_options(int s) | @@ -238,10 +238,37 @@ static int _modbus_tcp_set_ipv4_options(int s) | ||
| 238 | return 0; | 238 | return 0; |
| 239 | } | 239 | } |
| 240 | 240 | ||
| 241 | +static int _connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen, | ||
| 242 | + struct timeval *tv) | ||
| 243 | +{ | ||
| 244 | + int rc; | ||
| 245 | + | ||
| 246 | + rc = connect(sockfd, addr, addrlen); | ||
| 247 | + if (rc == -1 && errno == EINPROGRESS) { | ||
| 248 | + fd_set wset; | ||
| 249 | + int err; | ||
| 250 | + socklen_t errlen = sizeof(err); | ||
| 251 | + | ||
| 252 | + FD_ZERO(&wset); | ||
| 253 | + FD_SET(sockfd, &wset); | ||
| 254 | + rc = select(sockfd + 1, NULL, &wset, NULL, tv); | ||
| 255 | + if (rc < 0) { | ||
| 256 | + /* Timeout or fail */ | ||
| 257 | + return -1; | ||
| 258 | + } | ||
| 259 | + | ||
| 260 | + /* The socket is available for writing if it returns 0 */ | ||
| 261 | + return getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errlen); | ||
| 262 | + } | ||
| 263 | + /* 0 or (-1 and errno != EINPROGRESS) */ | ||
| 264 | + return rc; | ||
| 265 | +} | ||
| 266 | + | ||
| 241 | /* Establishes a modbus TCP connection with a Modbus server. */ | 267 | /* Establishes a modbus TCP connection with a Modbus server. */ |
| 242 | static int _modbus_tcp_connect(modbus_t *ctx) | 268 | static int _modbus_tcp_connect(modbus_t *ctx) |
| 243 | { | 269 | { |
| 244 | int rc; | 270 | int rc; |
| 271 | + /* Specialized version of sockaddr for Internet socket address (same size) */ | ||
| 245 | struct sockaddr_in addr; | 272 | struct sockaddr_in addr; |
| 246 | modbus_tcp_t *ctx_tcp = ctx->backend_data; | 273 | modbus_tcp_t *ctx_tcp = ctx->backend_data; |
| 247 | int flags = SOCK_STREAM; | 274 | int flags = SOCK_STREAM; |
| @@ -256,6 +283,10 @@ static int _modbus_tcp_connect(modbus_t *ctx) | @@ -256,6 +283,10 @@ static int _modbus_tcp_connect(modbus_t *ctx) | ||
| 256 | flags |= SOCK_CLOEXEC; | 283 | flags |= SOCK_CLOEXEC; |
| 257 | #endif | 284 | #endif |
| 258 | 285 | ||
| 286 | +#ifdef SOCK_NONBLOCK | ||
| 287 | + flags |= SOCK_NONBLOCK; | ||
| 288 | +#endif | ||
| 289 | + | ||
| 259 | ctx->s = socket(PF_INET, flags, 0); | 290 | ctx->s = socket(PF_INET, flags, 0); |
| 260 | if (ctx->s == -1) { | 291 | if (ctx->s == -1) { |
| 261 | return -1; | 292 | return -1; |
| @@ -274,8 +305,7 @@ static int _modbus_tcp_connect(modbus_t *ctx) | @@ -274,8 +305,7 @@ static int _modbus_tcp_connect(modbus_t *ctx) | ||
| 274 | addr.sin_family = AF_INET; | 305 | addr.sin_family = AF_INET; |
| 275 | addr.sin_port = htons(ctx_tcp->port); | 306 | addr.sin_port = htons(ctx_tcp->port); |
| 276 | addr.sin_addr.s_addr = inet_addr(ctx_tcp->ip); | 307 | addr.sin_addr.s_addr = inet_addr(ctx_tcp->ip); |
| 277 | - rc = connect(ctx->s, (struct sockaddr *)&addr, | ||
| 278 | - sizeof(struct sockaddr_in)); | 308 | + rc = _connect(ctx->s, (struct sockaddr *)&addr, sizeof(addr), &ctx->response_timeout); |
| 279 | if (rc == -1) { | 309 | if (rc == -1) { |
| 280 | close(ctx->s); | 310 | close(ctx->s); |
| 281 | return -1; | 311 | return -1; |
| @@ -317,6 +347,10 @@ static int _modbus_tcp_pi_connect(modbus_t *ctx) | @@ -317,6 +347,10 @@ static int _modbus_tcp_pi_connect(modbus_t *ctx) | ||
| 317 | flags |= SOCK_CLOEXEC; | 347 | flags |= SOCK_CLOEXEC; |
| 318 | #endif | 348 | #endif |
| 319 | 349 | ||
| 350 | +#ifdef SOCK_NONBLOCK | ||
| 351 | + flags |= SOCK_NONBLOCK; | ||
| 352 | +#endif | ||
| 353 | + | ||
| 320 | s = socket(ai_ptr->ai_family, flags, ai_ptr->ai_protocol); | 354 | s = socket(ai_ptr->ai_family, flags, ai_ptr->ai_protocol); |
| 321 | if (s < 0) | 355 | if (s < 0) |
| 322 | continue; | 356 | continue; |
| @@ -324,8 +358,8 @@ static int _modbus_tcp_pi_connect(modbus_t *ctx) | @@ -324,8 +358,8 @@ static int _modbus_tcp_pi_connect(modbus_t *ctx) | ||
| 324 | if (ai_ptr->ai_family == AF_INET) | 358 | if (ai_ptr->ai_family == AF_INET) |
| 325 | _modbus_tcp_set_ipv4_options(s); | 359 | _modbus_tcp_set_ipv4_options(s); |
| 326 | 360 | ||
| 327 | - rc = connect(s, ai_ptr->ai_addr, ai_ptr->ai_addrlen); | ||
| 328 | - if (rc != 0) { | 361 | + rc = _connect(s, ai_ptr->ai_addr, ai_ptr->ai_addrlen, &ctx->response_timeout); |
| 362 | + if (rc == -1) { | ||
| 329 | close(s); | 363 | close(s); |
| 330 | continue; | 364 | continue; |
| 331 | } | 365 | } |
| @@ -362,14 +396,14 @@ int _modbus_tcp_flush(modbus_t *ctx) | @@ -362,14 +396,14 @@ int _modbus_tcp_flush(modbus_t *ctx) | ||
| 362 | rc = recv(ctx->s, devnull, MODBUS_TCP_MAX_ADU_LENGTH, MSG_DONTWAIT); | 396 | rc = recv(ctx->s, devnull, MODBUS_TCP_MAX_ADU_LENGTH, MSG_DONTWAIT); |
| 363 | #else | 397 | #else |
| 364 | /* On Win32, it's a bit more complicated to not wait */ | 398 | /* On Win32, it's a bit more complicated to not wait */ |
| 365 | - fd_set rfds; | 399 | + fd_set rset; |
| 366 | struct timeval tv; | 400 | struct timeval tv; |
| 367 | 401 | ||
| 368 | tv.tv_sec = 0; | 402 | tv.tv_sec = 0; |
| 369 | tv.tv_usec = 0; | 403 | tv.tv_usec = 0; |
| 370 | - FD_ZERO(&rfds); | ||
| 371 | - FD_SET(ctx->s, &rfds); | ||
| 372 | - rc = select(ctx->s+1, &rfds, NULL, NULL, &tv); | 404 | + FD_ZERO(&rset); |
| 405 | + FD_SET(ctx->s, &rset); | ||
| 406 | + rc = select(ctx->s+1, &rset, NULL, NULL, &tv); | ||
| 373 | if (rc == -1) { | 407 | if (rc == -1) { |
| 374 | return -1; | 408 | return -1; |
| 375 | } | 409 | } |
| @@ -571,17 +605,17 @@ int modbus_tcp_pi_accept(modbus_t *ctx, int *socket) | @@ -571,17 +605,17 @@ int modbus_tcp_pi_accept(modbus_t *ctx, int *socket) | ||
| 571 | return ctx->s; | 605 | return ctx->s; |
| 572 | } | 606 | } |
| 573 | 607 | ||
| 574 | -int _modbus_tcp_select(modbus_t *ctx, fd_set *rfds, struct timeval *tv, int length_to_read) | 608 | +int _modbus_tcp_select(modbus_t *ctx, fd_set *rset, struct timeval *tv, int length_to_read) |
| 575 | { | 609 | { |
| 576 | int s_rc; | 610 | int s_rc; |
| 577 | - while ((s_rc = select(ctx->s+1, rfds, NULL, NULL, tv)) == -1) { | 611 | + while ((s_rc = select(ctx->s+1, rset, NULL, NULL, tv)) == -1) { |
| 578 | if (errno == EINTR) { | 612 | if (errno == EINTR) { |
| 579 | if (ctx->debug) { | 613 | if (ctx->debug) { |
| 580 | fprintf(stderr, "A non blocked signal was caught\n"); | 614 | fprintf(stderr, "A non blocked signal was caught\n"); |
| 581 | } | 615 | } |
| 582 | /* Necessary after an error */ | 616 | /* Necessary after an error */ |
| 583 | - FD_ZERO(rfds); | ||
| 584 | - FD_SET(ctx->s, rfds); | 617 | + FD_ZERO(rset); |
| 618 | + FD_SET(ctx->s, rset); | ||
| 585 | } else { | 619 | } else { |
| 586 | return -1; | 620 | return -1; |
| 587 | } | 621 | } |
src/modbus.c
| @@ -326,7 +326,7 @@ static int compute_data_length_after_meta(modbus_t *ctx, uint8_t *msg, | @@ -326,7 +326,7 @@ static int compute_data_length_after_meta(modbus_t *ctx, uint8_t *msg, | ||
| 326 | int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type) | 326 | int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type) |
| 327 | { | 327 | { |
| 328 | int rc; | 328 | int rc; |
| 329 | - fd_set rfds; | 329 | + fd_set rset; |
| 330 | struct timeval tv; | 330 | struct timeval tv; |
| 331 | struct timeval *p_tv; | 331 | struct timeval *p_tv; |
| 332 | int length_to_read; | 332 | int length_to_read; |
| @@ -342,8 +342,8 @@ int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type) | @@ -342,8 +342,8 @@ int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type) | ||
| 342 | } | 342 | } |
| 343 | 343 | ||
| 344 | /* Add a file descriptor to the set */ | 344 | /* Add a file descriptor to the set */ |
| 345 | - FD_ZERO(&rfds); | ||
| 346 | - FD_SET(ctx->s, &rfds); | 345 | + FD_ZERO(&rset); |
| 346 | + FD_SET(ctx->s, &rset); | ||
| 347 | 347 | ||
| 348 | /* We need to analyse the message step by step. At the first step, we want | 348 | /* We need to analyse the message step by step. At the first step, we want |
| 349 | * to reach the function code because all packets contain this | 349 | * to reach the function code because all packets contain this |
| @@ -362,7 +362,7 @@ int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type) | @@ -362,7 +362,7 @@ int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type) | ||
| 362 | } | 362 | } |
| 363 | 363 | ||
| 364 | while (length_to_read != 0) { | 364 | while (length_to_read != 0) { |
| 365 | - rc = ctx->backend->select(ctx, &rfds, p_tv, length_to_read); | 365 | + rc = ctx->backend->select(ctx, &rset, p_tv, length_to_read); |
| 366 | if (rc == -1) { | 366 | if (rc == -1) { |
| 367 | _error_print(ctx, "select"); | 367 | _error_print(ctx, "select"); |
| 368 | if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_LINK) { | 368 | if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_LINK) { |