/* finalize == 1: if data is of packet aligned size, add a zero length packet */ static int uhci_bulk (endpoint_t *ep, int size, u8 *data, int finalize) { int maxpsize = ep->maxpacketsize; if (maxpsize == 0) fatal("MaxPacketSize == 0!!!"); int numpackets = (size + maxpsize - 1) / maxpsize; if (finalize && ((size % maxpsize) == 0)) { numpackets++; } if (numpackets == 0) return 0; td_t *tds = create_schedule (numpackets); int i = 0, toggle = ep->toggle; while ((size > 0) || ((size == 0) && (finalize != 0))) { fill_schedule (&tds[i], ep, min (size, maxpsize), data, &toggle); i++; data += maxpsize; size -= maxpsize; } if (run_schedule (ep->dev, tds) == 1) { usb_debug("Stalled. Trying to clean up.\n"); clear_stall (ep); free (tds); return 1; } ep->toggle = toggle; free (tds); return 0; }
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 pr_netio_read(pr_netio_stream_t *nstrm, char *buf, size_t buflen, int bufmin) { int bread = 0, total = 0; /* Sanity check. */ if (!nstrm) { errno = EINVAL; return -1; } if (nstrm->strm_fd == -1) { errno = (nstrm->strm_errno ? nstrm->strm_errno : EBADF); return -1; } if (bufmin < 1) bufmin = 1; if (bufmin > buflen) bufmin = buflen; while (bufmin > 0) { polling: switch (pr_netio_poll(nstrm)) { case 1: return -2; case -1: return -1; default: do { pr_signals_handle(); run_schedule(); switch (nstrm->strm_type) { case PR_NETIO_STRM_CTRL: bread = ctrl_netio ? ctrl_netio->read(nstrm, buf, buflen) : core_ctrl_netio->read(nstrm, buf, buflen); break; case PR_NETIO_STRM_DATA: bread = data_netio ? data_netio->read(nstrm, buf, buflen) : core_data_netio->read(nstrm, buf, buflen); break; case PR_NETIO_STRM_OTHR: bread = othr_netio ? othr_netio->read(nstrm, buf, buflen) : core_othr_netio->read(nstrm, buf, buflen); break; } #ifdef EAGAIN if (bread == -1 && errno == EAGAIN) goto polling; #endif } while (bread == -1 && errno == EINTR); break; } if (bread == -1) { nstrm->strm_errno = errno; return -1; } /* EOF? */ if (bread == 0) { nstrm->strm_errno = 0; break; } buf += bread; total += bread; bufmin -= bread; buflen -= bread; } return total; }
int pr_netio_write(pr_netio_stream_t *nstrm, char *buf, size_t buflen) { int bwritten = 0, total = 0; /* Sanity check */ if (!nstrm) { errno = EINVAL; return -1; } if (nstrm->strm_fd == -1) { errno = (nstrm->strm_errno ? nstrm->strm_errno : EBADF); return -1; } while (buflen) { switch (pr_netio_poll(nstrm)) { case 1: return -2; case -1: return -1; default: /* We have to potentially restart here as well, in case we get EINTR. */ do { pr_signals_handle(); run_schedule(); switch (nstrm->strm_type) { case PR_NETIO_STRM_CTRL: bwritten = ctrl_netio ? ctrl_netio->write(nstrm, buf, buflen) : core_ctrl_netio->write(nstrm, buf, buflen); break; case PR_NETIO_STRM_DATA: bwritten = data_netio ? data_netio->write(nstrm, buf, buflen) : core_data_netio->write(nstrm, buf, buflen); break; case PR_NETIO_STRM_OTHR: bwritten = othr_netio ? othr_netio->write(nstrm, buf, buflen) : core_othr_netio->write(nstrm, buf, buflen); break; } } while (bwritten == -1 && errno == EINTR); break; } if (bwritten == -1) { nstrm->strm_errno = errno; return -1; } buf += bwritten; total += bwritten; buflen -= bwritten; } return total; }
int pr_netio_poll(pr_netio_stream_t *nstrm) { int res = 0; /* Sanity checks. */ if (!nstrm) { errno = EINVAL; return -1; } if (nstrm->strm_fd == -1) { errno = EBADF; return -1; } /* Has this stream been aborted? */ if (nstrm->strm_flags & PR_NETIO_SESS_ABORT) { nstrm->strm_flags &= ~PR_NETIO_SESS_ABORT; return 1; } while (TRUE) { run_schedule(); pr_signals_handle(); switch (nstrm->strm_type) { case PR_NETIO_STRM_CTRL: res = ctrl_netio ? ctrl_netio->poll(nstrm) : core_ctrl_netio->poll(nstrm); break; case PR_NETIO_STRM_DATA: res = data_netio ? data_netio->poll(nstrm) : core_data_netio->poll(nstrm); break; case PR_NETIO_STRM_OTHR: res = othr_netio ? othr_netio->poll(nstrm) : core_othr_netio->poll(nstrm); break; } switch (res) { case -1: if (errno == EINTR) { if (nstrm->strm_flags & PR_NETIO_SESS_ABORT) { nstrm->strm_flags &= ~PR_NETIO_SESS_ABORT; return 1; } /* Otherwise, restart the call */ pr_signals_handle(); continue; } /* Some other error occured */ nstrm->strm_errno = errno; return -1; case 0: /* In case the kernel doesn't support interrupted syscalls. */ if (nstrm->strm_flags & PR_NETIO_SESS_ABORT) { nstrm->strm_flags &= ~PR_NETIO_SESS_ABORT; return 1; } continue; default: return 0; } } /* This will never be reached. */ return -1; }
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; }
int pr_netio_read(pr_netio_stream_t *nstrm, char *buf, size_t buflen, int bufmin) { int bread = 0, total = 0; /* Sanity check. */ if (!nstrm) { errno = EINVAL; return -1; } if (nstrm->strm_fd == -1) { errno = (nstrm->strm_errno ? nstrm->strm_errno : EBADF); return -1; } if (bufmin < 1) bufmin = 1; if (bufmin > buflen) bufmin = buflen; while (bufmin > 0) { polling: switch (pr_netio_poll(nstrm)) { case 1: return -2; case -1: return -1; default: do { pr_signals_handle(); run_schedule(); switch (nstrm->strm_type) { case PR_NETIO_STRM_CTRL: bread = ctrl_netio ? (ctrl_netio->read)(nstrm, buf, buflen) : (default_ctrl_netio->read)(nstrm, buf, buflen); break; case PR_NETIO_STRM_DATA: if (XFER_ABORTED) break; bread = data_netio ? (data_netio->read)(nstrm, buf, buflen) : (default_data_netio->read)(nstrm, buf, buflen); break; case PR_NETIO_STRM_OTHR: bread = othr_netio ? (othr_netio->read)(nstrm, buf, buflen) : (default_othr_netio->read)(nstrm, buf, buflen); break; } #ifdef EAGAIN if (bread == -1 && errno == EAGAIN) { int xerrno = EAGAIN; /* Treat this as an interrupted call, call pr_signals_handle() * (which will delay for a few msecs because of EINTR), and try * again. * * This should avoid a tightly spinning loop if read(2) returns * EAGAIN, as on a data transfer (Bug#3639). */ errno = EINTR; pr_signals_handle(); errno = xerrno; goto polling; } #endif } while (bread == -1 && errno == EINTR); break; } if (bread == -1) { nstrm->strm_errno = errno; return -1; } /* EOF? */ if (bread == 0) { if (nstrm->strm_type == PR_NETIO_STRM_CTRL) { pr_trace_msg(trace_channel, 7, "read %d bytes from control stream fd %d, handling as EOF", bread, nstrm->strm_fd); } nstrm->strm_errno = 0; break; } buf += bread; total += bread; bufmin -= bread; buflen -= bread; } session.total_raw_in += total; return total; }
int pr_netio_write(pr_netio_stream_t *nstrm, char *buf, size_t buflen) { int bwritten = 0, total = 0; pr_buffer_t *pbuf; pool *sub_pool; /* Sanity check */ if (!nstrm) { errno = EINVAL; return -1; } if (nstrm->strm_fd == -1) { errno = (nstrm->strm_errno ? nstrm->strm_errno : EBADF); return -1; } /* Before we send out the data to the client, generate an event * for any listeners which may want to examine this data. To do this, we * need to allocate a pr_buffer_t for sending the buffer data to the * listeners. * * We could just use nstrm->strm_pool, but for a long-lived control * connection, this would amount to a slow memory increase. So instead, * we create a subpool from the stream's pool, and allocate the * pr_buffer_t out of that. Then simply destroy the subpool when done. */ sub_pool = pr_pool_create_sz(nstrm->strm_pool, 64); pbuf = pcalloc(sub_pool, sizeof(pr_buffer_t)); pbuf->buf = buf; pbuf->buflen = buflen; pbuf->current = pbuf->buf; pbuf->remaining = 0; switch (nstrm->strm_type) { case PR_NETIO_STRM_CTRL: pr_event_generate("core.ctrl-write", pbuf); break; case PR_NETIO_STRM_DATA: pr_event_generate("core.data-write", pbuf); break; case PR_NETIO_STRM_OTHR: pr_event_generate("core.othr-write", pbuf); break; } /* The event listeners may have changed the data to write out. */ buf = pbuf->buf; buflen = pbuf->buflen - pbuf->remaining; destroy_pool(sub_pool); while (buflen) { switch (pr_netio_poll(nstrm)) { case 1: return -2; case -1: return -1; default: /* We have to potentially restart here as well, in case we get EINTR. */ do { pr_signals_handle(); run_schedule(); switch (nstrm->strm_type) { case PR_NETIO_STRM_CTRL: bwritten = ctrl_netio ? (ctrl_netio->write)(nstrm, buf, buflen) : (default_ctrl_netio->write)(nstrm, buf, buflen); break; case PR_NETIO_STRM_DATA: if (XFER_ABORTED) break; bwritten = data_netio ? (data_netio->write)(nstrm, buf, buflen) : (default_data_netio->write)(nstrm, buf, buflen); break; case PR_NETIO_STRM_OTHR: bwritten = othr_netio ? (othr_netio->write)(nstrm, buf, buflen) : (default_othr_netio->write)(nstrm, buf, buflen); break; } } while (bwritten == -1 && errno == EINTR); break; } if (bwritten == -1) { nstrm->strm_errno = errno; return -1; } buf += bwritten; total += bwritten; buflen -= bwritten; } session.total_raw_out += total; return total; }
int pr_netio_poll(pr_netio_stream_t *nstrm) { int res = 0, xerrno = 0; /* Sanity checks. */ if (nstrm == NULL) { errno = EINVAL; return -1; } if (nstrm->strm_fd == -1) { errno = EBADF; return -1; } /* Has this stream been aborted? */ if (nstrm->strm_flags & PR_NETIO_SESS_ABORT) { nstrm->strm_flags &= ~PR_NETIO_SESS_ABORT; return 1; } while (TRUE) { run_schedule(); pr_signals_handle(); switch (nstrm->strm_type) { case PR_NETIO_STRM_CTRL: res = ctrl_netio ? (ctrl_netio->poll)(nstrm) : (default_ctrl_netio->poll)(nstrm); break; case PR_NETIO_STRM_DATA: res = data_netio ? (data_netio->poll)(nstrm) : (default_data_netio->poll)(nstrm); break; case PR_NETIO_STRM_OTHR: res = othr_netio ? (othr_netio->poll)(nstrm) : (default_othr_netio->poll)(nstrm); break; } switch (res) { case -1: xerrno = errno; if (xerrno == EINTR) { if (nstrm->strm_flags & PR_NETIO_SESS_ABORT) { nstrm->strm_flags &= ~PR_NETIO_SESS_ABORT; return 1; } /* Otherwise, restart the call */ pr_signals_handle(); continue; } /* Some other error occured */ nstrm->strm_errno = xerrno; /* If this is the control stream, and the error indicates a * broken pipe (i.e. the client went away), AND there is a data * transfer is progress, abort the transfer. */ if (xerrno == EPIPE && nstrm->strm_type == PR_NETIO_STRM_CTRL && (session.sf_flags & SF_XFER)) { pr_trace_msg(trace_channel, 5, "received EPIPE on control connection, setting 'aborted' " "session flag"); session.sf_flags |= SF_ABORT; } errno = nstrm->strm_errno; return -1; case 0: /* In case the kernel doesn't support interrupted syscalls. */ if (nstrm->strm_flags & PR_NETIO_SESS_ABORT) { nstrm->strm_flags &= ~PR_NETIO_SESS_ABORT; return 1; } /* If the stream has been marked as "interruptible", AND the * poll interval is zero seconds (meaning a true poll, not blocking), * then return here. */ if ((nstrm->strm_flags & PR_NETIO_SESS_INTR) && nstrm->strm_interval == 0) { errno = EOF; return -1; } continue; default: return 0; } } /* This will never be reached. */ 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; }