# # # patch "NEWS" # from [d7967f2eb3746ce5cf4e3e2b4c6222ace128c0e7] # to [18faedaecb9ad80547d8d5348745adec19f0cd61] # # patch "netsync.cc" # from [e549bac580f407665575fb8cd40178f0b3c3acf5] # to [944dac317f3f3d55d0fd8bc286512cb7c2fded9a] # ============================================================ --- NEWS d7967f2eb3746ce5cf4e3e2b4c6222ace128c0e7 +++ NEWS 18faedaecb9ad80547d8d5348745adec19f0cd61 @@ -6,6 +6,13 @@ Bugs fixed + - In certain cases, especially also on FreeBSD, netsync called + select() even after read() returned 0 bytes to indicate the + end of the file, resulting in a confusing error message. This + is fixed by treating EOF specially and prevent further calls + to select() on the file handle, as recommended by the + select_tut man page. + New features - The `mtn_automate' lua function now correctly parses and sets ============================================================ --- netsync.cc e549bac580f407665575fb8cd40178f0b3c3acf5 +++ netsync.cc 944dac317f3f3d55d0fd8bc286512cb7c2fded9a @@ -353,7 +353,7 @@ class session_base : public reactable class session_base : public reactable { - bool read_some(); + void read_some(bool & failed, bool & eof); bool write_some(); void mark_recent_io() { @@ -468,10 +468,12 @@ session_base::which_events() return ret; } -bool -session_base::read_some() +void +session_base::read_some(bool & failed, bool & eof) { I(inbuf.size() < constants::netcmd_maxsz); + eof = false; + failed = false; char tmp[constants::bufsz]; Netxx::signed_size_type count = str->read(tmp, sizeof(tmp)); if (count > 0) @@ -479,17 +481,38 @@ session_base::read_some() L(FL("read %d bytes from fd %d (peer %s)") % count % str->get_socketfd() % peer_id); if (encountered_error) - { - L(FL("in error unwind mode, so throwing them into the bit bucket")); - return true; - } + L(FL("in error unwind mode, so throwing them into the bit bucket")); + inbuf.append(tmp,count); mark_recent_io(); note_bytes_in(count); - return true; } + else if (count == 0) + { + // Returning 0 bytes after select() marks the file descriptor as + // ready for reading signifies EOF. + + switch (protocol_state) + { + case working_state: + P(F("peer %s IO terminated connection in working state (error)") + % peer_id); + break; + + case shutdown_state: + P(F("peer %s IO terminated connection in shutdown state " + "(possibly client misreported error)") + % peer_id); + break; + + case confirmed_state: + break; + } + + eof = true; + } else - return false; + failed = true; } bool @@ -531,11 +554,14 @@ session_base::do_io(Netxx::Probe::ready_ session_base::do_io(Netxx::Probe::ready_type what) { bool ok = true; + bool eof = false; try { if (what & Netxx::Probe::ready_read) { - if (!read_some()) + bool failed; + read_some(failed, eof); + if (failed) ok = false; } if (what & Netxx::Probe::ready_write) @@ -578,7 +604,11 @@ session_base::do_io(Netxx::Probe::ready_ % peer_id); ok = false; } - return ok; + + // Return false in case we reached EOF, so as to prevent further calls + // to select()s on this stream, as recommended by the select_tut man + // page. + return ok && !eof; } ////////////////////////////////////////////////////////////////////////