diff --git a/binaries/aarch64/tpws b/binaries/aarch64/tpws index 404d619..b3149de 100755 Binary files a/binaries/aarch64/tpws and b/binaries/aarch64/tpws differ diff --git a/binaries/arm/tpws b/binaries/arm/tpws index 6a13bfb..277b38f 100755 Binary files a/binaries/arm/tpws and b/binaries/arm/tpws differ diff --git a/binaries/freebsd-x64/tpws b/binaries/freebsd-x64/tpws index 93f70ee..e3479c5 100755 Binary files a/binaries/freebsd-x64/tpws and b/binaries/freebsd-x64/tpws differ diff --git a/binaries/mac64/tpws b/binaries/mac64/tpws index 40d9e1a..98125df 100755 Binary files a/binaries/mac64/tpws and b/binaries/mac64/tpws differ diff --git a/binaries/mips32r1-lsb/tpws b/binaries/mips32r1-lsb/tpws index 52bcd3d..d96e5d9 100755 Binary files a/binaries/mips32r1-lsb/tpws and b/binaries/mips32r1-lsb/tpws differ diff --git a/binaries/mips32r1-msb/tpws b/binaries/mips32r1-msb/tpws index faaa359..7045e6c 100755 Binary files a/binaries/mips32r1-msb/tpws and b/binaries/mips32r1-msb/tpws differ diff --git a/binaries/mips64r2-msb/tpws b/binaries/mips64r2-msb/tpws index a9aa3af..f903fbb 100755 Binary files a/binaries/mips64r2-msb/tpws and b/binaries/mips64r2-msb/tpws differ diff --git a/binaries/ppc/tpws b/binaries/ppc/tpws index 3286077..7624a42 100755 Binary files a/binaries/ppc/tpws and b/binaries/ppc/tpws differ diff --git a/binaries/x86/tpws b/binaries/x86/tpws index c210d86..d9fe7e7 100755 Binary files a/binaries/x86/tpws and b/binaries/x86/tpws differ diff --git a/binaries/x86_64/tpws b/binaries/x86_64/tpws index 7ae9db0..405eb47 100755 Binary files a/binaries/x86_64/tpws and b/binaries/x86_64/tpws differ diff --git a/binaries/x86_64/tpws_wsl.tgz b/binaries/x86_64/tpws_wsl.tgz index da48107..1140d3f 100644 Binary files a/binaries/x86_64/tpws_wsl.tgz and b/binaries/x86_64/tpws_wsl.tgz differ diff --git a/tpws/tpws_conn.c b/tpws/tpws_conn.c index 9ee4e29..c14dcdf 100644 --- a/tpws/tpws_conn.c +++ b/tpws/tpws_conn.c @@ -260,6 +260,12 @@ static bool conn_has_unsent_pair(tproxy_conn_t *conn) return conn_has_unsent(conn) || (conn_partner_alive(conn) && conn_has_unsent(conn->partner)); } +static void conn_shutdown(tproxy_conn_t *conn) +{ + if (shutdown(conn->fd,SHUT_WR)<0) + DLOG_PERROR("shutdown"); + conn->bShutdown = true; +} static ssize_t send_or_buffer(send_buffer_t *sb, int fd, const void *buf, size_t len, int flags, int ttl) { @@ -518,10 +524,10 @@ static bool epoll_update_flow(tproxy_conn_t *conn) { if (conn->bFlowInPrev==conn->bFlowIn && conn->bFlowOutPrev==conn->bFlowOut && conn->bPrevRdhup==(conn->state==CONN_RDHUP)) return true; // unchanged, no need to syscall + DBGPRINT("SET FLOW fd=%d to in=%d out=%d state_rdhup=%d\n",conn->fd,conn->bFlowIn,conn->bFlowOut,conn->state==CONN_RDHUP); uint32_t evtmask = (conn->state==CONN_RDHUP ? 0 : EPOLLRDHUP)|(conn->bFlowIn?EPOLLIN:0)|(conn->bFlowOut?EPOLLOUT:0); if (!epoll_set(conn, evtmask)) return false; - DBGPRINT("SET FLOW fd=%d to in=%d out=%d state_rdhup=%d\n",conn->fd,conn->bFlowIn,conn->bFlowOut,conn->state==CONN_RDHUP); conn->bFlowInPrev = conn->bFlowIn; conn->bFlowOutPrev = conn->bFlowOut; conn->bPrevRdhup = (conn->state==CONN_RDHUP); @@ -688,11 +694,11 @@ static bool epoll_set_flow_pair(tproxy_conn_t *conn) DBGPRINT("epoll_set_flow_pair fd=%d remote=%d partner_fd=%d bHasUnsent=%d bHasUnsentPartner=%d state_rdhup=%d\n", conn->fd , conn->remote, conn_partner_alive(conn) ? conn->partner->fd : 0, bHasUnsent, bHasUnsentPartner, conn->state==CONN_RDHUP); - if (!epoll_set_flow(conn, !bHasUnsentPartner && (conn->state!=CONN_RDHUP), bHasUnsent || conn->state==CONN_RDHUP)) + if (!epoll_set_flow(conn, !bHasUnsentPartner && (conn->state != CONN_RDHUP), bHasUnsent)) return false; if (conn_partner_alive(conn)) { - if (!epoll_set_flow(conn->partner, !bHasUnsent && (conn->partner->state!=CONN_RDHUP), bHasUnsentPartner || conn->partner->state==CONN_RDHUP)) + if (!epoll_set_flow(conn->partner, !bHasUnsent && (conn->partner->state != CONN_RDHUP), bHasUnsentPartner)) return false; } return true; @@ -724,6 +730,20 @@ static bool handle_unsent(tproxy_conn_t *conn) DBGPRINT("conn_buffers_send wr=%zd\n",wr); if (wr<0) return false; } + if (!conn_has_unsent(conn) && conn_partner_alive(conn) && conn->partner->state==CONN_RDHUP) + { + if (!conn->bShutdown) + { + DBGPRINT("fd=%d no more has unsent. partner in RDHUP state. executing delayed shutdown.\n", conn->fd); + conn_shutdown(conn); + } + if (conn->state==CONN_RDHUP && !conn_has_unsent(conn->partner)) + { + DBGPRINT("both partners are in RDHUP state and have no unsent. closing.\n"); + return false; + } + } + return epoll_set_flow_pair(conn); } @@ -1198,7 +1218,6 @@ static bool remove_closed_connections(int efd, struct tailhead *close_list) { TAILQ_REMOVE(close_list, conn, conn_ptrs); - shutdown(conn->fd,SHUT_RDWR); epoll_del(conn); VPRINT("Socket fd=%d (partner_fd=%d, remote=%d) closed, connection removed. total_read=%" PRIu64 " total_write=%" PRIu64 " event_count=%u\n", conn->fd, conn->partner ? conn->partner->fd : 0, conn->remote, conn->trd, conn->twr, conn->event_count); @@ -1303,6 +1322,7 @@ static void conn_close_with_partner_check(struct tailhead *conn_list, struct tai } } + static bool handle_resolve_pipe(tproxy_conn_t **conn, struct tailhead *conn_list, int fd) { ssize_t rd; @@ -1475,7 +1495,20 @@ int event_loop(const int *listen_fd, size_t listen_fd_ct) else { print_legs(); - VPRINT("Socket fd=%d (local) connected\n", conn->fd); + + if (params.debug>=1) + { + struct sockaddr_storage sa; + socklen_t salen=sizeof(sa); + char ip_port[48]; + + if (getpeername(conn->fd,(struct sockaddr *)&sa,&salen)) + *ip_port=0; + else + ntop46_port((struct sockaddr*)&sa,ip_port,sizeof(ip_port)); + + VPRINT("Socket fd=%d (local) connected from %s\n", conn->fd, ip_port); + } } } else @@ -1498,8 +1531,17 @@ int event_loop(const int *listen_fd, size_t listen_fd_ct) VPRINT("Socket fd=%d (partner_fd=%d, remote=%d) %s so_error=%d (%s)\n",conn->fd,conn->partner ? conn->partner->fd : 0,conn->remote,se,errn,strerror(errn)); proxy_remote_conn_ack(conn,errn); read_all_and_buffer(conn,3); - if (errn==ECONNRESET && conn->remote && params.tamper && conn_partner_alive(conn)) rst_in(&conn->partner->track); + if (errn==ECONNRESET && conn_partner_alive(conn)) + { + if (conn->remote && params.tamper) rst_in(&conn->partner->track); + struct linger lin; + lin.l_onoff=1; + lin.l_linger=0; + DBGPRINT("setting LINGER=0 to partner to force mirrored RST close\n"); + if (setsockopt(conn->partner->fd,SOL_SOCKET,SO_LINGER,&lin,sizeof(lin))<0) + DLOG_PERROR("setsockopt (SO_LINGER)"); + } conn_close_with_partner_check(&conn_list,&close_list,conn); continue; } @@ -1518,22 +1560,52 @@ int event_loop(const int *listen_fd, size_t listen_fd_ct) read_all_and_buffer(conn,2); if (!conn->remote && params.tamper) hup_out(&conn->track); + conn->state = CONN_RDHUP; // only writes. do not receive RDHUP anymore if (conn_has_unsent(conn)) { - DBGPRINT("conn fd=%d has unsent, not closing\n", conn->fd); - conn->state = CONN_RDHUP; // only writes + DBGPRINT("conn fd=%d has unsent\n", conn->fd); epoll_set_flow(conn,false,true); } else { - DBGPRINT("conn fd=%d has no unsent, closing\n", conn->fd); - conn_close_with_partner_check(&conn_list,&close_list,conn); + DBGPRINT("conn fd=%d has no unsent\n", conn->fd); + conn->bFlowIn = false; + epoll_update_flow(conn); + if (conn_partner_alive(conn)) + { + if (conn_has_unsent(conn->partner)) + DBGPRINT("partner has unset. partner shutdown delayed.\n"); + else + { + DBGPRINT("partner has no unsent. shutting down partner.\n"); + conn_shutdown(conn->partner); + if (conn->partner->state==CONN_RDHUP) + { + DBGPRINT("both partners are in RDHUP state and have no unsent. closing.\n"); + conn_close_with_partner_check(&conn_list,&close_list,conn); + } + } + } + else + { + DBGPRINT("partner is absent or not alive. closing.\n"); + close_tcp_conn(&conn_list,&close_list,conn); + } } continue; } if (events[i].events & (EPOLLIN|EPOLLOUT)) { + const char *se; + switch (events[i].events & (EPOLLIN|EPOLLOUT)) + { + case EPOLLIN: se="EPOLLIN"; break; + case EPOLLOUT: se="EPOLLOUT"; break; + case EPOLLIN|EPOLLOUT: se="EPOLLIN EPOLLOUT"; break; + default: se=NULL; + } + if (se) DBGPRINT("%s\n",se); // will not receive this until successful check_connection_attempt() if (!handle_epoll(conn, &conn_list, events[i].events)) { @@ -1541,6 +1613,12 @@ int event_loop(const int *listen_fd, size_t listen_fd_ct) conn_close_with_partner_check(&conn_list,&close_list,conn); continue; } + if ((conn->state == CONN_RDHUP) && conn_partner_alive(conn) && !conn->partner->bShutdown && !conn_has_unsent(conn)) + { + DBGPRINT("conn fd=%d has no unsent. shutting down partner.\n", conn->fd); + conn_shutdown(conn->partner); + } + } } diff --git a/tpws/tpws_conn.h b/tpws/tpws_conn.h index b45afb8..248ddcd 100644 --- a/tpws/tpws_conn.h +++ b/tpws/tpws_conn.h @@ -69,7 +69,7 @@ struct tproxy_conn // these value are used in flow control. we do not use ET (edge triggered) polling // if we dont disable notifications they will come endlessly until condition becomes false and will eat all cpu time - bool bFlowIn,bFlowOut, bFlowInPrev,bFlowOutPrev, bPrevRdhup; + bool bFlowIn,bFlowOut, bShutdown, bFlowInPrev,bFlowOutPrev, bPrevRdhup; // total read,write uint64_t trd,twr, tnrd;