AmendHub

Download:

jcs

/

subtext

/

amendments

/

534

binkp: Check for a dead TCP connection in many places

Previously if the connection dropped in the middle of fetching, we
may have been sitting in a loop forever (though still yielding, so
it was just killing the binkp/task thread).

jcs made amendment 534 about 1 year ago
--- binkp.c Thu Nov 9 09:48:19 2023 +++ binkp.c Fri Nov 10 17:08:42 2023 @@ -29,6 +29,10 @@ /* #define BINKP_DEBUG */ +#define BINKP_CONNECTION_ALIVE(bpc) \ + (bpc->tcp_status_pb.connectionState == ConnectionStateEstablished || \ + bpc->tcp_status_pb.connectionState == ConnectionStateCloseWait) + bool binkp_ready = false; time_t binkp_next_poll = 0; @@ -132,7 +136,7 @@ binkp_poll(void) if (!binkp_login()) goto done; - while (binkpc != NULL && !binkpc->done_receiving) { + while (binkpc != NULL && !binkpc->done_receiving && !binkpc->error) { binkp_read_frame(); uthread_yield(); } @@ -267,9 +271,16 @@ binkp_send_frame(short command, char *data, size_t dat return 0; } - while (binkpc->tcp_send_iopb.ioResult > 0) + while (binkpc->tcp_send_iopb.ioResult > 0) { /* previous _TCPSend has not completed yet */ + if (!BINKP_CONNECTION_ALIVE(binkpc)) { + binkpc->error = true; + logger_printf("[binkp] Connection lost (%d) while sending frame", + binkpc->tcp_status_pb.connectionState); + return false; + } uthread_yield(); + } if (command == BINKP_DATA) { binkpc->buf[0] = (data_size >> 8) & 0xff; @@ -342,8 +353,17 @@ binkp_read_frame(void) error = _TCPStatus(&binkpc->tcp_read_iopb, binkpc->tcp_stream, &binkpc->tcp_status_pb, nil, nil, false); - if (error) + if (error) { + binkpc->error = true; return false; + } + + if (!BINKP_CONNECTION_ALIVE(binkpc)) { + logger_printf("[binkp] Connection lost (%d) while reading frame", + binkpc->tcp_status_pb.connectionState); + binkpc->error = true; + return false; + } if (binkpc->tcp_status_pb.amtUnreadData < 2) return false; @@ -351,8 +371,10 @@ binkp_read_frame(void) rlen = 2; error = _TCPRcv(&binkpc->tcp_read_iopb, binkpc->tcp_stream, (Ptr)&binkpc->cur_frame, &rlen, nil, nil, false); - if (error) + if (error) { + binkpc->error = true; return false; + } if (binkpc->cur_frame.data_size == 0) { logger_printf("[binkp] Received bogus frame, no data_size"); @@ -371,6 +393,12 @@ binkp_read_frame(void) if (error) goto failed_read; + if (!BINKP_CONNECTION_ALIVE(binkpc)) { + logger_printf("[binkp] Connection lost (%d) while reading frame", + binkpc->tcp_status_pb.connectionState); + goto failed_read; + } + if (binkpc->tcp_status_pb.amtUnreadData == 0) { uthread_yield(); continue; @@ -575,6 +603,7 @@ failed_read: binkpc->cur_incoming_file.frefnum = 0; } binkpc->done_receiving = binkpc->done_sending = true; + binkpc->error = true; return false; } @@ -584,9 +613,13 @@ binkp_login(void) char command[50]; size_t len; + /* discard early frames */ while (binkpc != NULL && binkp_read_frame()) ; + if (!binkpc || binkpc->error) + return false; + len = snprintf(command, sizeof(command), "SYS %s", db->config.name); if (!binkp_send_frame(BINKP_COMMAND_M_NUL, command, len)) return false; @@ -612,7 +645,7 @@ binkp_login(void) strlen(db->config.binkp_password))) return false; - while (binkpc) { + while (binkpc && !binkpc->error) { if (!binkp_read_frame()) { uthread_yield(); continue; @@ -984,12 +1017,12 @@ binkp_deliver_outbox(void) frefnum = 0; /* wait for frame */ - while (binkpc != NULL && !binkp_read_frame()) { + while (binkpc != NULL && !binkp_read_frame() && !binkpc->error) { uthread_yield(); continue; } - if (!binkpc) { + if (!binkpc || binkpc->error) { logger_printf("[binkp] Connection lost waiting for M_GOT"); goto done; } --- binkp.h Thu Nov 9 09:47:58 2023 +++ binkp.h Fri Nov 10 16:46:53 2023 @@ -66,6 +66,7 @@ struct binkp_connection { struct binkp_file cur_incoming_file; bool done_receiving; bool done_sending; + bool error; }; extern bool binkp_ready;