Exemplo n.º 1
0
/* send an attention. this may get called at any time, so we can't use
 * DSI buffers to send one. 
   return 0 on error
 
 */
int dsi_attention(DSI *dsi, AFPUserBytes flags)
{
  /* header + AFPUserBytes */
  char block[DSI_BLOCKSIZ + sizeof(AFPUserBytes)];
  u_int32_t len, nlen;
  u_int16_t id;

  if (dsi->flags & DSI_SLEEPING)
      return 1;

  if (dsi->in_write) {
      return -1;
  }      
  id = htons(dsi_serverID(dsi));
  flags = htons(flags);
  len = MIN(sizeof(flags), dsi->attn_quantum);
  nlen = htonl(len);

  memset(block, 0, sizeof(block));
  block[0] = DSIFL_REQUEST; /* sending a request */
  block[1] = DSIFUNC_ATTN;  /* it's an attention */
  memcpy(block + 2, &id, sizeof(id));
  /* code = 0 */
  memcpy(block + 8, &nlen, sizeof(nlen));
  memcpy(block + 16, &flags, sizeof(flags));
  /* reserved = 0 */

  /* send an attention */
  return dsi_stream_write(dsi, block, DSI_BLOCKSIZ + len, DSI_NOWAIT);
}
Exemplo n.º 2
0
/* server generated tickles. as this is only called by the tickle handler,
 * we don't need to block signals. */
int dsi_tickle(DSI *dsi)
{
  char block[DSI_BLOCKSIZ];
  uint16_t id;
  
  if ((dsi->flags & DSI_SLEEPING) || dsi->in_write)
      return 1;

  id = htons(dsi_serverID(dsi));

  memset(block, 0, sizeof(block));
  block[0] = DSIFL_REQUEST;
  block[1] = DSIFUNC_TICKLE;
  memcpy(block + 2, &id, sizeof(id));
  /* code = len = reserved = 0 */

  return dsi_stream_write(dsi, block, DSI_BLOCKSIZ, DSI_NOWAIT);
}
Exemplo n.º 3
0
/* ---------------------------------------
 * write data. 0 on failure. this assumes that dsi_len will never
 * cause an overflow in the data buffer. 
 */
