Skip to content

Commit 74b3fd2

Browse files
authored
Merge pull request #3009 from cesanta/fin
Close connection fast if both sides sent FIN
2 parents 8dbfcbf + 091356e commit 74b3fd2

File tree

2 files changed

+30
-10
lines changed

2 files changed

+30
-10
lines changed

mongoose.c

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4108,6 +4108,8 @@ struct connstate {
41084108
#define MIP_TTYPE_FIN 4 // FIN sent, waiting until terminating the connection
41094109
uint8_t tmiss; // Number of keep-alive misses
41104110
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
41114113
};
41124114

41134115
#pragma pack(push, 1)
@@ -4722,7 +4724,7 @@ long mg_io_send(struct mg_connection *c, const void *buf, size_t len) {
47224724
}
47234725

47244726
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);
47264728
size_t min = avail > MG_MAX_RECV_SIZE ? MG_MAX_RECV_SIZE : avail;
47274729
struct mg_iobuf *io = &c->recv;
47284730
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) {
47364738
// Decrypted successfully - trigger MG_EV_READ
47374739
io->len += (size_t) n;
47384740
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
47404742
}
47414743
}
47424744

@@ -4752,21 +4754,24 @@ static void read_conn(struct mg_connection *c, struct pkt *pkt) {
47524754
// closure process
47534755
uint8_t flags = TH_ACK;
47544756
s->ack = (uint32_t) (mg_htonl(pkt->tcp->seq) + pkt->pay.len + 1);
4757+
s->fin_rcvd = true;
47554758
if (c->is_draining && s->ttype == MIP_TTYPE_FIN) {
47564759
if (s->seq == mg_htonl(pkt->tcp->ack)) { // Simultaneous closure ?
47574760
s->seq++; // Yes. Increment our SEQ
47584761
} else { // Otherwise,
47594762
s->seq = mg_htonl(pkt->tcp->ack); // Set to peer's ACK
47604763
}
4764+
s->twclosure = true;
47614765
} else {
47624766
flags |= TH_FIN;
47634767
c->is_draining = 1;
47644768
settmout(c, MIP_TTYPE_FIN);
47654769
}
47664770
tx_tcp(c->mgr->ifp, s->mac, rem_ip, flags, c->loc.port, c->rem.port,
47674771
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;
47704775
} else if (seq != s->ack) {
47714776
uint32_t ack = (uint32_t) (mg_htonl(pkt->tcp->seq) + pkt->pay.len);
47724777
if (s->ack == ack) {
@@ -5052,7 +5057,7 @@ static void mg_tcpip_poll(struct mg_tcpip_if *ifp, uint64_t now) {
50525057
struct connstate *s = (struct connstate *) (c + 1);
50535058
uint32_t rem_ip;
50545059
memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t));
5055-
if (now > s->timer) {
5060+
if (ifp->now > s->timer) {
50565061
if (s->ttype == MIP_TTYPE_ARP) {
50575062
mg_error(c, "ARP timeout");
50585063
} else if (c->is_udp) {
@@ -5240,10 +5245,15 @@ void mg_mgr_poll(struct mg_mgr *mgr, int ms) {
52405245
MG_VERBOSE(("%lu .. %c%c%c%c%c", c->id, c->is_tls ? 'T' : 't',
52415246
c->is_connecting ? 'C' : 'c', c->is_tls_hs ? 'H' : 'h',
52425247
c->is_resolving ? 'R' : 'r', c->is_closing ? 'C' : 'c'));
5248+
// order is important, TLS conn close with > 1 record in buffer
52435249
if (c->is_tls && mg_tls_pending(c) > 0) handle_tls_recv(c);
52445250
if (can_write(c)) write_conn(c);
52455251
if (c->is_draining && c->send.len == 0 && s->ttype != MIP_TTYPE_FIN)
52465252
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;
52475257
if (c->is_closing) close_conn(c);
52485258
}
52495259
(void) ms;

src/net_builtin.c

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ struct connstate {
2828
#define MIP_TTYPE_FIN 4 // FIN sent, waiting until terminating the connection
2929
uint8_t tmiss; // Number of keep-alive misses
3030
struct mg_iobuf raw; // For TLS only. Incoming raw data
31+
bool fin_rcvd; // We have received FIN from the peer
32+
bool twclosure; // 3-way closure done
3133
};
3234

3335
#pragma pack(push, 1)
@@ -642,7 +644,7 @@ long mg_io_send(struct mg_connection *c, const void *buf, size_t len) {
642644
}
643645

644646
static void handle_tls_recv(struct mg_connection *c) {
645-
size_t avail = mg_tls_pending(c);
647+
size_t avail = mg_tls_pending(c);
646648
size_t min = avail > MG_MAX_RECV_SIZE ? MG_MAX_RECV_SIZE : avail;
647649
struct mg_iobuf *io = &c->recv;
648650
if (io->size - io->len < min && !mg_iobuf_resize(io, io->len + min)) {
@@ -656,7 +658,7 @@ static void handle_tls_recv(struct mg_connection *c) {
656658
// Decrypted successfully - trigger MG_EV_READ
657659
io->len += (size_t) n;
658660
mg_call(c, MG_EV_READ, &n);
659-
} // else n < 0: outstanding data to be moved to c->recv
661+
} // else n < 0: outstanding data to be moved to c->recv
660662
}
661663
}
662664

@@ -672,21 +674,24 @@ static void read_conn(struct mg_connection *c, struct pkt *pkt) {
672674
// closure process
673675
uint8_t flags = TH_ACK;
674676
s->ack = (uint32_t) (mg_htonl(pkt->tcp->seq) + pkt->pay.len + 1);
677+
s->fin_rcvd = true;
675678
if (c->is_draining && s->ttype == MIP_TTYPE_FIN) {
676679
if (s->seq == mg_htonl(pkt->tcp->ack)) { // Simultaneous closure ?
677680
s->seq++; // Yes. Increment our SEQ
678681
} else { // Otherwise,
679682
s->seq = mg_htonl(pkt->tcp->ack); // Set to peer's ACK
680683
}
684+
s->twclosure = true;
681685
} else {
682686
flags |= TH_FIN;
683687
c->is_draining = 1;
684688
settmout(c, MIP_TTYPE_FIN);
685689
}
686690
tx_tcp(c->mgr->ifp, s->mac, rem_ip, flags, c->loc.port, c->rem.port,
687691
mg_htonl(s->seq), mg_htonl(s->ack), "", 0);
688-
} else if (pkt->pay.len == 0) {
689-
// TODO(cpq): handle this peer's ACK
692+
} else if (pkt->pay.len == 0) { // this is an ACK
693+
if (s->fin_rcvd && s->ttype == MIP_TTYPE_FIN)
694+
s->twclosure = true;
690695
} else if (seq != s->ack) {
691696
uint32_t ack = (uint32_t) (mg_htonl(pkt->tcp->seq) + pkt->pay.len);
692697
if (s->ack == ack) {
@@ -972,7 +977,7 @@ static void mg_tcpip_poll(struct mg_tcpip_if *ifp, uint64_t now) {
972977
struct connstate *s = (struct connstate *) (c + 1);
973978
uint32_t rem_ip;
974979
memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t));
975-
if (now > s->timer) {
980+
if (ifp->now > s->timer) {
976981
if (s->ttype == MIP_TTYPE_ARP) {
977982
mg_error(c, "ARP timeout");
978983
} else if (c->is_udp) {
@@ -1160,10 +1165,15 @@ void mg_mgr_poll(struct mg_mgr *mgr, int ms) {
11601165
MG_VERBOSE(("%lu .. %c%c%c%c%c", c->id, c->is_tls ? 'T' : 't',
11611166
c->is_connecting ? 'C' : 'c', c->is_tls_hs ? 'H' : 'h',
11621167
c->is_resolving ? 'R' : 'r', c->is_closing ? 'C' : 'c'));
1168+
// order is important, TLS conn close with > 1 record in buffer
11631169
if (c->is_tls && mg_tls_pending(c) > 0) handle_tls_recv(c);
11641170
if (can_write(c)) write_conn(c);
11651171
if (c->is_draining && c->send.len == 0 && s->ttype != MIP_TTYPE_FIN)
11661172
init_closure(c);
1173+
// For non-TLS, close immediately upon completing the 3-way closure
1174+
// For TLS, process any pending data until MIP_TTYPE_FIN timeout expires
1175+
if (s->twclosure && (!c->is_tls || mg_tls_pending(c) == 0))
1176+
c->is_closing = 1;
11671177
if (c->is_closing) close_conn(c);
11681178
}
11691179
(void) ms;

0 commit comments

Comments
 (0)