Browse Source

tcp_comm: Rework receive handling

Now whatever arrives will get stored, and then used up by as many stages
as possible.
Brian Starkey 2 years ago
parent
commit
8a71b096b9
1 changed files with 35 additions and 18 deletions
  1. 35
    18
      tcp_comm.c

+ 35
- 18
tcp_comm.c View File

@@ -37,9 +37,13 @@ struct tcp_comm_ctx {
37 37
 	enum conn_state conn_state;
38 38
 
39 39
 	struct tcp_pcb *client_pcb;
40
+	// Note: sizeof(buf) is used elsewhere, so if this is changed to not
41
+	// be an array, those will need updating
40 42
 	uint8_t buf[(sizeof(uint32_t) * (1 + COMM_MAX_NARG)) + TCP_COMM_MAX_DATA_LEN];
43
+
44
+	uint16_t rx_start_offs;
41 45
 	uint16_t rx_bytes_received;
42
-	uint16_t rx_bytes_remaining;
46
+	uint16_t rx_bytes_needed;
43 47
 
44 48
 	uint16_t tx_bytes_sent;
45 49
 	uint16_t tx_bytes_remaining;
@@ -89,10 +93,7 @@ static int tcp_comm_error_begin(struct tcp_comm_ctx *ctx);
89 93
 static int tcp_comm_sync_begin(struct tcp_comm_ctx *ctx)
90 94
 {
91 95
 	ctx->conn_state = CONN_STATE_WAIT_FOR_SYNC;
92
-	ctx->rx_bytes_received = 0;
93
-	ctx->rx_bytes_remaining = sizeof(uint32_t);
94
-
95
-	DEBUG_printf("sync_begin %d\n", ctx->rx_bytes_remaining);
96
+	ctx->rx_bytes_needed = sizeof(uint32_t);
96 97
 }
97 98
 
98 99
 static int tcp_comm_sync_complete(struct tcp_comm_ctx *ctx)
@@ -108,8 +109,7 @@ static int tcp_comm_sync_complete(struct tcp_comm_ctx *ctx)
108 109
 static int tcp_comm_opcode_begin(struct tcp_comm_ctx *ctx)
109 110
 {
110 111
 	ctx->conn_state = CONN_STATE_READ_OPCODE;
111
-	ctx->rx_bytes_received = 0;
112
-	ctx->rx_bytes_remaining = sizeof(uint32_t);
112
+	ctx->rx_bytes_needed = sizeof(uint32_t);
113 113
 
114 114
 	return 0;
115 115
 }
@@ -130,8 +130,7 @@ static int tcp_comm_opcode_complete(struct tcp_comm_ctx *ctx)
130 130
 static int tcp_comm_args_begin(struct tcp_comm_ctx *ctx)
131 131
 {
132 132
 	ctx->conn_state = CONN_STATE_READ_ARGS;
133
-	ctx->rx_bytes_received = 0;
134
-	ctx->rx_bytes_remaining = ctx->cmd->nargs * sizeof(uint32_t);
133
+	ctx->rx_bytes_needed = ctx->cmd->nargs * sizeof(uint32_t);
135 134
 
136 135
 	if (ctx->cmd->nargs == 0) {
137 136
 		return tcp_comm_args_complete(ctx);
@@ -163,8 +162,7 @@ static int tcp_comm_data_begin(struct tcp_comm_ctx *ctx, uint32_t data_len)
163 162
 	const struct comm_command *cmd = ctx->cmd;
164 163
 
165 164
 	ctx->conn_state = CONN_STATE_READ_DATA;
166
-	ctx->rx_bytes_received = 0;
167
-	ctx->rx_bytes_remaining = data_len;
165
+	ctx->rx_bytes_needed = data_len;
168 166
 
169 167
 	if (data_len == 0) {
170 168
 		return tcp_comm_data_complete(ctx);
@@ -378,8 +376,10 @@ static err_t tcp_comm_client_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *
378 376
 	if (p->tot_len > 0) {
379 377
 		DEBUG_printf("tcp_comm_server_recv %d err %d\n", p->tot_len, err);
380 378
 
381
-		if (p->tot_len > ctx->rx_bytes_remaining) {
382
-			DEBUG_printf("more data than expected: %d vs %d\n", p->tot_len, ctx->rx_bytes_remaining);
379
+		if (p->tot_len > (sizeof(ctx->buf) - ctx->rx_bytes_received)) {
380
+			// Doesn't fit in buffer at all. Protocol error.
381
+			DEBUG_printf("not enough space in buffer: %d vs %d\n", p->tot_len, sizeof(ctx->buf) - ctx->rx_bytes_received);
382
+
383 383
 			// TODO: Invoking the error response state here feels
384 384
 			// like a bit of a layering violation, but this is a
385 385
 			// protocol error, rather than a failure in the stack
@@ -389,23 +389,40 @@ static err_t tcp_comm_client_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *
389 389
 				return tcp_comm_client_complete(ctx, ERR_ARG);
390 390
 			}
391 391
 			return ERR_OK;
392
+		} else if (p->tot_len > (sizeof(ctx->buf) - (ctx->rx_start_offs + ctx->rx_bytes_received))) {
393
+			// There will be space, but we need to shift the data back
394
+			// to the start of the buffer
395
+			DEBUG_printf("memmove %d bytes to make space for %d bytes\n", ctx->rx_bytes_received, p->tot_len);
396
+			memmove(ctx->buf, ctx->buf + ctx->rx_start_offs, ctx->rx_bytes_received);
397
+			ctx->rx_start_offs = 0;
392 398
 		}
393 399
 
394
-		// Receive the buffer
395
-		if (pbuf_copy_partial(p, ctx->buf + ctx->rx_bytes_received, p->tot_len, 0) != p->tot_len) {
400
+		uint8_t *dst = ctx->buf + ctx->rx_start_offs + ctx->rx_bytes_received;
401
+
402
+		// We can always handle the full packet
403
+		if (pbuf_copy_partial(p, dst, p->tot_len, 0) != p->tot_len) {
396 404
 			DEBUG_printf("wrong copy len\n");
397 405
 			return tcp_comm_client_complete(ctx, ERR_ARG);
398 406
 		}
399 407
 
400 408
 		ctx->rx_bytes_received += p->tot_len;
401
-		ctx->rx_bytes_remaining -= p->tot_len;
402 409
 		tcp_recved(tpcb, p->tot_len);
403 410
 
404
-		if (ctx->rx_bytes_remaining == 0) {
411
+		while (ctx->rx_bytes_received >= ctx->rx_bytes_needed) {
412
+			uint16_t consumed = ctx->rx_bytes_needed;
413
+
405 414
 			int res = tcp_comm_rx_complete(ctx);
406 415
 			if (res) {
407 416
 				return tcp_comm_client_complete(ctx, ERR_ARG);
408 417
 			}
418
+
419
+			ctx->rx_start_offs += consumed;
420
+			ctx->rx_bytes_received -= consumed;
421
+
422
+			if (ctx->rx_bytes_received == 0) {
423
+				ctx->rx_start_offs = 0;
424
+				break;
425
+			}
409 426
 		}
410 427
 	}
411 428
 	pbuf_free(p);
@@ -427,7 +444,7 @@ static void tcp_comm_client_err(void *arg, err_t err)
427 444
 
428 445
 	ctx->client_pcb = NULL;
429 446
 	ctx->conn_state = CONN_STATE_CLOSED;
430
-	ctx->rx_bytes_remaining = 0;
447
+	ctx->rx_bytes_needed = 0;
431 448
 	cyw43_arch_gpio_put (0, false);
432 449
 }
433 450
 

Loading…
Cancel
Save