int dsi_stream_send(DSI *dsi, void *buf, size_t length)
{
  char block[DSI_BLOCKSIZ];
  struct iovec iov[2];
  int iovecs = 2;
  size_t towrite;
  ssize_t len;

  LOG(log_maxdebug, logtype_dsi, "dsi_stream_send(%u bytes): START", length);

  if (dsi->flags & DSI_DISCONNECTED)
      return 0;

  dsi_header_pack_reply(dsi, block);

  if (!length) { /* just write the header */
      LOG(log_maxdebug, logtype_dsi, "dsi_stream_send(%u bytes): DSI header, no data", sizeof(block));
    length = (dsi_stream_write(dsi, block, sizeof(block), 0) == sizeof(block));
    return length; /* really 0 on failure, 1 on success */
  }
  
  /* block signals */
  block_sig(dsi);
  iov[0].iov_base = block;
  iov[0].iov_len = sizeof(block);
  iov[1].iov_base = buf;
  iov[1].iov_len = length;
  
  towrite = sizeof(block) + length;
  dsi->write_count += towrite;
  while (towrite > 0) {
      if (((len = writev(dsi->socket, iov, iovecs)) == -1 && errno == EINTR) || (len == 0))
          continue;
    
      if ((size_t)len == towrite) /* wrote everything out */
          break;
      else if (len < 0) { /* error */
          if (errno == EAGAIN || errno == EWOULDBLOCK) {
              if (dsi_peek(dsi) == 0) {
                  continue;
              }
          }
          LOG(log_error, logtype_dsi, "dsi_stream_send: %s", strerror(errno));
          unblock_sig(dsi);
          return 0;
      }
    
      towrite -= len;
      if (towrite > length) { /* skip part of header */
          iov[0].iov_base = (char *) iov[0].iov_base + len;
          iov[0].iov_len -= len;
      } else { /* skip to data */
          if (iovecs == 2) {
              iovecs = 1;
              len -= iov[0].iov_len;
              iov[0] = iov[1];
          }
          iov[0].iov_base = (char *) iov[0].iov_base + len;
          iov[0].iov_len -= len;
      }
  }

  LOG(log_maxdebug, logtype_dsi, "dsi_stream_send(%u bytes): END", length);
  
  unblock_sig(dsi);
  return 1;
}
Exemplo n.º 4
0
ssize_t dsi_stream_read_file(DSI *dsi, const int fromfd, off_t offset, const size_t length, const int err)
{
    int ret = 0;
    size_t written = 0;
    size_t total = length;
    ssize_t len;
    off_t pos = offset;
    char block[DSI_BLOCKSIZ];
#ifdef HAVE_SENDFILEV
    int sfvcnt;
    struct sendfilevec vec[2];
    ssize_t nwritten;
#elif defined(FREEBSD)
    ssize_t nwritten;
    void *hdrp;
    struct sf_hdtr hdr;
    struct iovec iovec;
    hdr.headers = &iovec;
    hdr.hdr_cnt = 1;
    hdr.trailers = NULL;
    hdr.trl_cnt = 0;
    hdrp = &hdr;
#endif

    LOG(log_maxdebug, logtype_dsi, "dsi_stream_read_file(off: %jd, len: %zu)", (intmax_t)offset, length);

    if (dsi->flags & DSI_DISCONNECTED)
        return -1;

    dsi->in_write++;

    dsi->flags |= DSI_NOREPLY;
    dsi->header.dsi_flags = DSIFL_REPLY;
    dsi->header.dsi_len = htonl(length);
    dsi->header.dsi_code = htonl(err);
    dsi_header_pack_reply(dsi, block);

#ifdef HAVE_SENDFILEV
    total += DSI_BLOCKSIZ;
    sfvcnt = 2;
    vec[0].sfv_fd = SFV_FD_SELF;
    vec[0].sfv_flag = 0;
    /* Cast to unsigned long to prevent sign extension of the
     * pointer value for the LFS case; see Apache PR 39463. */
    vec[0].sfv_off = (unsigned long)block;
    vec[0].sfv_len = DSI_BLOCKSIZ;
    vec[1].sfv_fd = fromfd;
    vec[1].sfv_flag = 0;
    vec[1].sfv_off = offset;
    vec[1].sfv_len = length;
#elif defined(FREEBSD)
    iovec.iov_base = block;
    iovec.iov_len = DSI_BLOCKSIZ;
#else
    dsi_stream_write(dsi, block, sizeof(block), DSI_MSG_MORE);
#endif

    while (written < total) {
#ifdef HAVE_SENDFILEV
        nwritten = 0;
        len = sendfilev(dsi->socket, vec, sfvcnt, &nwritten);
#elif defined(FREEBSD)
        len = sendfile(fromfd, dsi->socket, pos, total - written, hdrp, &nwritten, 0);
        if (len == 0)
            len = nwritten;
#else
        len = sys_sendfile(dsi->socket, fromfd, &pos, total - written);
#endif
        if (len < 0) {
            switch (errno) {
            case EINTR:
            case EAGAIN:
                len = 0;
#if defined(HAVE_SENDFILEV) || defined(FREEBSD)
                len = (size_t)nwritten;
#elif defined(SOLARIS)
                if (pos > offset) {
                    /* we actually have sent sth., adjust counters and keep trying */
                    len = pos - offset;
                    offset = pos;
                }
#endif /* HAVE_SENDFILEV */

                if (dsi_peek(dsi) != 0) {
                    ret = -1;
                    goto exit;
                }
                break;
            default:
                LOG(log_error, logtype_dsi, "dsi_stream_read_file: %s", strerror(errno));
                ret = -1;
                goto exit;
            }
        } else if (len == 0) {
            /* afpd is going to exit */
            ret = -1;
            goto exit;
        }
#ifdef HAVE_SENDFILEV
        if (sfvcnt == 2 && len >= vec[0].sfv_len) {
            vec[1].sfv_off += len - vec[0].sfv_len;
            vec[1].sfv_len -= len - vec[0].sfv_len;

            vec[0] = vec[1];
            sfvcnt = 1;
        } else {
            vec[0].sfv_off += len;
            vec[0].sfv_len -= len;
        }
#elif defined(FREEBSD)
        if (hdrp) {
            if (len >= iovec.iov_len) {
                hdrp = NULL;
                len -= iovec.iov_len;   /* len now contains how much sendfile() actually sent from the file */
            } else {
                iovec.iov_len -= len;
                iovec.iov_base += len;
                len = 0;
            }
        }
        pos += len;
#endif  /* HAVE_SENDFILEV */
        LOG(log_maxdebug, logtype_dsi, "dsi_stream_read_file: wrote: %zd", len);
        written += len;
    }
#ifdef HAVE_SENDFILEV
    written -= DSI_BLOCKSIZ;
#endif
    dsi->write_count += written;

exit:
    dsi->in_write--;
    LOG(log_maxdebug, logtype_dsi, "dsi_stream_read_file: written: %zd", written);
    if (ret != 0)
        return -1;
    return written;
}
Exemplo n.º 5
0
/* ---------------------------------------
 * write data. 0 on failure. this assumes that dsi_len will never
 * cause an overflow in the data buffer. 
 */
