static void iocpdesc_fail(iocpdesc_t *iocpd, HRESULT status, const char* text) { pni_win32_error(iocpd->error, text, status); if (iocpd->iocp->iocp_trace) { iocp_log("connection terminated: %s\n", pn_error_text(iocpd->error)); } if (!is_listener(iocpd) && !iocpd->write_closed && !pni_write_pipeline_size(iocpd->pipeline)) iocp_shutdown(iocpd); iocpd->write_closed = true; iocpd->read_closed = true; iocpd->poll_error = true; pni_events_update(iocpd, iocpd->events & ~(PN_READABLE | PN_WRITABLE)); }
/* * Note: iocp write completion is not "bytes on the wire", it is "peer * acked the sent bytes". Completion can be seconds on a slow * consuming peer. */ static void complete_write(write_result_t *result, DWORD xfer_count, HRESULT status) { iocpdesc_t *iocpd = result->base.iocpd; if (iocpd->closing) { pni_write_pipeline_return(iocpd->pipeline, result); if (!iocpd->write_closed && !write_in_progress(iocpd)) iocp_shutdown(iocpd); reap_check(iocpd); return; } if (status == 0 && xfer_count > 0) { if (xfer_count != result->requested) { // Is this recoverable? How to preserve order if multiple overlapped writes? pni_write_pipeline_return(iocpd->pipeline, result); iocpdesc_fail(iocpd, WSA_OPERATION_ABORTED, "Partial overlapped write on socket"); return; } else { // Success. pni_write_pipeline_return(iocpd->pipeline, result); if (pni_write_pipeline_writable(iocpd->pipeline)) pni_events_update(iocpd, iocpd->events | PN_WRITABLE); return; } } // Other error pni_write_pipeline_return(iocpd->pipeline, result); if (status == WSAECONNABORTED || status == WSAECONNRESET || status == WSAENOTCONN || status == ERROR_NETNAME_DELETED) { iocpd->write_closed = true; iocpd->poll_error = true; pni_events_update(iocpd, iocpd->events & ~PN_WRITABLE); pni_win32_error(iocpd->error, "Remote close or timeout", status); } else { iocpdesc_fail(iocpd, status, "IOCP async write error"); } }
void pni_iocp_begin_close(iocpdesc_t *iocpd) { assert (!iocpd->closing); if (is_listener(iocpd)) { // Listening socket is easy. Close the socket which will cancel async ops. pn_socket_t old_sock = iocpd->socket; iocpd->socket = INVALID_SOCKET; iocpd->closing = true; iocpd->read_closed = true; iocpd->write_closed = true; closesocket(old_sock); // Pending accepts will now complete. Zombie can die when all consumed. zombie_list_add(iocpd); pni_iocpdesc_map_del(iocpd->iocp, old_sock); // may pn_free *iocpd } else { // Continue async operation looking for graceful close confirmation or timeout. pn_socket_t old_sock = iocpd->socket; iocpd->closing = true; if (!iocpd->write_closed && !write_in_progress(iocpd)) iocp_shutdown(iocpd); zombie_list_add(iocpd); pni_iocpdesc_map_del(iocpd->iocp, old_sock); // may pn_free *iocpd } }