Commit 31577bbb41064a111be9b84bed79df36f3fe3443
Committed by
Stéphane Raimbault
1 parent
2f0b8355
Introduced select() operation for backends
Introduced the select() operation for backends as the WAIT_DATA macro approach is not very extensible and causes trouble when adding platform- specific codepaths. Signed-off-by: Stéphane Raimbault <stephane.raimbault@gmail.com>
Showing
4 changed files
with
97 additions
and
41 deletions
src/modbus-private.h
| @@ -85,6 +85,7 @@ typedef struct _modbus_backend { | @@ -85,6 +85,7 @@ typedef struct _modbus_backend { | ||
| 85 | int (*flush) (modbus_t *ctx); | 85 | int (*flush) (modbus_t *ctx); |
| 86 | int (*listen) (modbus_t *ctx, int nb_connection); | 86 | int (*listen) (modbus_t *ctx, int nb_connection); |
| 87 | int (*accept) (modbus_t *ctx, int *socket); | 87 | int (*accept) (modbus_t *ctx, int *socket); |
| 88 | + int (*select) (modbus_t *ctx, fd_set *rfds, struct timeval *tv, int msg_length_computed, int msg_length); | ||
| 88 | int (*filter_request) (modbus_t *ctx, int slave); | 89 | int (*filter_request) (modbus_t *ctx, int slave); |
| 89 | } modbus_backend_t; | 90 | } modbus_backend_t; |
| 90 | 91 |
src/modbus-rtu.c
| @@ -485,6 +485,49 @@ int _modbus_rtu_accept(modbus_t *ctx, int *socket) | @@ -485,6 +485,49 @@ int _modbus_rtu_accept(modbus_t *ctx, int *socket) | ||
| 485 | return -1; | 485 | return -1; |
| 486 | } | 486 | } |
| 487 | 487 | ||
| 488 | +int _modbus_rtu_select(modbus_t *ctx, fd_set *rfds, struct timeval *tv, int msg_length_computed, int msg_length) | ||
| 489 | +{ | ||
| 490 | + int s_rc; | ||
| 491 | + while ((s_rc = select(ctx->s+1, rfds, NULL, NULL, tv)) == -1) { | ||
| 492 | + if (errno == EINTR) { | ||
| 493 | + if (ctx->debug) { | ||
| 494 | + fprintf(stderr, "A non blocked signal was caught\n"); | ||
| 495 | + } | ||
| 496 | + /* Necessary after an error */ | ||
| 497 | + FD_ZERO(rfds); | ||
| 498 | + FD_SET(ctx->s, rfds); | ||
| 499 | + } else { | ||
| 500 | + _error_print(ctx, "select"); | ||
| 501 | + if (ctx->error_recovery && (errno == EBADF)) { | ||
| 502 | + modbus_close(ctx); | ||
| 503 | + modbus_connect(ctx); | ||
| 504 | + errno = EBADF; | ||
| 505 | + return -1; | ||
| 506 | + } else { | ||
| 507 | + return -1; | ||
| 508 | + } | ||
| 509 | + } | ||
| 510 | + } | ||
| 511 | + | ||
| 512 | + if (s_rc == 0) { | ||
| 513 | + /* Timeout */ | ||
| 514 | + if (msg_length == (ctx->backend->header_length + 2 + | ||
| 515 | + ctx->backend->checksum_length)) { | ||
| 516 | + /* Optimization allowed because exception response is | ||
| 517 | + the smallest trame in modbus protocol (3) so always | ||
| 518 | + raise a timeout error. | ||
| 519 | + Temporary error before exception analyze. */ | ||
| 520 | + errno = EMBUNKEXC; | ||
| 521 | + } else { | ||
| 522 | + errno = ETIMEDOUT; | ||
| 523 | + _error_print(ctx, "select"); | ||
| 524 | + } | ||
| 525 | + return -1; | ||
| 526 | + } | ||
| 527 | + | ||
| 528 | + return s_rc; | ||
| 529 | +} | ||
| 530 | + | ||
| 488 | int _modbus_rtu_filter_request(modbus_t *ctx, int slave) | 531 | int _modbus_rtu_filter_request(modbus_t *ctx, int slave) |
| 489 | { | 532 | { |
| 490 | /* Filter on the Modbus unit identifier (slave) in RTU mode */ | 533 | /* Filter on the Modbus unit identifier (slave) in RTU mode */ |
| @@ -518,6 +561,7 @@ const modbus_backend_t _modbus_rtu_backend = { | @@ -518,6 +561,7 @@ const modbus_backend_t _modbus_rtu_backend = { | ||
| 518 | _modbus_rtu_flush, | 561 | _modbus_rtu_flush, |
| 519 | _modbus_rtu_listen, | 562 | _modbus_rtu_listen, |
| 520 | _modbus_rtu_accept, | 563 | _modbus_rtu_accept, |
| 564 | + _modbus_rtu_select, | ||
| 521 | _modbus_rtu_filter_request | 565 | _modbus_rtu_filter_request |
| 522 | }; | 566 | }; |
| 523 | 567 |
src/modbus-tcp.c
| @@ -297,6 +297,49 @@ int _modbus_tcp_accept(modbus_t *ctx, int *socket) | @@ -297,6 +297,49 @@ int _modbus_tcp_accept(modbus_t *ctx, int *socket) | ||
| 297 | return ctx->s; | 297 | return ctx->s; |
| 298 | } | 298 | } |
| 299 | 299 | ||
| 300 | +int _modbus_tcp_select(modbus_t *ctx, fd_set *rfds, struct timeval *tv, int msg_length_computed, int msg_length) | ||
| 301 | +{ | ||
| 302 | + int s_rc; | ||
| 303 | + while ((s_rc = select(ctx->s+1, rfds, NULL, NULL, tv)) == -1) { | ||
| 304 | + if (errno == EINTR) { | ||
| 305 | + if (ctx->debug) { | ||
| 306 | + fprintf(stderr, "A non blocked signal was caught\n"); | ||
| 307 | + } | ||
| 308 | + /* Necessary after an error */ | ||
| 309 | + FD_ZERO(rfds); | ||
| 310 | + FD_SET(ctx->s, rfds); | ||
| 311 | + } else { | ||
| 312 | + _error_print(ctx, "select"); | ||
| 313 | + if (ctx->error_recovery && (errno == EBADF)) { | ||
| 314 | + modbus_close(ctx); | ||
| 315 | + modbus_connect(ctx); | ||
| 316 | + errno = EBADF; | ||
| 317 | + return -1; | ||
| 318 | + } else { | ||
| 319 | + return -1; | ||
| 320 | + } | ||
| 321 | + } | ||
| 322 | + } | ||
| 323 | + | ||
| 324 | + if (s_rc == 0) { | ||
| 325 | + /* Timeout */ | ||
| 326 | + if (msg_length == (ctx->backend->header_length + 2 + | ||
| 327 | + ctx->backend->checksum_length)) { | ||
| 328 | + /* Optimization allowed because exception response is | ||
| 329 | + the smallest trame in modbus protocol (3) so always | ||
| 330 | + raise a timeout error. | ||
| 331 | + Temporary error before exception analyze. */ | ||
| 332 | + errno = EMBUNKEXC; | ||
| 333 | + } else { | ||
| 334 | + errno = ETIMEDOUT; | ||
| 335 | + _error_print(ctx, "select"); | ||
| 336 | + } | ||
| 337 | + return -1; | ||
| 338 | + } | ||
| 339 | + | ||
| 340 | + return s_rc; | ||
| 341 | +} | ||
| 342 | + | ||
| 300 | int _modbus_tcp_filter_request(modbus_t *ctx, int slave) | 343 | int _modbus_tcp_filter_request(modbus_t *ctx, int slave) |
| 301 | { | 344 | { |
| 302 | return 0; | 345 | return 0; |
| @@ -320,6 +363,7 @@ const modbus_backend_t _modbus_tcp_backend = { | @@ -320,6 +363,7 @@ const modbus_backend_t _modbus_tcp_backend = { | ||
| 320 | _modbus_tcp_flush, | 363 | _modbus_tcp_flush, |
| 321 | _modbus_tcp_listen, | 364 | _modbus_tcp_listen, |
| 322 | _modbus_tcp_accept, | 365 | _modbus_tcp_accept, |
| 366 | + _modbus_tcp_select, | ||
| 323 | _modbus_tcp_filter_request | 367 | _modbus_tcp_filter_request |
| 324 | }; | 368 | }; |
| 325 | 369 |
src/modbus.c
| @@ -226,44 +226,6 @@ static int compute_data_length(modbus_t *ctx, uint8_t *msg) | @@ -226,44 +226,6 @@ static int compute_data_length(modbus_t *ctx, uint8_t *msg) | ||
| 226 | return length; | 226 | return length; |
| 227 | } | 227 | } |
| 228 | 228 | ||
| 229 | -#define WAIT_DATA() { \ | ||
| 230 | - while ((s_rc = select(ctx->s+1, &rfds, NULL, NULL, &tv)) == -1) { \ | ||
| 231 | - if (errno == EINTR) { \ | ||
| 232 | - if (ctx->debug) { \ | ||
| 233 | - fprintf(stderr, "A non blocked signal was caught\n"); \ | ||
| 234 | - } \ | ||
| 235 | - /* Necessary after an error */ \ | ||
| 236 | - FD_ZERO(&rfds); \ | ||
| 237 | - FD_SET(ctx->s, &rfds); \ | ||
| 238 | - } else { \ | ||
| 239 | - _error_print(ctx, "select"); \ | ||
| 240 | - if (ctx->error_recovery && (errno == EBADF)) { \ | ||
| 241 | - modbus_close(ctx); \ | ||
| 242 | - modbus_connect(ctx); \ | ||
| 243 | - errno = EBADF; \ | ||
| 244 | - return -1; \ | ||
| 245 | - } else { \ | ||
| 246 | - return -1; \ | ||
| 247 | - } \ | ||
| 248 | - } \ | ||
| 249 | - } \ | ||
| 250 | - \ | ||
| 251 | - if (s_rc == 0) { \ | ||
| 252 | - /* Timeout */ \ | ||
| 253 | - if (msg_length == (ctx->backend->header_length + 2 + \ | ||
| 254 | - ctx->backend->checksum_length)) { \ | ||
| 255 | - /* Optimization allowed because exception response is \ | ||
| 256 | - the smallest trame in modbus protocol (3) so always \ | ||
| 257 | - raise a timeout error. \ | ||
| 258 | - Temporary error before exception analyze. */ \ | ||
| 259 | - errno = EMBUNKEXC; \ | ||
| 260 | - } else { \ | ||
| 261 | - errno = ETIMEDOUT; \ | ||
| 262 | - _error_print(ctx, "select"); \ | ||
| 263 | - } \ | ||
| 264 | - return -1; \ | ||
| 265 | - } \ | ||
| 266 | -} | ||
| 267 | 229 | ||
| 268 | /* Waits a response from a modbus server or a request from a modbus client. | 230 | /* Waits a response from a modbus server or a request from a modbus client. |
| 269 | This function blocks if there is no replies (3 timeouts). | 231 | This function blocks if there is no replies (3 timeouts). |
| @@ -330,8 +292,10 @@ static int receive_msg(modbus_t *ctx, int msg_length_computed, | @@ -330,8 +292,10 @@ static int receive_msg(modbus_t *ctx, int msg_length_computed, | ||
| 330 | 292 | ||
| 331 | length_to_read = msg_length_computed; | 293 | length_to_read = msg_length_computed; |
| 332 | 294 | ||
| 333 | - s_rc = 0; | ||
| 334 | - WAIT_DATA(); | 295 | + s_rc = ctx->backend->select(ctx, &rfds, &tv, msg_length_computed, msg_length); |
| 296 | + if (s_rc == -1) { | ||
| 297 | + return -1; | ||
| 298 | + } | ||
| 335 | 299 | ||
| 336 | p_msg = msg; | 300 | p_msg = msg; |
| 337 | while (s_rc) { | 301 | while (s_rc) { |
| @@ -405,7 +369,10 @@ static int receive_msg(modbus_t *ctx, int msg_length_computed, | @@ -405,7 +369,10 @@ static int receive_msg(modbus_t *ctx, int msg_length_computed, | ||
| 405 | tv.tv_sec = ctx->timeout_end.tv_sec; | 369 | tv.tv_sec = ctx->timeout_end.tv_sec; |
| 406 | tv.tv_usec = ctx->timeout_end.tv_usec; | 370 | tv.tv_usec = ctx->timeout_end.tv_usec; |
| 407 | 371 | ||
| 408 | - WAIT_DATA(); | 372 | + s_rc = ctx->backend->select(ctx, &rfds, &tv, msg_length_computed, msg_length); |
| 373 | + if (s_rc == -1) { | ||
| 374 | + return -1; | ||
| 375 | + } | ||
| 409 | } else { | 376 | } else { |
| 410 | /* All chars are received */ | 377 | /* All chars are received */ |
| 411 | s_rc = FALSE; | 378 | s_rc = FALSE; |