int dsi_stream_send(DSI *dsi, void *buf, size_t length)
{
  char block[DSI_BLOCKSIZ];
  struct iovec iov[2];
  size_t towrite;
  ssize_t len;

  LOG(log_maxdebug, logtype_dsi, "dsi_stream_send: %u bytes",
      length ? length : sizeof(block));

  if (dsi->flags & DSI_DISCONNECTED)
      return 0;

  block[0] = dsi->header.dsi_flags;
  block[1] = dsi->header.dsi_command;
  memcpy(block + 2, &dsi->header.dsi_requestID, 
	 sizeof(dsi->header.dsi_requestID));
  memcpy(block + 4, &dsi->header.dsi_code, sizeof(dsi->header.dsi_code));
  memcpy(block + 8, &dsi->header.dsi_len, sizeof(dsi->header.dsi_len));
  memcpy(block + 12, &dsi->header.dsi_reserved,
	 sizeof(dsi->header.dsi_reserved));

  if (!length) { /* just write the header */
    length = (dsi_stream_write(dsi, block, sizeof(block), 0) == sizeof(block));
    return length; /* really 0 on failure, 1 on success */
  }
  
  /* block signals */
  block_sig(dsi);
  iov[0].iov_base = block;
  iov[0].iov_len = sizeof(block);
  iov[1].iov_base = buf;
  iov[1].iov_len = length;
  
  towrite = sizeof(block) + length;
  dsi->write_count += towrite;
  while (towrite > 0) {
      if (((len = writev(dsi->socket, iov, 2)) == -1 && errno == EINTR) || (len == 0))
          continue;
    
      if ((size_t)len == towrite) /* wrote everything out */
          break;
      else if (len < 0) { /* error */
          if (errno == EAGAIN || errno == EWOULDBLOCK) {
              if (!dsi_peek(dsi)) {
                  continue;
              }
          }
          LOG(log_error, logtype_dsi, "dsi_stream_send: %s", strerror(errno));
          unblock_sig(dsi);
          return 0;
      }
    
      towrite -= len;
      if (towrite > length) { /* skip part of header */
          iov[0].iov_base = (char *) iov[0].iov_base + len;
          iov[0].iov_len -= len;
      } else { /* skip to data */
          if (iov[0].iov_len) {
              len -= iov[0].iov_len;
              iov[0].iov_len = 0;
          }
          iov[1].iov_base = (char *) iov[1].iov_base + len;
          iov[1].iov_len -= len;
      }
  }
  
  unblock_sig(dsi);
  return 1;
}