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;