Пример #1
0
/* 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;
}
Пример #2
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);  
}
Пример #3
0
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;
}
Пример #4
0
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;
}
Пример #5
0
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;
}
Пример #6
0
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;
}
Пример #7
0
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;
}
Пример #8
0
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;
}
Пример #9
0
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;
}
Пример #10
0
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;
}