Project

General

Profile

Bug #4987

libkmf doesn't correctly implement timeouts on downloads

Added by Jason King over 5 years ago.

Status:
New
Priority:
Normal
Assignee:
-
Category:
lib - userland libraries
Start date:
2014-07-10
Due date:
% Done:

0%

Estimated time:
Difficulty:
Medium
Tags:
needs-triage

Description

kmf_get_encoded_oscp_response(), kmf_download_crl(), and kmf_download_cert() all allow a caller to pass a timeout value (in seconds). However, they all ultimately call usr/src/lib/libkmf/common/client.c:get_encoded_response which roughly does:

   pfd.sock = non_blocking_socket_fd;
   pfd.events = POLLIN;

   /* Get header */
    do {
            poll(&pfd, 1, timeout);

            /* Append data to buf */
            n = read(non_blocking_socket_fd, buf + offset, buf_remaining);

            /* set headerEnd to end of header in buf  or NULL if not there yet */
  } while (headerEnd == NULL && n > 0 && !error);
  ...
  /* Get body */
  do {
          poll(&pdf, 1, timeout);

          /* Append data to buf */
          n = read(non_blocking_socket_fd, buf + offset, buf_remaining);
  } while (n > 0 && !error);

Since there are at least 2 calls to poll, and potentially more based on network conditions and the behavior of the peer, it is quite possible that it would take far longer to execute than the timeout value. Instead it should use a pattern along the lines of (may not be 100% correct):

    /* Use gethrtime() / hrtime_t to avoid clock drift issues */
    hrtime_t deadline = gethrtime() + timeout * NANOSEC;

  /* Get header */
   do {
       hrtime_t timeout = deadline - gethrtime();

       if (timeout <= 0)
           break;

       poll(..., (int)NSEC2MSEC(timeout));
       n = read(...);

       /* Find end of header */
   } while (headerEnd == NULL && !error);
    ...
  /* Get body */
   do {
       hrtime_t timeout = deadline - gethrtime();

       if (timeout <= 0)
           break;

       poll(..., (int)NSEC2MSEC(timeout));

      /* Append to buf */
       n = read(...);
    } while (n > 0 && !error);

Also available in: Atom PDF