Bugfix in tcp-socket: there were a few corner cases when the tcp-socket state would be messed up, which is fixed with this patch
This commit is contained in:
parent
df2cdbbd79
commit
0f1f12fdc7
@ -41,6 +41,8 @@
|
|||||||
|
|
||||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||||
|
|
||||||
|
static void relisten(struct tcp_socket *s);
|
||||||
|
|
||||||
LIST(socketlist);
|
LIST(socketlist);
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
PROCESS(tcp_socket_process, "TCP socket process");
|
PROCESS(tcp_socket_process, "TCP socket process");
|
||||||
@ -58,8 +60,8 @@ senddata(struct tcp_socket *s)
|
|||||||
{
|
{
|
||||||
int len = MIN(s->output_data_max_seg, uip_mss());
|
int len = MIN(s->output_data_max_seg, uip_mss());
|
||||||
|
|
||||||
if(s->output_data_len > 0) {
|
if(s->output_senddata_len > 0) {
|
||||||
len = MIN(s->output_data_len, len);
|
len = MIN(s->output_senddata_len, len);
|
||||||
s->output_data_send_nxt = len;
|
s->output_data_send_nxt = len;
|
||||||
uip_send(s->output_data_ptr, len);
|
uip_send(s->output_data_ptr, len);
|
||||||
}
|
}
|
||||||
@ -68,21 +70,27 @@ senddata(struct tcp_socket *s)
|
|||||||
static void
|
static void
|
||||||
acked(struct tcp_socket *s)
|
acked(struct tcp_socket *s)
|
||||||
{
|
{
|
||||||
if(s->output_data_len > 0) {
|
if(s->output_senddata_len > 0) {
|
||||||
/* Copy the data in the outputbuf down and update outputbufptr and
|
/* Copy the data in the outputbuf down and update outputbufptr and
|
||||||
outputbuf_lastsent */
|
outputbuf_lastsent */
|
||||||
|
|
||||||
if(s->output_data_send_nxt > 0) {
|
if(s->output_data_send_nxt > 0) {
|
||||||
memcpy(&s->output_data_ptr[0],
|
memcpy(&s->output_data_ptr[0],
|
||||||
&s->output_data_ptr[s->output_data_send_nxt],
|
&s->output_data_ptr[s->output_data_send_nxt],
|
||||||
s->output_data_maxlen - s->output_data_send_nxt);
|
s->output_data_maxlen - s->output_data_send_nxt);
|
||||||
}
|
}
|
||||||
if(s->output_data_len < s->output_data_send_nxt) {
|
if(s->output_data_len < s->output_data_send_nxt) {
|
||||||
printf("tcp: acked assertion failed s->output_data_len (%d) < s->output_data_send_nxt (%d)\n",
|
printf("tcp: acked assertion failed s->output_data_len (%d) < s->output_data_send_nxt (%d)\n",
|
||||||
s->output_data_len,
|
s->output_data_len,
|
||||||
s->output_data_send_nxt);
|
s->output_data_send_nxt);
|
||||||
|
tcp_markconn(uip_conn, NULL);
|
||||||
|
uip_abort();
|
||||||
|
call_event(s, TCP_SOCKET_ABORTED);
|
||||||
|
relisten(s);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
s->output_data_len -= s->output_data_send_nxt;
|
s->output_data_len -= s->output_data_send_nxt;
|
||||||
|
s->output_senddata_len = s->output_data_len;
|
||||||
s->output_data_send_nxt = 0;
|
s->output_data_send_nxt = 0;
|
||||||
|
|
||||||
call_event(s, TCP_SOCKET_DATA_SENT);
|
call_event(s, TCP_SOCKET_DATA_SENT);
|
||||||
@ -134,6 +142,11 @@ appcall(void *state)
|
|||||||
{
|
{
|
||||||
struct tcp_socket *s = state;
|
struct tcp_socket *s = state;
|
||||||
|
|
||||||
|
if(s != NULL && s->c != NULL && s->c != uip_conn) {
|
||||||
|
/* Safe-guard: this should not happen, as the incoming event relates to
|
||||||
|
* a previous connection */
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(uip_connected()) {
|
if(uip_connected()) {
|
||||||
/* Check if this connection originated in a local listen
|
/* Check if this connection originated in a local listen
|
||||||
socket. We do this by checking the state pointer - if NULL,
|
socket. We do this by checking the state pointer - if NULL,
|
||||||
@ -176,8 +189,10 @@ appcall(void *state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(uip_aborted()) {
|
if(uip_aborted()) {
|
||||||
|
tcp_markconn(uip_conn, NULL);
|
||||||
call_event(s, TCP_SOCKET_ABORTED);
|
call_event(s, TCP_SOCKET_ABORTED);
|
||||||
relisten(s);
|
relisten(s);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(s == NULL) {
|
if(s == NULL) {
|
||||||
@ -203,13 +218,16 @@ appcall(void *state)
|
|||||||
if(s->output_data_len == 0 && s->flags & TCP_SOCKET_FLAGS_CLOSING) {
|
if(s->output_data_len == 0 && s->flags & TCP_SOCKET_FLAGS_CLOSING) {
|
||||||
s->flags &= ~TCP_SOCKET_FLAGS_CLOSING;
|
s->flags &= ~TCP_SOCKET_FLAGS_CLOSING;
|
||||||
uip_close();
|
uip_close();
|
||||||
|
s->c = NULL;
|
||||||
tcp_markconn(uip_conn, NULL);
|
tcp_markconn(uip_conn, NULL);
|
||||||
call_event(s, TCP_SOCKET_CLOSED);
|
s->c = NULL;
|
||||||
|
/*call_event(s, TCP_SOCKET_CLOSED);*/
|
||||||
relisten(s);
|
relisten(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(uip_closed()) {
|
if(uip_closed()) {
|
||||||
tcp_markconn(uip_conn, NULL);
|
tcp_markconn(uip_conn, NULL);
|
||||||
|
s->c = NULL;
|
||||||
call_event(s, TCP_SOCKET_CLOSED);
|
call_event(s, TCP_SOCKET_CLOSED);
|
||||||
relisten(s);
|
relisten(s);
|
||||||
}
|
}
|
||||||
@ -255,6 +273,7 @@ tcp_socket_register(struct tcp_socket *s, void *ptr,
|
|||||||
s->ptr = ptr;
|
s->ptr = ptr;
|
||||||
s->input_data_ptr = input_databuf;
|
s->input_data_ptr = input_databuf;
|
||||||
s->input_data_maxlen = input_databuf_len;
|
s->input_data_maxlen = input_databuf_len;
|
||||||
|
s->output_data_len = 0;
|
||||||
s->output_data_ptr = output_databuf;
|
s->output_data_ptr = output_databuf;
|
||||||
s->output_data_maxlen = output_databuf_len;
|
s->output_data_maxlen = output_databuf_len;
|
||||||
s->input_callback = input_callback;
|
s->input_callback = input_callback;
|
||||||
@ -268,12 +287,15 @@ tcp_socket_register(struct tcp_socket *s, void *ptr,
|
|||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
int
|
int
|
||||||
tcp_socket_connect(struct tcp_socket *s,
|
tcp_socket_connect(struct tcp_socket *s,
|
||||||
uip_ipaddr_t *ipaddr,
|
const uip_ipaddr_t *ipaddr,
|
||||||
uint16_t port)
|
uint16_t port)
|
||||||
{
|
{
|
||||||
if(s == NULL) {
|
if(s == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
if(s->c != NULL) {
|
||||||
|
tcp_markconn(s->c, NULL);
|
||||||
|
}
|
||||||
PROCESS_CONTEXT_BEGIN(&tcp_socket_process);
|
PROCESS_CONTEXT_BEGIN(&tcp_socket_process);
|
||||||
s->c = tcp_connect(ipaddr, uip_htons(port), s);
|
s->c = tcp_connect(ipaddr, uip_htons(port), s);
|
||||||
PROCESS_CONTEXT_END();
|
PROCESS_CONTEXT_END();
|
||||||
@ -317,7 +339,7 @@ tcp_socket_unlisten(struct tcp_socket *s)
|
|||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
int
|
int
|
||||||
tcp_socket_send(struct tcp_socket *s,
|
tcp_socket_send(struct tcp_socket *s,
|
||||||
const uint8_t *data, int datalen)
|
const uint8_t *data, int datalen)
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
@ -329,6 +351,11 @@ tcp_socket_send(struct tcp_socket *s,
|
|||||||
|
|
||||||
memcpy(&s->output_data_ptr[s->output_data_len], data, len);
|
memcpy(&s->output_data_ptr[s->output_data_len], data, len);
|
||||||
s->output_data_len += len;
|
s->output_data_len += len;
|
||||||
|
|
||||||
|
if(s->output_senddata_len == 0) {
|
||||||
|
s->output_senddata_len = s->output_data_len;
|
||||||
|
}
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
@ -365,3 +392,9 @@ tcp_socket_unregister(struct tcp_socket *s)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
int
|
||||||
|
tcp_socket_max_sendlen(struct tcp_socket *s)
|
||||||
|
{
|
||||||
|
return s->output_data_maxlen - s->output_data_len;
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
@ -32,6 +32,8 @@
|
|||||||
#ifndef TCP_SOCKET_H
|
#ifndef TCP_SOCKET_H
|
||||||
#define TCP_SOCKET_H
|
#define TCP_SOCKET_H
|
||||||
|
|
||||||
|
#include "uip.h"
|
||||||
|
|
||||||
struct tcp_socket;
|
struct tcp_socket;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -95,6 +97,7 @@ struct tcp_socket {
|
|||||||
uint16_t output_data_maxlen;
|
uint16_t output_data_maxlen;
|
||||||
uint16_t output_data_len;
|
uint16_t output_data_len;
|
||||||
uint16_t output_data_send_nxt;
|
uint16_t output_data_send_nxt;
|
||||||
|
uint16_t output_senddata_len;
|
||||||
uint16_t output_data_max_seg;
|
uint16_t output_data_max_seg;
|
||||||
|
|
||||||
uint8_t flags;
|
uint8_t flags;
|
||||||
@ -170,7 +173,7 @@ int tcp_socket_register(struct tcp_socket *s, void *ptr,
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int tcp_socket_connect(struct tcp_socket *s,
|
int tcp_socket_connect(struct tcp_socket *s,
|
||||||
uip_ipaddr_t *ipaddr,
|
const uip_ipaddr_t *ipaddr,
|
||||||
uint16_t port);
|
uint16_t port);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -266,4 +269,19 @@ int tcp_socket_close(struct tcp_socket *s);
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int tcp_socket_unregister(struct tcp_socket *s);
|
int tcp_socket_unregister(struct tcp_socket *s);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief The maximum amount of data that could currently be sent
|
||||||
|
* \param s A pointer to a TCP socket
|
||||||
|
* \return The number of bytes available in the output buffer
|
||||||
|
*
|
||||||
|
* This function queries the TCP socket and returns the
|
||||||
|
* number of bytes available in the output buffer. This
|
||||||
|
* function is used before calling tcp_socket_send() to
|
||||||
|
* ensure that one application level message can be held
|
||||||
|
* in the output buffer.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int tcp_socket_max_sendlen(struct tcp_socket *s);
|
||||||
|
|
||||||
#endif /* TCP_SOCKET_H */
|
#endif /* TCP_SOCKET_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user