e576bb2002-10-11Martin Nilsson /* || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. */
1b10db2002-10-08Martin Nilsson 
fe749b2013-06-17Martin Nilsson /*! @module Stdio
c592502012-05-12Henrik Grubbström (Grubba)  */ /*! @class sendfile *! *! Send @expr{headers + from_fd[off..off+len-1] + trailers@} to *! @expr{to_fd@} asyncronously. *! *! @note *! This is the low-level implementation, which has several limitations. *! You probably want to use @[Stdio.sendfile()] instead. *! *! @seealso *! @[Stdio.sendfile()]
f439fc1999-04-03Henrik Grubbström (Grubba)  */
848dec1999-04-18Henrik Grubbström (Grubba) /* * FIXME: * Support for NT. * * Need to lock the fd's so that the user can't close them for us. */
f439fc1999-04-03Henrik Grubbström (Grubba) #include "global.h"
b30f5a1999-04-20Henrik Grubbström (Grubba) #include "file_machine.h"
f439fc1999-04-03Henrik Grubbström (Grubba) 
a1209a1999-04-20Henrik Grubbström (Grubba) #include "fdlib.h"
f439fc1999-04-03Henrik Grubbström (Grubba) #include "fd_control.h" #include "object.h" #include "array.h" #include "threads.h" #include "interpret.h" #include "svalue.h" #include "callback.h" #include "backend.h" #include "module_support.h"
7978572000-08-19Henrik Grubbström (Grubba) #include "bignum.h"
f439fc1999-04-03Henrik Grubbström (Grubba) 
61e49f1999-04-20Henrik Grubbström (Grubba) #include "file.h"
f439fc1999-04-03Henrik Grubbström (Grubba) #include <errno.h>
e5510f2000-03-13Henrik Grubbström (Grubba) #ifdef HAVE_SYS_PARAM_H #include <sys/param.h> #endif /* HAVE_SYS_PARAM_H */
7e74561999-04-18Henrik Grubbström (Grubba) #include <sys/stat.h>
7acc901999-05-08Simon Coggins #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif /* HAVE_SYS_SOCKET_H */
f439fc1999-04-03Henrik Grubbström (Grubba) #ifdef HAVE_SYS_UIO_H #include <sys/uio.h> #endif /* HAVE_SYS_UIO_H */
0533952004-03-30Henrik Grubbström (Grubba) #ifdef HAVE_NETINET_TCP_H #include <netinet/tcp.h> #endif /* HAVE_NETINET_TCP_H */
c870812004-04-14Henrik Grubbström (Grubba) #ifdef HAVE_SYS_SENDFILE_H
5df5b42004-04-15Henrik Grubbström (Grubba) #ifndef HAVE_BROKEN_SYS_SENDFILE_H
c870812004-04-14Henrik Grubbström (Grubba) #include <sys/sendfile.h>
5df5b42004-04-15Henrik Grubbström (Grubba) #endif /* !HAVE_BROKEN_SYS_SENDFILE_H */
c870812004-04-14Henrik Grubbström (Grubba) #endif /* HAVE_SYS_SENDFILE_H */
af25a22000-08-12Per Hedbor #if 0
848dec1999-04-18Henrik Grubbström (Grubba) #ifdef HAVE_SYS_MMAN_H #include <sys/mman.h> #else /* !HAVE_SYS_MMAN_H */ #ifdef HAVE_LINUX_MMAN_H #include <linux/mman.h> #else /* !HAVE_LINUX_MMAN_H */
af25a22000-08-12Per Hedbor #ifdef HAVE_MMAP /* sys/mman.h is _probably_ there anyway. */
848dec1999-04-18Henrik Grubbström (Grubba) #include <sys/mman.h> #endif /* HAVE_MMAP */ #endif /* HAVE_LINUX_MMAN_H */ #endif /* HAVE_SYS_MMAN_H */
af25a22000-08-12Per Hedbor #endif
848dec1999-04-18Henrik Grubbström (Grubba) 
6ad2372002-05-11Martin Nilsson #define sp Pike_sp
d41c4c2000-12-02Henrik Grubbström (Grubba) /* #define SF_DEBUG */
f439fc1999-04-03Henrik Grubbström (Grubba)  #ifdef SF_DEBUG #define SF_DFPRINTF(X) fprintf X #else /* !SF_DEBUG */ #define SF_DFPRINTF(X) #endif /* SF_DEBUG */
848dec1999-04-18Henrik Grubbström (Grubba) #define BUF_SIZE 0x00010000 /* 64K */ #define MMAP_SIZE 0x00100000 /* 1M */ #ifndef MAP_FAILED #define MAP_FAILED ((void *)-1)
7e74561999-04-18Henrik Grubbström (Grubba) #endif /* !MAP_FAILED */ #ifndef MAP_FILE #define MAP_FILE 0 #endif /* !MAP_FILE */
f4b4de2014-10-17Henrik Grubbström (Grubba) #if !defined(SOL_TCP) && defined(IPPROTO_TCP)
adde172014-10-17Henrik Grubbström (Grubba)  /* SOL_TCP isn't defined in Solaris. */ #define SOL_TCP IPPROTO_TCP #endif
ea496f1999-04-14Henrik Grubbström (Grubba) /* * Only support for threaded operation right now. */ #ifdef _REENTRANT
ccbfdc1999-05-13David Hedbor #undef THIS
206c152000-07-07Henrik Grubbström (Grubba) #define THIS ((struct pike_sendfile *)(Pike_fp->current_storage))
f439fc1999-04-03Henrik Grubbström (Grubba) 
ea496f1999-04-14Henrik Grubbström (Grubba) /*
0533952004-03-30Henrik Grubbström (Grubba)  * We assume sendfile(2) has been fixed on all OS's by now. * FIXME: Configure tests? * /grubba 2004-03-30 */ #if 0 /*
e7ae8b2000-10-19Henrik Grubbström (Grubba)  * All known versions of sendfile(2) are broken.
0533952004-03-30Henrik Grubbström (Grubba)  * /grubba 2000-10-19
e7ae8b2000-10-19Henrik Grubbström (Grubba)  */ #ifndef HAVE_BROKEN_SENDFILE #define HAVE_BROKEN_SENDFILE #endif /* !HAVE_BROKEN_SENDFILE */
0533952004-03-30Henrik Grubbström (Grubba) #endif /* 0 */
e7ae8b2000-10-19Henrik Grubbström (Grubba)  /*
4b776e2000-03-21Henrik Grubbström (Grubba)  * Disable any use of sendfile(2) if HAVE_BROKEN_SENDFILE is defined.
e5510f2000-03-13Henrik Grubbström (Grubba)  */
4b776e2000-03-21Henrik Grubbström (Grubba) #ifdef HAVE_BROKEN_SENDFILE #undef HAVE_SENDFILE
e5510f2000-03-13Henrik Grubbström (Grubba) #undef HAVE_FREEBSD_SENDFILE
4b776e2000-03-21Henrik Grubbström (Grubba) #undef HAVE_HPUX_SENDFILE
da94d52008-07-10Henrik Grubbström (Grubba) #undef HAVE_MACOSX_SENDFILE
4b776e2000-03-21Henrik Grubbström (Grubba) #endif /* HAVE_BROKEN_SENDFILE */
e5510f2000-03-13Henrik Grubbström (Grubba)  /*
ea496f1999-04-14Henrik Grubbström (Grubba)  * Globals */
f439fc1999-04-03Henrik Grubbström (Grubba) static struct program *pike_sendfile_prog = NULL; /* * Struct init code. */
74dfe82012-12-30Jonas Walldén static void exit_pike_sendfile(struct object *UNUSED(o))
f439fc1999-04-03Henrik Grubbström (Grubba) {
525f1a1999-08-17Henrik Grubbström (Grubba)  SF_DFPRINTF((stderr, "sendfile: Exiting...\n"));
40338f2017-07-10Martin Nilsson  if (THIS->iovs)
f439fc1999-04-03Henrik Grubbström (Grubba)  free(THIS->iovs);
40338f2017-07-10Martin Nilsson  if (THIS->buffer)
ea496f1999-04-14Henrik Grubbström (Grubba)  free(THIS->buffer);
40338f2017-07-10Martin Nilsson  if (THIS->headers)
f439fc1999-04-03Henrik Grubbström (Grubba)  free_array(THIS->headers);
40338f2017-07-10Martin Nilsson  if (THIS->trailers)
f439fc1999-04-03Henrik Grubbström (Grubba)  free_array(THIS->trailers);
40338f2017-07-10Martin Nilsson  if (THIS->from_file)
f439fc1999-04-03Henrik Grubbström (Grubba)  free_object(THIS->from_file);
40338f2017-07-10Martin Nilsson  if (THIS->to_file)
f439fc1999-04-03Henrik Grubbström (Grubba)  free_object(THIS->to_file);
40338f2017-07-10Martin Nilsson  /* This can occur if Pike exits before the backend has started. */ if (THIS->self)
f439fc1999-04-03Henrik Grubbström (Grubba)  free_object(THIS->self);
40338f2017-07-10Martin Nilsson  if (THIS->backend_callback)
f33d082003-06-02Martin Stjernholm  remove_callback (THIS->backend_callback);
f439fc1999-04-03Henrik Grubbström (Grubba) } /*
ea496f1999-04-14Henrik Grubbström (Grubba)  * Fallback code
f439fc1999-04-03Henrik Grubbström (Grubba)  */
ea496f1999-04-14Henrik Grubbström (Grubba) #ifndef HAVE_WRITEV #define writev my_writev
2204d22000-08-07Henrik Grubbström (Grubba) static size_t writev(int fd, struct iovec *iov, int n)
f439fc1999-04-03Henrik Grubbström (Grubba) {
ea496f1999-04-14Henrik Grubbström (Grubba)  if (n) {
ccbfdc1999-05-13David Hedbor  return fd_write(fd, iov->iov_base, iov->iov_len);
ea496f1999-04-14Henrik Grubbström (Grubba)  } return 0; } #endif /* !HAVE_WRITEV */
f439fc1999-04-03Henrik Grubbström (Grubba) 
ea496f1999-04-14Henrik Grubbström (Grubba) /* * Helper functions */
f439fc1999-04-03Henrik Grubbström (Grubba) 
023e682000-01-27Henrik Grubbström (Grubba) static void sf_call_callback(struct pike_sendfile *this)
ea496f1999-04-14Henrik Grubbström (Grubba) {
1a11662000-10-07Henrik Grubbström (Grubba)  debug_malloc_touch(this->args);
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(this->callback) != T_INT) { if (((TYPEOF(this->callback) == T_OBJECT) || ((TYPEOF(this->callback) == T_FUNCTION) && (SUBTYPEOF(this->callback) != FUNCTION_BUILTIN))) &&
c4c5f12005-10-19Henrik Grubbström (Grubba)  !this->callback.u.object->prog) { /* Destructed object or function. */ free_array(this->args); this->args = NULL; } else { int sz = this->args->size; push_int64(this->sent); push_array_items(this->args); this->args = NULL; apply_svalue(&this->callback, 1 + sz); pop_stack(); }
f439fc1999-04-03Henrik Grubbström (Grubba)  free_svalue(&this->callback);
017b572011-10-28Henrik Grubbström (Grubba)  SET_SVAL(this->callback, T_INT, NUMBER_NUMBER, integer, 0);
ea496f1999-04-14Henrik Grubbström (Grubba)  } else { free_array(this->args); this->args = NULL; } }
74dfe82012-12-30Jonas Walldén static void call_callback_and_free(struct callback *cb, void *this_, void *UNUSED(arg))
ea496f1999-04-14Henrik Grubbström (Grubba) { struct pike_sendfile *this = this_; SF_DFPRINTF((stderr, "sendfile: Calling callback...\n")); remove_callback(cb);
f33d082003-06-02Martin Stjernholm  this->backend_callback = NULL;
ea496f1999-04-14Henrik Grubbström (Grubba)  if (this->self) {
a4a1722000-12-05Per Hedbor  /* Make sure we get freed in case of error */
ea496f1999-04-14Henrik Grubbström (Grubba)  push_object(this->self); this->self = NULL;
f439fc1999-04-03Henrik Grubbström (Grubba)  }
ea496f1999-04-14Henrik Grubbström (Grubba)  sf_call_callback(this);
f439fc1999-04-03Henrik Grubbström (Grubba)  /* Free ourselves */ pop_stack(); }
ea496f1999-04-14Henrik Grubbström (Grubba) /*
13670c2015-05-25Martin Nilsson  * Code called in the threaded case.
ea496f1999-04-14Henrik Grubbström (Grubba)  */
f439fc1999-04-03Henrik Grubbström (Grubba) /* writev() without the IOV_MAX limit. */
1330e12000-08-10Henrik Grubbström (Grubba) static ptrdiff_t send_iov(int fd, struct iovec *iov, int iovcnt)
f439fc1999-04-03Henrik Grubbström (Grubba) {
1330e12000-08-10Henrik Grubbström (Grubba)  ptrdiff_t sent = 0;
f439fc1999-04-03Henrik Grubbström (Grubba) 
a335c02000-10-23Henrik Grubbström (Grubba)  SF_DFPRINTF((stderr, "sendfile: send_iov(%d, %p, %d)...\n", fd, iov, iovcnt)); #ifdef SF_DEBUG { int cnt; for(cnt = 0; cnt < iovcnt; cnt++) {
4081122000-12-02Henrik Grubbström (Grubba)  SF_DFPRINTF((stderr, "sendfile: %4d: iov_base: %p, iov_len: %ld\n",
cc7cf42015-10-14Martin Nilsson  cnt, iov[cnt].iov_base, (long)iov[cnt].iov_len));
a335c02000-10-23Henrik Grubbström (Grubba)  } } #endif /* SF_DEBUG */
f439fc1999-04-03Henrik Grubbström (Grubba)  while (iovcnt) {
1330e12000-08-10Henrik Grubbström (Grubba)  ptrdiff_t bytes;
f439fc1999-04-03Henrik Grubbström (Grubba)  int cnt = iovcnt; #ifdef IOV_MAX if (cnt > IOV_MAX) cnt = IOV_MAX; #endif
a335c02000-10-23Henrik Grubbström (Grubba) #ifdef DEF_IOV_MAX if (cnt > DEF_IOV_MAX) cnt = DEF_IOV_MAX; #endif
f439fc1999-04-03Henrik Grubbström (Grubba) #ifdef MAX_IOVEC if (cnt > MAX_IOVEC) cnt = MAX_IOVEC; #endif bytes = writev(fd, iov, cnt); if ((bytes < 0) && (errno == EINTR)) { continue;
fc66db2000-01-24Henrik Grubbström (Grubba)  } else if (bytes < 0) {
f439fc1999-04-03Henrik Grubbström (Grubba)  /* Error or file closed at other end. */
a335c02000-10-23Henrik Grubbström (Grubba)  SF_DFPRINTF((stderr, "sendfile: send_iov(): writev() failed with errno:%d.\n" "sendfile: Sent %ld bytes so far.\n",
cc7cf42015-10-14Martin Nilsson  errno, (long)sent));
f439fc1999-04-03Henrik Grubbström (Grubba)  return sent; } else { sent += bytes; while (bytes) {
2204d22000-08-07Henrik Grubbström (Grubba)  if ((size_t)bytes >= (size_t)iov->iov_len) {
f439fc1999-04-03Henrik Grubbström (Grubba)  bytes -= iov->iov_len; iov++; iovcnt--; } else { iov->iov_base = ((char *)iov->iov_base) + bytes; iov->iov_len -= bytes; break; } } } }
a335c02000-10-23Henrik Grubbström (Grubba)  SF_DFPRINTF((stderr, "sendfile: send_iov(): Sent %d bytes\n", sent));
f439fc1999-04-03Henrik Grubbström (Grubba)  return sent; }
023e682000-01-27Henrik Grubbström (Grubba) void low_do_sendfile(struct pike_sendfile *this)
f439fc1999-04-03Henrik Grubbström (Grubba) {
0533952004-03-30Henrik Grubbström (Grubba) #if defined(SOL_TCP) && (defined(TCP_CORK) || defined(TCP_NODELAY)) int old_val = -1;
2d76f22005-05-20Martin Stjernholm  socklen_t old_len = (socklen_t) sizeof(old_val);
0533952004-03-30Henrik Grubbström (Grubba) #ifdef TCP_CORK int new_val = 1; #else /* !TCP_CORK */ int new_val = 0; #endif /* TCP_CORK */ #endif /* SOL_TCP && (TCP_CORK || TCP_NODELAY) */
f439fc1999-04-03Henrik Grubbström (Grubba)  /* Make sure we're using blocking I/O */ set_nonblocking(this->to_fd, 0);
0533952004-03-30Henrik Grubbström (Grubba) #ifdef SOL_TCP #ifdef TCP_CORK /* Attempt to set the out socket into cork mode. * FIXME: Do we need to adjust TCP_NODELAY here? */ while ((getsockopt(this->to_fd, SOL_TCP, TCP_CORK,
c870812004-04-14Henrik Grubbström (Grubba)  &old_val, &old_len)<0) &&
0533952004-03-30Henrik Grubbström (Grubba)  (errno == EINTR)) ; if (!old_val) { while ((setsockopt(this->to_fd, SOL_TCP, TCP_CORK, &new_val, sizeof(new_val))<0) && (errno == EINTR)) ; } #elif defined(TCP_NODELAY) /* Attempt to set the out socket into nagle mode. */ while ((getsockopt(this->to_fd, SOL_TCP, TCP_NODELAY,
c870812004-04-14Henrik Grubbström (Grubba)  &old_val, &old_len)<0) &&
0533952004-03-30Henrik Grubbström (Grubba)  (errno == EINTR)) ; if (old_val == 1) { while ((setsockopt(this->to_fd, SOL_TCP, TCP_NODELAY, &new_val, sizeof(new_val))<0) && (errno == EINTR)) ;
13670c2015-05-25Martin Nilsson  }
0533952004-03-30Henrik Grubbström (Grubba) #endif /* TCP_CORK || TCP_NODELAY */ #endif /* SOL_TCP */
f439fc1999-04-03Henrik Grubbström (Grubba)  SF_DFPRINTF((stderr, "sendfile: Worker started\n")); if ((this->from_file) && (this->len)) {
da94d52008-07-10Henrik Grubbström (Grubba) #if defined(HAVE_FREEBSD_SENDFILE) || defined(HAVE_HPUX_SENDFILE) || defined(HAVE_MACOSX_SENDFILE)
f439fc1999-04-03Henrik Grubbström (Grubba)  off_t sent = 0; int len = this->len;
675f641999-06-23Henrik Grubbström (Grubba)  int res;
f439fc1999-04-03Henrik Grubbström (Grubba) 
da94d52008-07-10Henrik Grubbström (Grubba) #if defined(HAVE_FREEBSD_SENDFILE) || defined(HAVE_MACOSX_SENDFILE)
675f641999-06-23Henrik Grubbström (Grubba)  struct sf_hdtr hdtr = { NULL, 0, NULL, 0 };
da94d52008-07-10Henrik Grubbström (Grubba) #ifdef HAVE_FREEBSD_SENDFILE
f439fc1999-04-03Henrik Grubbström (Grubba)  SF_DFPRINTF((stderr, "sendfile: Using FreeBSD-style sendfile()\n"));
da94d52008-07-10Henrik Grubbström (Grubba) #else SF_DFPRINTF((stderr, "sendfile: Using MacOS X-style sendfile()\n")); #endif
f439fc1999-04-03Henrik Grubbström (Grubba)  if (this->hd_cnt) { hdtr.headers = this->hd_iov; hdtr.hdr_cnt = this->hd_cnt; } if (this->tr_cnt) { hdtr.trailers = this->tr_iov; hdtr.trl_cnt = this->tr_cnt; }
da94d52008-07-10Henrik Grubbström (Grubba) #else /* !(HAVE_FREEBSD_SENDFILE || HAVE_MACOSX_SENDFILE) */
2820c41999-10-15Henrik Grubbström (Grubba)  /* HPUX_SENDFILE */
675f641999-06-23Henrik Grubbström (Grubba)  struct iovec hdtr[2] = { NULL, 0, NULL, 0 }; SF_DFPRINTF((stderr, "sendfile: Using HP/UX-style sendfile()\n")); /* NOTE: hd_cnt/tr_cnt are always 0 or 1 since * we've joined the headers/trailers in sf_create(). */ if (this->hd_cnt) { hdtr[0].iov_base = this->hd_iov->iov_base; hdtr[0].iov_len = this->hd_iov->iov_len; } if (this->tr_cnt) { hdtr[1].iov_base = this->tr_iov->iov_base; hdtr[1].iov_len = this->tr_iov->iov_len; } #endif /* HAVE_FREEBSD_SENDFILE */
f439fc1999-04-03Henrik Grubbström (Grubba)  if (len < 0) {
2247be2008-02-20Henrik Grubbström (Grubba)  /* Send entire file. * * From FreeBSD: * The nbytes argument specifies how many bytes of the file * should be sent, with 0 having the special meaning of send * until the end of file has been reached.
da94d52008-07-10Henrik Grubbström (Grubba)  * * From HPUX: * nbytes is the number of bytes to be sent from the file. If * this parameter is set to zero, data from the offset to the * end of the file will be sent. * * From MacOS X: * The len argument is a value-result parameter, that * specifies how many bytes of the file should be sent and/or * how many bytes have been sent. Initially the value pointed * to by the len argument specifies how many bytes should be * sent with 0 having the special meaning to send until the * end of file has been reached. On return the value pointed * to by the len argument indicates how many bytes have been * sent. The len pointer may not be NULL.
2247be2008-02-20Henrik Grubbström (Grubba)  */
f439fc1999-04-03Henrik Grubbström (Grubba)  len = 0; }
b78cc62008-12-17Henrik Grubbström (Grubba) #ifdef HAVE_SENDFILE_HEADER_LEN_PROBLEM if (len) { /* Adjust the length to account for the length of the headers. */ /* From FreeBSD 7.x src/sys/kern/uipc_syscalls.c:kern_sendfile(): * * In FBSD < 5.0 the nbytes to send also included * the header. If compat is specified subtract the * header size from nbytes. */ /* From MacOS X 10.5.6 xnu/bsd/kern/uipc_syscalls.c:sendfile(): * * Get number of bytes to send * Should it applies to size of header and trailer? * JMM - error handling? */ for (res = 0; res < this->hd_cnt; res ++) { len += this->hd_iov[res].iov_len; } } #endif
f439fc1999-04-03Henrik Grubbström (Grubba) 
bb3fc92008-07-10Henrik Grubbström (Grubba)  do {
675f641999-06-23Henrik Grubbström (Grubba) #ifdef HAVE_FREEBSD_SENDFILE
bb3fc92008-07-10Henrik Grubbström (Grubba)  res = sendfile(this->from_fd, this->to_fd, this->offset, len, &hdtr, &sent, 0);
675f641999-06-23Henrik Grubbström (Grubba) #else /* !HAVE_FREEBSD_SENDFILE */
da94d52008-07-10Henrik Grubbström (Grubba) #ifdef HAVE_MACOSX_SENDFILE
bb3fc92008-07-10Henrik Grubbström (Grubba)  sent = len; res = sendfile(this->from_fd, this->to_fd, this->offset, &sent, &hdtr, 0);
da94d52008-07-10Henrik Grubbström (Grubba) #else
0533952004-03-30Henrik Grubbström (Grubba)  /* HPUX_SENDFILE */
bb3fc92008-07-10Henrik Grubbström (Grubba)  res = sendfile(this->to_fd, this->from_fd, this->offset, len, hdtr, 0);
da94d52008-07-10Henrik Grubbström (Grubba) #endif /* HAVE_MACOSX_SENDFILE */
675f641999-06-23Henrik Grubbström (Grubba) #endif /* HAVE_FREEBSD_SENDFILE */
bb3fc92008-07-10Henrik Grubbström (Grubba)  SF_DFPRINTF((stderr, "sendfile: sendfile() returned %d\n", res)); } while ((res < 0) && (errno == EINTR));
2c63932000-03-13 Kai Voigt 
675f641999-06-23Henrik Grubbström (Grubba)  if (res < 0) {
f439fc1999-04-03Henrik Grubbström (Grubba)  switch(errno) { default: case ENOTSOCK: case EINVAL: /* Try doing it by hand instead. */ goto fallback; break; case EFAULT: /* Bad arguments */
675f641999-06-23Henrik Grubbström (Grubba) #ifdef HAVE_FREEBSD_SENDFILE
5aad932002-08-15Marcus Comstedt  Pike_fatal("FreeBSD style sendfile(): EFAULT\n");
675f641999-06-23Henrik Grubbström (Grubba) #else /* !HAVE_FREEBSD_SENDFILE */
0533952004-03-30Henrik Grubbström (Grubba)  /* HPUX_SENDFILE */
5aad932002-08-15Marcus Comstedt  Pike_fatal("HP/UX style sendfile(): EFAULT\n");
675f641999-06-23Henrik Grubbström (Grubba) #endif /* HAVE_FREEBSD_SENDFILE */
f439fc1999-04-03Henrik Grubbström (Grubba)  break; case EBADF:
7acc901999-05-08Simon Coggins  case ENOTCONN:
f439fc1999-04-03Henrik Grubbström (Grubba)  case EPIPE: case EIO: case EAGAIN: /* Bad fd's or socket has been closed at other end. */ break; }
da94d52008-07-10Henrik Grubbström (Grubba) #ifdef HAVE_HPUX_SENDFILE
0533952004-03-30Henrik Grubbström (Grubba)  /* HPUX_SENDFILE */
675f641999-06-23Henrik Grubbström (Grubba)  } else { sent = res;
da94d52008-07-10Henrik Grubbström (Grubba) #endif /* HAVE_HPUX_SENDFILE */
f439fc1999-04-03Henrik Grubbström (Grubba)  } this->sent += sent; goto done; fallback:
da94d52008-07-10Henrik Grubbström (Grubba) #endif /* HAVE_FREEBSD_SENDFILE || HAVE_HPUX_SENDFILE || HAVE_MACOSX_SENDFILE */
f439fc1999-04-03Henrik Grubbström (Grubba)  SF_DFPRINTF((stderr, "sendfile: Sending headers\n")); /* Send headers */ if (this->hd_cnt) { this->sent += send_iov(this->to_fd, this->hd_iov, this->hd_cnt); }
a335c02000-10-23Henrik Grubbström (Grubba)  SF_DFPRINTF((stderr, "sendfile: Sent %ld bytes so far.\n",
cc7cf42015-10-14Martin Nilsson  (long)this->sent));
13670c2015-05-25Martin Nilsson 
da94d52008-07-10Henrik Grubbström (Grubba) #if defined(HAVE_SENDFILE) && !defined(HAVE_FREEBSD_SENDFILE) && !defined(HAVE_HPUX_SENDFILE) && !defined(HAVE_MACOSX_SENDFILE)
87ab032008-07-10Henrik Grubbström (Grubba)  SF_DFPRINTF((stderr, "sendfile: Sending file with sendfile() Linux & Solaris.\n"));
f439fc1999-04-03Henrik Grubbström (Grubba)  {
87ab032008-07-10Henrik Grubbström (Grubba)  int fail; off_t offset = this->offset; if (this->len < 0) { PIKE_STAT_T st; if (!fd_fstat(this->from_fd, &st) && S_ISREG(st.st_mode)) { this->len = st.st_size - offset; /* To end of file */ } else {
0a3c552016-05-09Martin Nilsson  this->len = MAX_INT64;
87ab032008-07-10Henrik Grubbström (Grubba)  } } while (this->len > 0) { do { fail = sendfile(this->to_fd, this->from_fd, &offset, this->len); } while ((fail < 0) && (errno == EINTR)); this->offset = offset; if (fail <= 0) { if (!fail) break; /* EOF */ /* Failed: Try normal... */ goto normal; } this->sent += fail; this->len -= fail;
f439fc1999-04-03Henrik Grubbström (Grubba)  } goto send_trailers; } normal:
da94d52008-07-10Henrik Grubbström (Grubba) #endif /* HAVE_SENDFILE && !HAVE_FREEBSD_SENDFILE && !HAVE_HPUX_SENDFILE && !HAVE_MACOSX_SENDFILE */
f439fc1999-04-03Henrik Grubbström (Grubba)  SF_DFPRINTF((stderr, "sendfile: Sending file by hand\n"));
af25a22000-08-12Per Hedbor #if 0 /* mmap is slower than read/write on most if not all systems */
848dec1999-04-18Henrik Grubbström (Grubba) #if defined(HAVE_MMAP) && defined(HAVE_MUNMAP) {
40962a2003-03-27Martin Stjernholm  PIKE_STAT_T st;
848dec1999-04-18Henrik Grubbström (Grubba) 
a1209a1999-04-20Henrik Grubbström (Grubba)  if (!fd_fstat(this->from_fd, &st) &&
848dec1999-04-18Henrik Grubbström (Grubba)  S_ISREG(st.st_mode)) { /* Regular file, try using mmap(). */ SF_DFPRINTF((stderr, "sendfile: from is a regular file - trying mmap().\n")); while (this->len) { void *mem;
b96ca92000-08-19Henrik Grubbström (Grubba)  ptrdiff_t len = st.st_size - this->offset; /* To end of file */
848dec1999-04-18Henrik Grubbström (Grubba)  char *buf; int buflen; if ((len > this->len) && (this->len >= 0)) { len = this->len; } /* Try to limit memory space usage */ if (len > MMAP_SIZE) { len = MMAP_SIZE; }
9a02d31999-10-14Fredrik Hübinette (Hubbe) 
2820c41999-10-15Henrik Grubbström (Grubba)  if (!len) { /* Done */ goto send_trailers; }
9a02d31999-10-14Fredrik Hübinette (Hubbe) 
848dec1999-04-18Henrik Grubbström (Grubba)  mem = mmap(NULL, len, PROT_READ, MAP_FILE|MAP_SHARED, this->from_fd, this->offset);
1492271999-08-27Fredrik Hübinette (Hubbe)  if (((long)mem) == ((long)MAP_FAILED)) {
848dec1999-04-18Henrik Grubbström (Grubba)  /* Try using read & write instead. */ goto use_read_write; }
2820c41999-10-15Henrik Grubbström (Grubba) #if defined(HAVE_MADVISE) && defined(MADV_SEQUENTIAL)
848dec1999-04-18Henrik Grubbström (Grubba)  madvise(mem, len, MADV_SEQUENTIAL);
2820c41999-10-15Henrik Grubbström (Grubba) #endif /* HAVE_MADVISE && MADV_SEQUENTIAL */
848dec1999-04-18Henrik Grubbström (Grubba)  buf = mem; buflen = len; while (buflen) {
a1209a1999-04-20Henrik Grubbström (Grubba)  int wrlen = fd_write(this->to_fd, buf, buflen);
848dec1999-04-18Henrik Grubbström (Grubba)  if ((wrlen < 0) && (errno == EINTR)) { continue;
fc66db2000-01-24Henrik Grubbström (Grubba)  } else if (wrlen < 0) {
848dec1999-04-18Henrik Grubbström (Grubba)  munmap(mem, len); goto send_trailers; } buf += wrlen; buflen -= wrlen; this->sent += wrlen; this->offset += wrlen; if (this->len > 0) { this->len -= wrlen; } } munmap(mem, len); }
9a02d31999-10-14Fredrik Hübinette (Hubbe) 
2820c41999-10-15Henrik Grubbström (Grubba)  /* Shouldn't there be a goto here ? /Hubbe */ /* True. Fixed. /grubba */ goto send_trailers;
848dec1999-04-18Henrik Grubbström (Grubba)  } } use_read_write: #endif /* HAVE_MMAP && HAVE_MUNMAP */
af25a22000-08-12Per Hedbor #endif
848dec1999-04-18Henrik Grubbström (Grubba)  SF_DFPRINTF((stderr, "sendfile: Using read() and write().\n"));
cd85782015-05-04Henrik Grubbström (Grubba)  while ((fd_lseek(this->from_fd, this->offset, SEEK_SET) < 0) && (errno == EINTR)) ;
f439fc1999-04-03Henrik Grubbström (Grubba)  {
b96ca92000-08-19Henrik Grubbström (Grubba)  ptrdiff_t buflen;
097de92006-07-05Martin Stjernholm  ptrdiff_t len; if ((this->len > this->buf_size) || (this->len < 0)) {
2c63932000-03-13 Kai Voigt  len = this->buf_size;
ea496f1999-04-14Henrik Grubbström (Grubba)  }
097de92006-07-05Martin Stjernholm  else
cc7cf42015-10-14Martin Nilsson  len = (ptrdiff_t) this->len;
a1209a1999-04-20Henrik Grubbström (Grubba)  while ((buflen = fd_read(this->from_fd, this->buffer, len)) > 0) {
ea496f1999-04-14Henrik Grubbström (Grubba)  char *buf = this->buffer; this->len -= buflen; this->offset += buflen; while (buflen) {
b96ca92000-08-19Henrik Grubbström (Grubba)  ptrdiff_t wrlen = fd_write(this->to_fd, buf, buflen);
ea496f1999-04-14Henrik Grubbström (Grubba)  if ((wrlen < 0) && (errno == EINTR)) { continue;
fc66db2000-01-24Henrik Grubbström (Grubba)  } else if (wrlen < 0) {
ea496f1999-04-14Henrik Grubbström (Grubba)  goto send_trailers;
f439fc1999-04-03Henrik Grubbström (Grubba)  }
ea496f1999-04-14Henrik Grubbström (Grubba)  buf += wrlen; buflen -= wrlen; this->sent += wrlen; }
097de92006-07-05Martin Stjernholm  if ((this->len > this->buf_size) || (this->len < 0)) {
2c63932000-03-13 Kai Voigt  len = this->buf_size;
f439fc1999-04-03Henrik Grubbström (Grubba)  }
097de92006-07-05Martin Stjernholm  else
cc7cf42015-10-14Martin Nilsson  len = (ptrdiff_t) this->len;
f439fc1999-04-03Henrik Grubbström (Grubba)  } } send_trailers:
a335c02000-10-23Henrik Grubbström (Grubba)  SF_DFPRINTF((stderr, "sendfile: Sent %ld bytes so far.\n",
cc7cf42015-10-14Martin Nilsson  (long)this->sent));
13670c2015-05-25Martin Nilsson 
ea496f1999-04-14Henrik Grubbström (Grubba)  /* No more need for the buffer */ free(this->buffer); this->buffer = NULL;
f439fc1999-04-03Henrik Grubbström (Grubba)  SF_DFPRINTF((stderr, "sendfile: Sending trailers.\n")); if (this->tr_cnt) { this->sent += send_iov(this->to_fd, this->tr_iov, this->tr_cnt); } } else { /* Only headers & trailers */ struct iovec *iov = this->hd_iov; int iovcnt = this->hd_cnt; SF_DFPRINTF((stderr, "sendfile: Only headers & trailers.\n")); if (!iovcnt) { /* Only trailers */ iovcnt = this->tr_cnt; iov = this->tr_iov; } else if (this->tr_cnt) { /* Both headers & trailers */ if (iov + this->hd_cnt != this->tr_iov) { /* They are not back-to-back. Fix! */ int i; struct iovec *iov_tmp = iov + this->hd_cnt; for (i=0; i < this->tr_cnt; i++) { iov_tmp[i] = this->tr_iov[i]; } } /* They are now back-to-back. */ iovcnt += this->tr_cnt; } /* All iovec's are now in iov & iovcnt */ this->sent += send_iov(this->to_fd, iov, iovcnt); }
da94d52008-07-10Henrik Grubbström (Grubba) #if defined(HAVE_FREEBSD_SENDFILE) || defined(HAVE_HPUX_SENDFILE) || defined(HAVE_MACOSX_SENDFILE)
f439fc1999-04-03Henrik Grubbström (Grubba)  done:
da94d52008-07-10Henrik Grubbström (Grubba) #endif /* HAVE_FREEBSD_SENDFILE || HAVE_HPUX_SENDFILE || HAVE_MACOSX_SENDFILE */
f439fc1999-04-03Henrik Grubbström (Grubba) 
0533952004-03-30Henrik Grubbström (Grubba) #ifdef SOL_TCP #ifdef TCP_CORK /* Restore the cork mode for the socket. */ if (!old_val) { while((setsockopt(this->to_fd, SOL_TCP, TCP_CORK,
c870812004-04-14Henrik Grubbström (Grubba)  &old_val, old_len)<0) && (errno == EINTR))
0533952004-03-30Henrik Grubbström (Grubba)  ; } #elif defined(TCP_NODELAY) /* Restore the nagle mode for the socket. */ if (old_val == 1) { while((setsockopt(this->to_fd, SOL_TCP, TCP_NODELAY,
c870812004-04-14Henrik Grubbström (Grubba)  &old_val, old_len)<0) && (errno == EINTR))
0533952004-03-30Henrik Grubbström (Grubba)  ; } #endif /* TCP_CORK || TCP_NODELAY */ #endif /* SOL_TCP */
f439fc1999-04-03Henrik Grubbström (Grubba)  SF_DFPRINTF((stderr, "sendfile: Done. Setting up callback\n" "%d bytes sent\n", this->sent));
0533952004-03-30Henrik Grubbström (Grubba)  /* FIXME: Restore non-blocking mode here? */
023e682000-01-27Henrik Grubbström (Grubba) } static void worker(void *this_) { struct pike_sendfile *this = this_;
9407d82007-05-26Henrik Grubbström (Grubba)  struct Backend_struct *backend;
02428c2007-06-26Henrik Grubbström (Grubba)  struct timeval tv;
023e682000-01-27Henrik Grubbström (Grubba)  low_do_sendfile(this);
f439fc1999-04-03Henrik Grubbström (Grubba) 
5715cc2001-11-01Martin Stjernholm  low_mt_lock_interpreter(); /* Can run even if threads_disabled. */
f439fc1999-04-03Henrik Grubbström (Grubba) 
61e49f1999-04-20Henrik Grubbström (Grubba)  /* * Unlock the fd's */ if (this->from) { if (this->from_file->prog) { this->from->flags &= ~FILE_LOCK_FD; } else { /* Destructed. */
9136692003-10-15Henrik Grubbström (Grubba)  if (this->from_fd >= 0) { fd_close(this->from_fd); }
61e49f1999-04-20Henrik Grubbström (Grubba)  /* Paranoia */
10dac82004-04-05Martin Stjernholm  change_fd_for_box (&this->from->box, -1);
61e49f1999-04-20Henrik Grubbström (Grubba)  } } if (this->to_file->prog) { this->to->flags &= ~FILE_LOCK_FD; } else { /* Destructed */
7640ae2008-01-23Henrik Grubbström (Grubba)  fd_close(this->to_fd);
61e49f1999-04-20Henrik Grubbström (Grubba)  /* Paranoia */
10dac82004-04-05Martin Stjernholm  change_fd_for_box (&this->to->box, -1);
61e49f1999-04-20Henrik Grubbström (Grubba)  }
13670c2015-05-25Martin Nilsson 
f439fc1999-04-03Henrik Grubbström (Grubba)  /* Neither of the following can be done in our current context * so we do them from a backend callback. * * Call the callback. * * Get rid of extra ref to the object, and free ourselves. */
f33d082003-06-02Martin Stjernholm #ifdef PIKE_DEBUG if (this->backend_callback) Pike_fatal ("Didn't expect a backend callback to be installed already.\n"); #endif
9407d82007-05-26Henrik Grubbström (Grubba)  if (!(backend = this->to->box.backend)) { backend = default_backend; }
f33d082003-06-02Martin Stjernholm  this->backend_callback =
9407d82007-05-26Henrik Grubbström (Grubba)  backend_add_backend_callback(backend, call_callback_and_free, this, 0);
f439fc1999-04-03Henrik Grubbström (Grubba)  /* Call as soon as possible. */
02428c2007-06-26Henrik Grubbström (Grubba)  tv.tv_usec = 0; tv.tv_sec = 0; backend_lower_timeout(backend, &tv);
f439fc1999-04-03Henrik Grubbström (Grubba)  /* Wake up the backend */
9407d82007-05-26Henrik Grubbström (Grubba)  backend_wake_up_backend(backend);
be13111999-04-23Henrik Grubbström (Grubba)  /* We're gone... */ num_threads--;
13670c2015-05-25Martin Nilsson 
c91f892000-04-19Martin Stjernholm  mt_unlock_interpreter();
f439fc1999-04-03Henrik Grubbström (Grubba)  /* Die */
b5ee861999-08-17Henrik Grubbström (Grubba)  return;
f439fc1999-04-03Henrik Grubbström (Grubba) } /*
ea496f1999-04-14Henrik Grubbström (Grubba)  * Functions callable from Pike code
f439fc1999-04-03Henrik Grubbström (Grubba)  */
844cc12008-03-29Martin Bähr /*! @decl void create(array(string) headers, object from, int offset, int len, @ *! array(string) trailers, object to, @
2247be2008-02-20Henrik Grubbström (Grubba)  *! function callback, mixed ... args) *! *! Low-level implementation of @[Stdio.sendfile()]. *! *! Sends @[headers] followed by @[len] bytes starting at @[offset] *! from the file @[from] followed by @[trailers] to the file @[to]. *! When completed @[callback] will be called with the total number of *! bytes sent as the first argument, followed by @[args]. *! *! Any of @[headers], @[from] and @[trailers] may be left out *! by setting them to @expr{0@}. *! *! Setting @[offset] to @expr{-1@} means send from the current position in *! @[from]. *! *! Setting @[len] to @expr{-1@} means send until @[from]'s end of file is *! reached. *! *! @note *! Don't use this class directly! Use @[Stdio.sendfile()] instead. *! *! In Pike 7.7 and later the @[callback] function will be called *! from the backend associated with @[to]. *!
ee15042015-10-22Henrik Grubbström (Grubba)  *! @note *! May use blocking I/O and thus trigger process being killed *! with @tt{SIGPIPE@} when the other end closes the connection. *! Add a call to @[signal()] to avoid this. *!
2247be2008-02-20Henrik Grubbström (Grubba)  *! @seealso *! @[Stdio.sendfile()]
f439fc1999-04-03Henrik Grubbström (Grubba)  */ static void sf_create(INT32 args) { struct pike_sendfile sf; int iovcnt = 0; struct svalue *cb = NULL;
0a3c552016-05-09Martin Nilsson  INT64 offset, len;
f439fc1999-04-03Henrik Grubbström (Grubba)  if (THIS->to_file) {
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("sendfile->create(): Called a second time!\n");
f439fc1999-04-03Henrik Grubbström (Grubba)  }
cce8681999-10-14Henrik Grubbström (Grubba)  /* In case the user has succeeded in initializing _callback * before create() is called. */ free_svalue(&(THIS->callback));
017b572011-10-28Henrik Grubbström (Grubba)  SET_SVAL(THIS->callback, T_INT, NUMBER_NUMBER, integer, 0);
cce8681999-10-14Henrik Grubbström (Grubba)  /* NOTE: The references to the stuff in sf are held by the stack. * This means that we can throw errors without needing to clean up. */
21b12a2014-09-03Martin Nilsson  memset(&sf, 0, sizeof(struct pike_sendfile));
017b572011-10-28Henrik Grubbström (Grubba)  SET_SVAL(sf.callback, T_INT, NUMBER_NUMBER, integer, 0);
f439fc1999-04-03Henrik Grubbström (Grubba) 
c91b1d2018-08-05Martin Nilsson  get_all_args(NULL, args, "%A%O%l%l%A%o%*",
a92ad62003-10-13Henrik Grubbström (Grubba)  &(sf.headers), &(sf.from_file), &offset, &len, &(sf.trailers), &(sf.to_file), &cb); sf.offset = offset; sf.len = len;
b53c531999-10-06Fredrik Hübinette (Hubbe)  /* We need to give 'cb' another reference /Hubbe */
cce8681999-10-14Henrik Grubbström (Grubba)  /* No, we don't. We steal the reference from the stack. * /grubba */ /* assign_svalue(&(sf.callback),cb); */ sf.callback = *cb;
f439fc1999-04-03Henrik Grubbström (Grubba)  /* Fix the trailing args */ push_array(sf.args = aggregate_array(args-7)); args = 8;
3002661999-04-17Henrik Grubbström (Grubba)  /* FIXME: Ought to fix fp so that the backtraces look right. */
61e49f1999-04-20Henrik Grubbström (Grubba)  /* Check that we're called with the right kind of objects. */ if (sf.to_file->prog == file_program) { sf.to = (struct my_file *)(sf.to_file->storage);
76f7462014-05-26Martin Nilsson  } else if (!(sf.to = get_storage(sf.to_file, file_program))) {
cfb8312011-09-12Henrik Grubbström (Grubba)  struct svalue *sval;
13b5ed2014-05-26Per Hedbor  if (!(sval = get_storage(sf.to_file, file_ref_program)) ||
017b572011-10-28Henrik Grubbström (Grubba)  (TYPEOF(*sval) != T_OBJECT) ||
13b5ed2014-05-26Per Hedbor  !(sf.to = get_storage(sval->u.object, file_program))) {
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("sendfile", 6, "object(Stdio.File)");
61e49f1999-04-20Henrik Grubbström (Grubba)  }
cfb8312011-09-12Henrik Grubbström (Grubba)  add_ref(sval->u.object);
61e49f1999-04-20Henrik Grubbström (Grubba) #ifdef PIKE_DEBUG
017b572011-10-28Henrik Grubbström (Grubba)  if ((TYPEOF(sp[5-args]) != T_OBJECT) ||
61e49f1999-04-20Henrik Grubbström (Grubba)  (sp[5-args].u.object != sf.to_file)) {
5aad932002-08-15Marcus Comstedt  Pike_fatal("sendfile: Stack out of sync(1).\n");
61e49f1999-04-20Henrik Grubbström (Grubba)  } #endif /* PIKE_DEBUG */
cfb8312011-09-12Henrik Grubbström (Grubba)  sf.to_file = sval->u.object;
7727411999-04-22Henrik Grubbström (Grubba)  free_object(sp[5-args].u.object);
1e5acf1999-04-21Henrik Grubbström (Grubba)  sp[5-args].u.object = sf.to_file;
61e49f1999-04-20Henrik Grubbström (Grubba)  } if ((sf.to->flags & FILE_LOCK_FD) ||
10dac82004-04-05Martin Stjernholm  (sf.to->box.fd < 0)) {
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("sendfile", 6, "object(Stdio.File)");
61e49f1999-04-20Henrik Grubbström (Grubba)  }
10dac82004-04-05Martin Stjernholm  sf.to_fd = sf.to->box.fd;
61e49f1999-04-20Henrik Grubbström (Grubba)  if (sf.from_file && !sf.len) { /* No need for the from_file object. */ /* NOTE: We need to zap from_file from the stack too. */ free_object(sf.from_file); sf.from_file = NULL; sf.from = NULL;
017b572011-10-28Henrik Grubbström (Grubba)  SET_SVAL(sp[1-args], T_INT, NUMBER_NUMBER, integer, 0);
61e49f1999-04-20Henrik Grubbström (Grubba)  } if (sf.from_file) { if (sf.from_file->prog == file_program) { sf.from = (struct my_file *)(sf.from_file->storage);
76f7462014-05-26Martin Nilsson  } else if (!(sf.from = get_storage(sf.from_file, file_program))) {
cfb8312011-09-12Henrik Grubbström (Grubba)  struct svalue *sval;
76f7462014-05-26Martin Nilsson  if (!(sval = get_storage(sf.from_file, file_ref_program)) ||
ab3d032015-03-18Jonas Walldén  (TYPEOF(*sval) != T_OBJECT) ||
13b5ed2014-05-26Per Hedbor  !(sf.from = get_storage(sval->u.object, file_program))) {
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("sendfile", 2, "object(Stdio.File)");
61e49f1999-04-20Henrik Grubbström (Grubba)  }
cfb8312011-09-12Henrik Grubbström (Grubba)  add_ref(sval->u.object);
61e49f1999-04-20Henrik Grubbström (Grubba) #ifdef PIKE_DEBUG
017b572011-10-28Henrik Grubbström (Grubba)  if ((TYPEOF(sp[1-args]) != T_OBJECT) ||
61e49f1999-04-20Henrik Grubbström (Grubba)  (sp[1-args].u.object != sf.from_file)) {
5aad932002-08-15Marcus Comstedt  Pike_fatal("sendfile: Stack out of sync(2).\n");
61e49f1999-04-20Henrik Grubbström (Grubba)  } #endif /* PIKE_DEBUG */
cfb8312011-09-12Henrik Grubbström (Grubba)  sf.from_file = sval->u.object;
1e5acf1999-04-21Henrik Grubbström (Grubba)  free_object(sp[1-args].u.object); sp[1-args].u.object = sf.from_file;
61e49f1999-04-20Henrik Grubbström (Grubba)  } if ((sf.from->flags & FILE_LOCK_FD) ||
10dac82004-04-05Martin Stjernholm  (sf.from->box.fd < 0)) {
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("sendfile", 2, "object(Stdio.File)");
61e49f1999-04-20Henrik Grubbström (Grubba)  }
10dac82004-04-05Martin Stjernholm  sf.from_fd = sf.from->box.fd;
61e49f1999-04-20Henrik Grubbström (Grubba)  }
f439fc1999-04-03Henrik Grubbström (Grubba)  /* Do some extra arg checking */ sf.hd_cnt = 0; if (sf.headers) { struct array *a = sf.headers; int i; for (i=0; i < a->size; i++) {
017b572011-10-28Henrik Grubbström (Grubba)  if ((TYPEOF(a->item[i]) != T_STRING) || (a->item[i].u.string->size_shift)) {
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("sendfile", 1, "array(string)");
f439fc1999-04-03Henrik Grubbström (Grubba)  } } iovcnt = a->size; sf.hd_cnt = a->size; } sf.tr_cnt = 0; if (sf.trailers) { struct array *a = sf.trailers; int i; for (i=0; i < a->size; i++) {
017b572011-10-28Henrik Grubbström (Grubba)  if ((TYPEOF(a->item[i]) != T_STRING) || (a->item[i].u.string->size_shift)) {
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("sendfile", 5, "array(string)");
f439fc1999-04-03Henrik Grubbström (Grubba)  } } iovcnt += a->size; sf.tr_cnt = a->size; } /* Set up the iovec's */ if (iovcnt) {
675f641999-06-23Henrik Grubbström (Grubba) #ifdef HAVE_HPUX_SENDFILE iovcnt = 2; #endif /* HAVE_HPUX_SENDFILE */
dc8d022014-04-27Martin Nilsson  sf.iovs = xalloc(sizeof(struct iovec) * iovcnt);
f439fc1999-04-03Henrik Grubbström (Grubba)  sf.hd_iov = sf.iovs;
675f641999-06-23Henrik Grubbström (Grubba) #ifdef HAVE_HPUX_SENDFILE sf.tr_iov = sf.iovs + 1; #else /* !HAVE_HPUX_SENDFILE */
f439fc1999-04-03Henrik Grubbström (Grubba)  sf.tr_iov = sf.iovs + sf.hd_cnt;
675f641999-06-23Henrik Grubbström (Grubba) #endif /* HAVE_HPUX_SENDFILE */
f439fc1999-04-03Henrik Grubbström (Grubba)  if (sf.headers) { int i; for (i = sf.hd_cnt; i--;) { struct pike_string *s;
675f641999-06-23Henrik Grubbström (Grubba) #ifdef HAVE_HPUX_SENDFILE ref_push_string(sf.headers->item[i].u.string); #else /* !HAVE_HPUX_SENDFILE */
f439fc1999-04-03Henrik Grubbström (Grubba)  if ((s = sf.headers->item[i].u.string)->len) { sf.hd_iov[i].iov_base = s->str; sf.hd_iov[i].iov_len = s->len; } else { sf.hd_iov++; sf.hd_cnt--; }
675f641999-06-23Henrik Grubbström (Grubba) #endif /* HAVE_HPUX_SENDFILE */
f439fc1999-04-03Henrik Grubbström (Grubba)  }
675f641999-06-23Henrik Grubbström (Grubba) #ifdef HAVE_HPUX_SENDFILE if (sf.hd_cnt) { f_add(sf.hd_cnt);
b78cc62008-12-17Henrik Grubbström (Grubba)  sf.hd_cnt = 1;
675f641999-06-23Henrik Grubbström (Grubba)  free_string(sf.headers->item->u.string); sf.headers->item->u.string = sp[-1].u.string; sp--;
fc66db2000-01-24Henrik Grubbström (Grubba)  dmalloc_touch_svalue(sp);
675f641999-06-23Henrik Grubbström (Grubba)  sf.hd_iov->iov_base = sf.headers->item->u.string->str; sf.hd_iov->iov_len = sf.headers->item->u.string->len; } else { sf.hd_iov->iov_base = NULL; sf.hd_iov->iov_len = 0; } #endif /* HAVE_HPUX_SENDFILE */
f439fc1999-04-03Henrik Grubbström (Grubba)  } if (sf.trailers) { int i; for (i = sf.tr_cnt; i--;) { struct pike_string *s;
675f641999-06-23Henrik Grubbström (Grubba) #ifdef HAVE_HPUX_SENDFILE ref_push_string(sf.trailers->item[i].u.string); #else /* !HAVE_HPUX_SENDFILE */
f439fc1999-04-03Henrik Grubbström (Grubba)  if ((s = sf.trailers->item[i].u.string)->len) { sf.tr_iov[i].iov_base = s->str; sf.tr_iov[i].iov_len = s->len; } else { sf.tr_iov++; sf.tr_cnt--; }
675f641999-06-23Henrik Grubbström (Grubba) #endif /* HAVE_HPUX_SENDFILE */ } #ifdef HAVE_HPUX_SENDFILE if (sf.tr_cnt) { f_add(sf.tr_cnt); free_string(sf.trailers->item->u.string); sf.trailers->item->u.string = sp[-1].u.string; sp--;
fc66db2000-01-24Henrik Grubbström (Grubba)  dmalloc_touch_svalue(sp);
675f641999-06-23Henrik Grubbström (Grubba)  sf.tr_iov->iov_base = sf.trailers->item->u.string->str; sf.tr_iov->iov_len = sf.trailers->item->u.string->len; } else { sf.tr_iov->iov_base = NULL; sf.tr_iov->iov_len = 0;
f439fc1999-04-03Henrik Grubbström (Grubba)  }
675f641999-06-23Henrik Grubbström (Grubba) #endif /* HAVE_HPUX_SENDFILE */
f439fc1999-04-03Henrik Grubbström (Grubba)  } } /* We need to copy the arrays since the user might do destructive * operations on them, and we need the arrays to keep references to * the strings. */ if ((sf.headers) && (sf.headers->refs > 1)) { struct array *a = copy_array(sf.headers);
60385b1999-04-21Henrik Grubbström (Grubba) #ifdef PIKE_DEBUG
017b572011-10-28Henrik Grubbström (Grubba)  if ((TYPEOF(sp[-args]) != T_ARRAY) || (sp[-args].u.array != sf.headers)) {
5aad932002-08-15Marcus Comstedt  Pike_fatal("sendfile: Stack out of sync(3).\n");
60385b1999-04-21Henrik Grubbström (Grubba)  } #endif /* PIKE_DEBUG */
f439fc1999-04-03Henrik Grubbström (Grubba)  free_array(sf.headers);
60385b1999-04-21Henrik Grubbström (Grubba)  sp[-args].u.array = a;
f439fc1999-04-03Henrik Grubbström (Grubba)  sf.headers = a; } if ((sf.trailers) && (sf.trailers->refs > 1)) { struct array *a = copy_array(sf.trailers);
60385b1999-04-21Henrik Grubbström (Grubba) #ifdef PIKE_DEBUG
017b572011-10-28Henrik Grubbström (Grubba)  if ((TYPEOF(sp[4-args]) != T_ARRAY) || (sp[4-args].u.array != sf.trailers)) {
5aad932002-08-15Marcus Comstedt  Pike_fatal("sendfile: Stack out of sync(4).\n");
60385b1999-04-21Henrik Grubbström (Grubba)  } #endif /* PIKE_DEBUG */
f439fc1999-04-03Henrik Grubbström (Grubba)  free_array(sf.trailers);
60385b1999-04-21Henrik Grubbström (Grubba)  sp[4-args].u.array = a;
f439fc1999-04-03Henrik Grubbström (Grubba)  sf.trailers = a; }
ea496f1999-04-14Henrik Grubbström (Grubba)  if (sf.from_file) { /* We may need a buffer to hold the data */
dc8d022014-04-27Martin Nilsson  ONERROR tmp; SET_ONERROR(tmp, free, sf.iovs); sf.buffer = xalloc(BUF_SIZE); UNSET_ONERROR(tmp);
2c63932000-03-13 Kai Voigt  sf.buf_size = BUF_SIZE;
ea496f1999-04-14Henrik Grubbström (Grubba)  }
f439fc1999-04-03Henrik Grubbström (Grubba) 
61e49f1999-04-20Henrik Grubbström (Grubba)  {
ea496f1999-04-14Henrik Grubbström (Grubba)  /* Threaded blocking mode possible */ /* Make sure both file objects are in blocking mode. */
3002661999-04-17Henrik Grubbström (Grubba)  if (sf.from_file) {
61e49f1999-04-20Henrik Grubbström (Grubba)  /* set_blocking */ set_nonblocking(sf.from_fd, 0); sf.from->open_mode &= ~FILE_NONBLOCKING;
31d5821999-04-21Henrik Grubbström (Grubba)  /* Fix offset */ if (sf.offset < 0) { sf.offset = fd_lseek(sf.from_fd, 0, SEEK_CUR); if (sf.offset < 0) { sf.offset = 0; } }
ea496f1999-04-14Henrik Grubbström (Grubba)  }
61e49f1999-04-20Henrik Grubbström (Grubba)  /* set_blocking */ set_nonblocking(sf.to_fd, 0); sf.to->open_mode &= ~FILE_NONBLOCKING;
cce8681999-10-14Henrik Grubbström (Grubba) 
3002661999-04-17Henrik Grubbström (Grubba)  /* * Setup done. Note that we keep refs to all refcounted svalues in * our object. */ sp -= args; *THIS = sf;
fc66db2000-01-24Henrik Grubbström (Grubba)  DO_IF_DMALLOC(while(args--) dmalloc_touch_svalue(sp + args));
3002661999-04-17Henrik Grubbström (Grubba)  args = 0; /* FIXME: Ought to fix fp so that the backtraces look right. */
ea496f1999-04-14Henrik Grubbström (Grubba)  /* Note: we hold a reference to ourselves. * The gc() won't find it, so be carefull. */
206c152000-07-07Henrik Grubbström (Grubba)  add_ref(THIS->self = Pike_fp->current_object);
ea496f1999-04-14Henrik Grubbström (Grubba) 
61e49f1999-04-20Henrik Grubbström (Grubba)  /* * Make sure the user can't modify the fd's under us. */ sf.to->flags |= FILE_LOCK_FD; if (sf.from) { sf.from->flags |= FILE_LOCK_FD; }
9a02d31999-10-14Fredrik Hübinette (Hubbe)  /* It is a good idea to increase num_threads before the thread * is actually created, otherwise the backend (or somebody) may * be hogging the interpreter lock... /Hubbe */ num_threads++;
f439fc1999-04-03Henrik Grubbström (Grubba)  /* The worker will have a ref. */
525f1a1999-08-17Henrik Grubbström (Grubba)  th_farm(worker, THIS); #if 0 {
be13111999-04-23Henrik Grubbström (Grubba)  /* Failure */ sf.to->flags &= ~FILE_LOCK_FD; if (sf.from) { sf.from->flags &= ~FILE_LOCK_FD; } free_object(THIS->self);
d118f22018-02-19Martin Nilsson  Pike_error("Failed to create thread.\n");
be13111999-04-23Henrik Grubbström (Grubba)  }
525f1a1999-08-17Henrik Grubbström (Grubba) #endif /* 0 */
f439fc1999-04-03Henrik Grubbström (Grubba)  } return; }
c592502012-05-12Henrik Grubbström (Grubba) /*! @endclass */
ea496f1999-04-14Henrik Grubbström (Grubba) #endif /* _REENTRANT */
f439fc1999-04-03Henrik Grubbström (Grubba) /* * Module init code */
29f9a92013-06-11Martin Nilsson void init_stdio_sendfile(void)
f439fc1999-04-03Henrik Grubbström (Grubba) {
ea496f1999-04-14Henrik Grubbström (Grubba) #ifdef _REENTRANT
48b97a2003-10-28Martin Stjernholm  START_NEW_PROGRAM_ID (STDIO_SENDFILE);
f439fc1999-04-03Henrik Grubbström (Grubba)  ADD_STORAGE(struct pike_sendfile);
4903e82016-01-30Martin Nilsson  PIKE_MAP_VARIABLE("_args", OFFSETOF(pike_sendfile, args), tArray, T_ARRAY, 0); PIKE_MAP_VARIABLE("_callback", OFFSETOF(pike_sendfile, callback), tFuncV(tInt,tMix,tVoid), T_MIXED, 0);
f439fc1999-04-03Henrik Grubbström (Grubba)  /* function(array(string),object,int,int,array(string),object,function(int,mixed...:void),mixed...:void) */ ADD_FUNCTION("create", sf_create, tFuncV(tArr(tStr) tObj tInt tInt tArr(tStr) tObj tFuncV(tInt, tMix, tVoid), tMix, tVoid), 0); set_exit_callback(exit_pike_sendfile); pike_sendfile_prog = end_program(); add_program_constant("sendfile", pike_sendfile_prog, 0);
ea496f1999-04-14Henrik Grubbström (Grubba) #endif /* _REENTRANT */
f439fc1999-04-03Henrik Grubbström (Grubba) }
29f9a92013-06-11Martin Nilsson void exit_stdio_sendfile(void)
f439fc1999-04-03Henrik Grubbström (Grubba) {
ea496f1999-04-14Henrik Grubbström (Grubba) #ifdef _REENTRANT
f439fc1999-04-03Henrik Grubbström (Grubba)  if (pike_sendfile_prog) { free_program(pike_sendfile_prog); pike_sendfile_prog = NULL; }
ea496f1999-04-14Henrik Grubbström (Grubba) #endif /* _REENTRANT */
f439fc1999-04-03Henrik Grubbström (Grubba) }
c592502012-05-12Henrik Grubbström (Grubba)  /*! @endmodule */