@@ -4108,6 +4108,8 @@ struct connstate {
4108
4108
#define MIP_TTYPE_FIN 4 // FIN sent, waiting until terminating the connection
4109
4109
uint8_t tmiss; // Number of keep-alive misses
4110
4110
struct mg_iobuf raw; // For TLS only. Incoming raw data
4111
+ bool fin_rcvd; // We have received FIN from the peer
4112
+ bool twclosure; // 3-way closure done
4111
4113
};
4112
4114
4113
4115
#pragma pack(push, 1)
@@ -4722,7 +4724,7 @@ long mg_io_send(struct mg_connection *c, const void *buf, size_t len) {
4722
4724
}
4723
4725
4724
4726
static void handle_tls_recv(struct mg_connection *c) {
4725
- size_t avail = mg_tls_pending(c);
4727
+ size_t avail = mg_tls_pending(c);
4726
4728
size_t min = avail > MG_MAX_RECV_SIZE ? MG_MAX_RECV_SIZE : avail;
4727
4729
struct mg_iobuf *io = &c->recv;
4728
4730
if (io->size - io->len < min && !mg_iobuf_resize(io, io->len + min)) {
@@ -4736,7 +4738,7 @@ static void handle_tls_recv(struct mg_connection *c) {
4736
4738
// Decrypted successfully - trigger MG_EV_READ
4737
4739
io->len += (size_t) n;
4738
4740
mg_call(c, MG_EV_READ, &n);
4739
- } // else n < 0: outstanding data to be moved to c->recv
4741
+ } // else n < 0: outstanding data to be moved to c->recv
4740
4742
}
4741
4743
}
4742
4744
@@ -4752,21 +4754,24 @@ static void read_conn(struct mg_connection *c, struct pkt *pkt) {
4752
4754
// closure process
4753
4755
uint8_t flags = TH_ACK;
4754
4756
s->ack = (uint32_t) (mg_htonl(pkt->tcp->seq) + pkt->pay.len + 1);
4757
+ s->fin_rcvd = true;
4755
4758
if (c->is_draining && s->ttype == MIP_TTYPE_FIN) {
4756
4759
if (s->seq == mg_htonl(pkt->tcp->ack)) { // Simultaneous closure ?
4757
4760
s->seq++; // Yes. Increment our SEQ
4758
4761
} else { // Otherwise,
4759
4762
s->seq = mg_htonl(pkt->tcp->ack); // Set to peer's ACK
4760
4763
}
4764
+ s->twclosure = true;
4761
4765
} else {
4762
4766
flags |= TH_FIN;
4763
4767
c->is_draining = 1;
4764
4768
settmout(c, MIP_TTYPE_FIN);
4765
4769
}
4766
4770
tx_tcp(c->mgr->ifp, s->mac, rem_ip, flags, c->loc.port, c->rem.port,
4767
4771
mg_htonl(s->seq), mg_htonl(s->ack), "", 0);
4768
- } else if (pkt->pay.len == 0) {
4769
- // TODO(cpq): handle this peer's ACK
4772
+ } else if (pkt->pay.len == 0) { // this is an ACK
4773
+ if (s->fin_rcvd && s->ttype == MIP_TTYPE_FIN)
4774
+ s->twclosure = true;
4770
4775
} else if (seq != s->ack) {
4771
4776
uint32_t ack = (uint32_t) (mg_htonl(pkt->tcp->seq) + pkt->pay.len);
4772
4777
if (s->ack == ack) {
@@ -5052,7 +5057,7 @@ static void mg_tcpip_poll(struct mg_tcpip_if *ifp, uint64_t now) {
5052
5057
struct connstate *s = (struct connstate *) (c + 1);
5053
5058
uint32_t rem_ip;
5054
5059
memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t));
5055
- if (now > s->timer) {
5060
+ if (ifp-> now > s->timer) {
5056
5061
if (s->ttype == MIP_TTYPE_ARP) {
5057
5062
mg_error(c, "ARP timeout");
5058
5063
} else if (c->is_udp) {
@@ -5240,10 +5245,15 @@ void mg_mgr_poll(struct mg_mgr *mgr, int ms) {
5240
5245
MG_VERBOSE(("%lu .. %c%c%c%c%c", c->id, c->is_tls ? 'T' : 't',
5241
5246
c->is_connecting ? 'C' : 'c', c->is_tls_hs ? 'H' : 'h',
5242
5247
c->is_resolving ? 'R' : 'r', c->is_closing ? 'C' : 'c'));
5248
+ // order is important, TLS conn close with > 1 record in buffer
5243
5249
if (c->is_tls && mg_tls_pending(c) > 0) handle_tls_recv(c);
5244
5250
if (can_write(c)) write_conn(c);
5245
5251
if (c->is_draining && c->send.len == 0 && s->ttype != MIP_TTYPE_FIN)
5246
5252
init_closure(c);
5253
+ // For non-TLS, close immediately upon completing the 3-way closure
5254
+ // For TLS, process any pending data until MIP_TTYPE_FIN timeout expires
5255
+ if (s->twclosure && (!c->is_tls || mg_tls_pending(c) == 0))
5256
+ c->is_closing = 1;
5247
5257
if (c->is_closing) close_conn(c);
5248
5258
}
5249
5259
(void) ms;
0 commit comments