diff --git a/src/core/tcp_conn.h b/src/core/tcp_conn.h index b989e94633b..aaf1f2fcb05 100644 --- a/src/core/tcp_conn.h +++ b/src/core/tcp_conn.h @@ -193,12 +193,22 @@ typedef struct tcp_conn_alias { #endif +enum tcp_closed_reason { + TCP_CLOSED_EOF = 0, + TCP_CLOSED_TIMEOUT, + TCP_CLOSED_RESET, + + _TCP_CLOSED_REASON_MAX /* /!\ keep this one always at the end */ +}; + + typedef struct tcp_connection { int s; /*socket, used by "tcp main" */ int fd; /* used only by "children", don't modify it! private data! */ gen_lock_t write_lock; int id; /* id (unique!) used to retrieve a specific connection when * reply-ing */ + enum tcp_closed_reason event; /* connection close reason */ int reader_pid; /* pid of the active reader process */ struct receive_info rcv; /* src & dst ip, ports, proto a.s.o*/ ksr_coninfo_t cinfo; /* connection info (e.g., for haproxy ) */ @@ -343,14 +353,6 @@ typedef struct tcp_event_info { struct tcp_connection *con; } tcp_event_info_t; -enum tcp_closed_reason { - TCP_CLOSED_EOF = 0, - TCP_CLOSED_TIMEOUT, - TCP_CLOSED_RESET, - - _TCP_CLOSED_REASON_MAX /* /!\ keep this one always at the end */ -}; - typedef struct tcp_closed_event_info { enum tcp_closed_reason reason; struct tcp_connection *con; diff --git a/src/core/tcp_main.c b/src/core/tcp_main.c index f7383252853..1e03ded6b0e 100644 --- a/src/core/tcp_main.c +++ b/src/core/tcp_main.c @@ -3549,11 +3549,18 @@ int _tcpconn_write_nb(int fd, struct tcp_connection* c, } -static int tcp_emit_closed_event(struct tcp_connection *con, enum tcp_closed_reason reason) +static int tcp_emit_closed_event(struct tcp_connection *con) { int ret; tcp_closed_event_info_t tev; sr_event_param_t evp = {0}; + enum tcp_closed_reason reason; + + if (con->event) { + reason = con->event; + } else { + reason = TCP_CLOSED_EOF; + } ret = 0; LM_DBG("TCP closed event creation triggered (reason: %d)\n", reason); @@ -3649,7 +3656,7 @@ inline static int handle_tcp_child(struct tcp_child* tcp_c, int fd_i) /* if refcnt was 1 => it was used only in the tcp reader => it's not hashed or watched for IO anymore => no need to io_watch_del() */ - tcp_emit_closed_event(tcpconn, TCP_CLOSED_EOF); + tcp_emit_closed_event(tcpconn); tcpconn_destroy(tcpconn); break; } @@ -3661,7 +3668,7 @@ inline static int handle_tcp_child(struct tcp_child* tcp_c, int fd_i) tcpconn->flags &= ~F_CONN_WRITE_W; } #endif /* TCP_ASYNC */ - tcp_emit_closed_event(tcpconn, TCP_CLOSED_EOF); + tcp_emit_closed_event(tcpconn); tcpconn_put_destroy(tcpconn); } #ifdef TCP_ASYNC @@ -3713,7 +3720,8 @@ inline static int handle_tcp_child(struct tcp_child* tcp_c, int fd_i) io_watch_del(&io_h, tcpconn->s, -1, IO_FD_CLOSING); tcpconn->flags&=~F_CONN_WRITE_W; } - tcp_emit_closed_event(tcpconn, TCP_CLOSED_EOF); + tcpconn->event = TCP_CLOSED_TIMEOUT; + tcp_emit_closed_event(tcpconn); tcpconn_put_destroy(tcpconn); } else if (unlikely(tcpconn->flags & F_CONN_WRITE_W)){ BUG("unhashed connection watched for write\n"); @@ -3750,7 +3758,7 @@ inline static int handle_tcp_child(struct tcp_child* tcp_c, int fd_i) tcpconn->flags&=~F_CONN_WRITE_W; } #endif /* TCP_ASYNC */ - tcp_emit_closed_event(tcpconn, TCP_CLOSED_EOF); + tcp_emit_closed_event(tcpconn); tcpconn_put_destroy(tcpconn); } #ifdef TCP_ASYNC @@ -3782,7 +3790,7 @@ inline static int handle_tcp_child(struct tcp_child* tcp_c, int fd_i) #endif /* TCP_ASYNC */ if (tcpconn_try_unhash(tcpconn)) tcpconn_put(tcpconn); - tcp_emit_closed_event(tcpconn, TCP_CLOSED_EOF); + tcp_emit_closed_event(tcpconn); tcpconn_put_destroy(tcpconn); /* deref & delete if refcnt==0 */ break; default: diff --git a/src/core/tcp_read.c b/src/core/tcp_read.c index db8e1025018..0adbf89dfda 100644 --- a/src/core/tcp_read.c +++ b/src/core/tcp_read.c @@ -268,6 +268,11 @@ int tcp_read_data(int fd, struct tcp_connection *c, ip_addr2a(&c->rcv.src_ip), c->rcv.src_port); LOG(cfg_get(core, core_cfg, corelog),"-> [%s]:%u)\n", ip_addr2a(&c->rcv.dst_ip), c->rcv.dst_port); + if (errno == ETIMEDOUT) { + c->event = TCP_CLOSED_TIMEOUT; + } else if (errno == ECONNRESET) { + c->event = TCP_CLOSED_RESET; + } return -1; } }else if (unlikely((bytes_read==0) || @@ -279,6 +284,7 @@ int tcp_read_data(int fd, struct tcp_connection *c, ip_addr2a(&c->rcv.dst_ip), c->rcv.dst_port); c->state=S_CONN_EOF; *flags|=RD_CONN_EOF; + c->event=TCP_CLOSED_EOF; }else{ if (unlikely(c->state==S_CONN_CONNECT || c->state==S_CONN_ACCEPT)){ TCP_STATS_ESTABLISHED(c->state); @@ -1670,6 +1676,7 @@ static ticks_t tcpconn_read_timeout(ticks_t t, struct timer_ln* tl, void* data) } if(tcp_conn_lst!=NULL) { tcpconn_listrm(tcp_conn_lst, c, c_next, c_prev); + c->event = TCP_CLOSED_TIMEOUT; release_tcpconn(c, (c->state<0)?CONN_ERROR:CONN_RELEASE, tcpmain_sock); } return 0;