From 074f20f93b0c13c6d5633a39fc5b62435cb8084a Mon Sep 17 00:00:00 2001 From: jyelon Date: Mon, 3 Apr 2023 15:05:36 -0400 Subject: [PATCH] Fix a subtle bug in the poll code --- luprex/cpp/drv/driver-common.cpp | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/luprex/cpp/drv/driver-common.cpp b/luprex/cpp/drv/driver-common.cpp index d005e606..49feff6c 100644 --- a/luprex/cpp/drv/driver-common.cpp +++ b/luprex/cpp/drv/driver-common.cpp @@ -261,6 +261,7 @@ class Driver { // Copy data from the send BIO into the socket. // // 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) { if ((chan.state == CHAN_INACTIVE) || (!chan.recent_error.empty())) { @@ -270,7 +271,10 @@ class Driver { char *data; int ndata = BIO_get_mem_data(chan.send_bio, &data); 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); + std::string err; int nwrote = socket_send(chan.socket, data, ndata, err); // std::cerr << "chan " << chan.chid << " send " << nwrote << " err=" << err << std::endl; @@ -453,12 +457,6 @@ class Driver { // Construct the struct pollfd vector. 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_) { struct pollfd &pfd = pollvec_[pollsize++]; assert(chan.socket != INVALID_SOCKET); @@ -477,20 +475,19 @@ class Driver { 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. socket_poll(pollvec_.get(), pollsize, mstimeout, err); if_error_print_and_exit(err); - // Check listening sockets. + // Advance channels where possible and then check listen sockets. 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_) { struct pollfd &pfd = pollvec_[index++]; if ((pfd.revents & POLLIN) != 0) { @@ -513,6 +510,12 @@ class Driver { chan.nbytes = 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 drvutil::remove_marked_items(chans_);