int pr_netio_lingering_abort(pr_netio_stream_t *nstrm, long linger) { int res; if (nstrm == NULL) { errno = EINVAL; return -1; } /* Send an appropriate response code down the stream asychronously. */ pr_response_send_async(R_426, _("Transfer aborted. Data connection closed.")); pr_netio_shutdown(nstrm, 1); if (nstrm->strm_fd >= 0) { fd_set rs; struct timeval tv; /* Wait for just a little while for the shutdown to take effect. */ tv.tv_sec = 0L; tv.tv_usec = 300000L; while (TRUE) { run_schedule(); FD_ZERO(&rs); FD_SET(nstrm->strm_fd, &rs); res = select(nstrm->strm_fd+1, &rs, NULL, NULL, &tv); if (res == -1) { if (errno == EINTR) { pr_signals_handle(); /* Linger some more. */ tv.tv_sec = 0L; tv.tv_usec = 300000L; continue; } else { nstrm->strm_errno = errno; return -1; } } break; } } /* Now continue with a normal lingering close. */ return netio_lingering_close(nstrm, linger, NETIO_LINGERING_CLOSE_FL_NO_SHUTDOWN); }
int proxy_netio_shutdown(pr_netio_stream_t *nstrm, int how) { int res, xerrno; pr_netio_t *curr_netio = NULL; if (nstrm == NULL) { errno = EINVAL; return -1; } curr_netio = proxy_netio_unset(nstrm->strm_type, "netio_shutdown"); res = pr_netio_shutdown(nstrm, how); xerrno = errno; proxy_netio_set(nstrm->strm_type, curr_netio); errno = xerrno; return res; }
static int netio_lingering_close(pr_netio_stream_t *nstrm, long linger, int flags) { int res; struct timeval tv; fd_set rs; time_t when = time(NULL) + linger; if (!nstrm) { errno = EINVAL; return -1; } if (!(flags & NETIO_LINGERING_CLOSE_FL_NO_SHUTDOWN)) pr_netio_shutdown(nstrm, 1); tv.tv_sec = linger; tv.tv_usec = 0L; /* Handle timers during reading, once selected for read this * should mean all buffers have been flushed and the receiving end * has closed. */ while (TRUE) { run_schedule(); FD_ZERO(&rs); FD_SET(nstrm->strm_fd, &rs); res = select(nstrm->strm_fd+1, &rs, NULL, NULL, &tv); if (res == -1) { if (errno == EINTR) { time_t now = time(NULL); pr_signals_handle(); /* Still here? If the requested lingering interval hasn't passed, * continue lingering. Reset the timeval struct's fields to * linger for the interval remaining in the given period of time. */ if (now < when) { tv.tv_sec = when - now; tv.tv_usec = 0L; continue; } } else { nstrm->strm_errno = errno; return -1; } } break; } if (nstrm->strm_type == PR_NETIO_STRM_CTRL) return ctrl_netio ? ctrl_netio->close(nstrm) : core_ctrl_netio->close(nstrm); if (nstrm->strm_type == PR_NETIO_STRM_DATA) return data_netio ? data_netio->close(nstrm) : core_data_netio->close(nstrm); if (nstrm->strm_type == PR_NETIO_STRM_OTHR) return othr_netio ? othr_netio->close(nstrm) : core_othr_netio->close(nstrm); errno = EPERM; return -1; }
static int netio_lingering_close(pr_netio_stream_t *nstrm, long linger, int flags) { int res; if (nstrm == NULL) { errno = EINVAL; return -1; } if (nstrm->strm_fd < 0) { /* Already closed. */ return 0; } if (!(flags & NETIO_LINGERING_CLOSE_FL_NO_SHUTDOWN)) { pr_netio_shutdown(nstrm, 1); } if (nstrm->strm_fd >= 0) { struct timeval tv; fd_set rfds; time_t when = time(NULL) + linger; tv.tv_sec = linger; tv.tv_usec = 0L; /* Handle timers during reading, once selected for read this * should mean all buffers have been flushed and the receiving end * has closed. */ while (TRUE) { run_schedule(); FD_ZERO(&rfds); FD_SET(nstrm->strm_fd, &rfds); pr_trace_msg(trace_channel, 8, "lingering %lu secs before closing fd %d", (unsigned long) tv.tv_sec, nstrm->strm_fd); res = select(nstrm->strm_fd+1, &rfds, NULL, NULL, &tv); if (res == -1) { if (errno == EINTR) { time_t now = time(NULL); pr_signals_handle(); /* Still here? If the requested lingering interval hasn't passed, * continue lingering. Reset the timeval struct's fields to * linger for the interval remaining in the given period of time. */ if (now < when) { tv.tv_sec = when - now; tv.tv_usec = 0L; continue; } } else { nstrm->strm_errno = errno; return -1; } } else { if (FD_ISSET(nstrm->strm_fd, &rfds)) { pr_trace_msg(trace_channel, 8, "received data for reading on fd %d, ignoring", nstrm->strm_fd); } } break; } } pr_trace_msg(trace_channel, 8, "done lingering, closing fd %d", nstrm->strm_fd); switch (nstrm->strm_type) { case PR_NETIO_STRM_CTRL: return ctrl_netio ? (ctrl_netio->close)(nstrm) : (default_ctrl_netio->close)(nstrm); case PR_NETIO_STRM_DATA: return data_netio ? (data_netio->close)(nstrm) : (default_data_netio->close)(nstrm); case PR_NETIO_STRM_OTHR: return othr_netio ? (othr_netio->close)(nstrm) : (default_othr_netio->close)(nstrm); } errno = EPERM; return -1; }