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 1 year 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
 	enum conn_state conn_state;
37
 	enum conn_state conn_state;
38
 
38
 
39
 	struct tcp_pcb *client_pcb;
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
 	uint8_t buf[(sizeof(uint32_t) * (1 + COMM_MAX_NARG)) + TCP_COMM_MAX_DATA_LEN];
42
 	uint8_t buf[(sizeof(uint32_t) * (1 + COMM_MAX_NARG)) + TCP_COMM_MAX_DATA_LEN];
43
+
44
+	uint16_t rx_start_offs;
41
 	uint16_t rx_bytes_received;
45
 	uint16_t rx_bytes_received;
42
-	uint16_t rx_bytes_remaining;
46
+	uint16_t rx_bytes_needed;
43
 
47
 
44
 	uint16_t tx_bytes_sent;
48
 	uint16_t tx_bytes_sent;
45
 	uint16_t tx_bytes_remaining;
49
 	uint16_t tx_bytes_remaining;
89
 static int tcp_comm_sync_begin(struct tcp_comm_ctx *ctx)
93
 static int tcp_comm_sync_begin(struct tcp_comm_ctx *ctx)
90
 {
94
 {
91
 	ctx->conn_state = CONN_STATE_WAIT_FOR_SYNC;
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
 static int tcp_comm_sync_complete(struct tcp_comm_ctx *ctx)
99
 static int tcp_comm_sync_complete(struct tcp_comm_ctx *ctx)
108
 static int tcp_comm_opcode_begin(struct tcp_comm_ctx *ctx)
109
 static int tcp_comm_opcode_begin(struct tcp_comm_ctx *ctx)
109
 {
110
 {
110
 	ctx->conn_state = CONN_STATE_READ_OPCODE;
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
 	return 0;
114
 	return 0;
115
 }
115
 }
130
 static int tcp_comm_args_begin(struct tcp_comm_ctx *ctx)
130
 static int tcp_comm_args_begin(struct tcp_comm_ctx *ctx)
131
 {
131
 {
132
 	ctx->conn_state = CONN_STATE_READ_ARGS;
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
 	if (ctx->cmd->nargs == 0) {
135
 	if (ctx->cmd->nargs == 0) {
137
 		return tcp_comm_args_complete(ctx);
136
 		return tcp_comm_args_complete(ctx);
163
 	const struct comm_command *cmd = ctx->cmd;
162
 	const struct comm_command *cmd = ctx->cmd;
164
 
163
 
165
 	ctx->conn_state = CONN_STATE_READ_DATA;
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
 	if (data_len == 0) {
167
 	if (data_len == 0) {
170
 		return tcp_comm_data_complete(ctx);
168
 		return tcp_comm_data_complete(ctx);
378
 	if (p->tot_len > 0) {
376
 	if (p->tot_len > 0) {
379
 		DEBUG_printf("tcp_comm_server_recv %d err %d\n", p->tot_len, err);
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
 			// TODO: Invoking the error response state here feels
383
 			// TODO: Invoking the error response state here feels
384
 			// like a bit of a layering violation, but this is a
384
 			// like a bit of a layering violation, but this is a
385
 			// protocol error, rather than a failure in the stack
385
 			// protocol error, rather than a failure in the stack
389
 				return tcp_comm_client_complete(ctx, ERR_ARG);
389
 				return tcp_comm_client_complete(ctx, ERR_ARG);
390
 			}
390
 			}
391
 			return ERR_OK;
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
 			DEBUG_printf("wrong copy len\n");
404
 			DEBUG_printf("wrong copy len\n");
397
 			return tcp_comm_client_complete(ctx, ERR_ARG);
405
 			return tcp_comm_client_complete(ctx, ERR_ARG);
398
 		}
406
 		}
399
 
407
 
400
 		ctx->rx_bytes_received += p->tot_len;
408
 		ctx->rx_bytes_received += p->tot_len;
401
-		ctx->rx_bytes_remaining -= p->tot_len;
402
 		tcp_recved(tpcb, p->tot_len);
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
 			int res = tcp_comm_rx_complete(ctx);
414
 			int res = tcp_comm_rx_complete(ctx);
406
 			if (res) {
415
 			if (res) {
407
 				return tcp_comm_client_complete(ctx, ERR_ARG);
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
 	pbuf_free(p);
428
 	pbuf_free(p);
427
 
444
 
428
 	ctx->client_pcb = NULL;
445
 	ctx->client_pcb = NULL;
429
 	ctx->conn_state = CONN_STATE_CLOSED;
446
 	ctx->conn_state = CONN_STATE_CLOSED;
430
-	ctx->rx_bytes_remaining = 0;
447
+	ctx->rx_bytes_needed = 0;
431
 	cyw43_arch_gpio_put (0, false);
448
 	cyw43_arch_gpio_put (0, false);
432
 }
449
 }
433
 
450
 

Loading…
Cancel
Save