Fix a subtle bug in the poll code

This commit is contained in:
2023-04-03 15:05:36 -04:00
parent f3e4974f6a
commit 074f20f93b

View File

@@ -261,6 +261,7 @@ class Driver {
// Copy data from the send BIO into the socket. // Copy data from the send BIO into the socket.
// //
// If it detects an error, sets the recent_errno flag. // If it detects an error, sets the recent_errno flag.
// It is an error to call this when there is nothing in the send BIO.
// //
void transfer_send_bio_to_socket(ChanInfo &chan) { void transfer_send_bio_to_socket(ChanInfo &chan) {
if ((chan.state == CHAN_INACTIVE) || (!chan.recent_error.empty())) { if ((chan.state == CHAN_INACTIVE) || (!chan.recent_error.empty())) {
@@ -270,7 +271,10 @@ class Driver {
char *data; char *data;
int ndata = BIO_get_mem_data(chan.send_bio, &data); int ndata = BIO_get_mem_data(chan.send_bio, &data);
if (ndata > DRV_SHORTSTRING_SIZE) ndata = DRV_SHORTSTRING_SIZE; if (ndata > DRV_SHORTSTRING_SIZE) ndata = DRV_SHORTSTRING_SIZE;
// It is an error to call this function when there is nothing in the send BIO.
assert(ndata > 0); assert(ndata > 0);
std::string err; std::string err;
int nwrote = socket_send(chan.socket, data, ndata, err); int nwrote = socket_send(chan.socket, data, ndata, err);
// std::cerr << "chan " << chan.chid << " send " << nwrote << " err=" << err << std::endl; // std::cerr << "chan " << chan.chid << " send " << nwrote << " err=" << err << std::endl;
@@ -453,12 +457,6 @@ class Driver {
// Construct the struct pollfd vector. // Construct the struct pollfd vector.
int pollsize = 0; int pollsize = 0;
for (const auto &p : listen_sockets_) {
struct pollfd &pfd = pollvec_[pollsize++];
pfd.fd = p.second;
pfd.events = POLLIN;
pfd.revents = 0;
}
for (const ChanInfo &chan : chans_) { for (const ChanInfo &chan : chans_) {
struct pollfd &pfd = pollvec_[pollsize++]; struct pollfd &pfd = pollvec_[pollsize++];
assert(chan.socket != INVALID_SOCKET); assert(chan.socket != INVALID_SOCKET);
@@ -477,20 +475,19 @@ class Driver {
mstimeout = 0; mstimeout = 0;
} }
} }
for (const auto &p : listen_sockets_) {
struct pollfd &pfd = pollvec_[pollsize++];
pfd.fd = p.second;
pfd.events = POLLIN;
pfd.revents = 0;
}
// Do the poll. // Do the poll.
socket_poll(pollvec_.get(), pollsize, mstimeout, err); socket_poll(pollvec_.get(), pollsize, mstimeout, err);
if_error_print_and_exit(err); if_error_print_and_exit(err);
// Check listening sockets. // Advance channels where possible and then check listen sockets.
int index = 0; int index = 0;
for (auto &p : listen_sockets_) {
struct pollfd &pfd = pollvec_[index++];
if (pfd.revents & (POLLIN | POLLERR)) {
accept_connection(p.first, p.second);
}
}
// Advance channels where possible.
for (ChanInfo &chan : chans_) { for (ChanInfo &chan : chans_) {
struct pollfd &pfd = pollvec_[index++]; struct pollfd &pfd = pollvec_[index++];
if ((pfd.revents & POLLIN) != 0) { if ((pfd.revents & POLLIN) != 0) {
@@ -513,6 +510,12 @@ class Driver {
chan.nbytes = 0; chan.nbytes = 0;
chan.bytes = 0; chan.bytes = 0;
} }
for (auto &p : listen_sockets_) {
struct pollfd &pfd = pollvec_[index++];
if (pfd.revents & (POLLIN | POLLERR)) {
accept_connection(p.first, p.second);
}
}
// Delete any newly-inactive channels // Delete any newly-inactive channels
drvutil::remove_marked_items(chans_); drvutil::remove_marked_items(chans_);