pike.git / src / modules / _Stdio / sendfile.c

version» Context lines:

pike.git/src/modules/_Stdio/sendfile.c:43:   #include "bignum.h"      #include "file.h"      #include <errno.h>      #ifdef HAVE_SYS_PARAM_H   #include <sys/param.h>   #endif /* HAVE_SYS_PARAM_H */    - #ifdef HAVE_SYS_TYPES_H - #include <sys/types.h> - #endif /* HAVE_SYS_TYPES_H */ -  - #ifdef HAVE_UNISTD_H - #include <unistd.h> - #endif /* HAVE_UNISTD_H */ -  +    #include <sys/stat.h>      #ifdef HAVE_SYS_SOCKET_H   #include <sys/socket.h>   #endif /* HAVE_SYS_SOCKET_H */      #ifdef HAVE_SYS_UIO_H   #include <sys/uio.h>   #endif /* HAVE_SYS_UIO_H */   
pike.git/src/modules/_Stdio/sendfile.c:107:   #define MMAP_SIZE 0x00100000 /* 1M */      #ifndef MAP_FAILED   #define MAP_FAILED ((void *)-1)   #endif /* !MAP_FAILED */      #ifndef MAP_FILE   #define MAP_FILE 0   #endif /* !MAP_FILE */    + #if !defined(SOL_TCP) && defined(IPPROTO_TCP) +  /* SOL_TCP isn't defined in Solaris. */ + #define SOL_TCP IPPROTO_TCP + #endif +    /*    * Only support for threaded operation right now.    */   #ifdef _REENTRANT      #undef THIS   #define THIS ((struct pike_sendfile *)(Pike_fp->current_storage))      /*    * We assume sendfile(2) has been fixed on all OS's by now.
pike.git/src/modules/_Stdio/sendfile.c:150:   /*    * Globals    */      static struct program *pike_sendfile_prog = NULL;      /*    * Struct init code.    */    - static void init_pike_sendfile(struct object *UNUSED(o)) - { -  MEMSET(THIS, 0, sizeof(struct pike_sendfile)); -  -  /* callback doesn't actually need to be initialized since it is a -  * mapped variable, but since we just zapped it with zeroes we need -  * to set the type to T_INT again.. /Hubbe -  */ -  SET_SVAL(THIS->callback, T_INT, NUMBER_NUMBER, integer, 0); - } -  +    static void exit_pike_sendfile(struct object *UNUSED(o))   {    SF_DFPRINTF((stderr, "sendfile: Exiting...\n"));    -  if (THIS->iovs) { +  if (THIS->iovs)    free(THIS->iovs); -  THIS->iovs = NULL; -  } -  if (THIS->buffer) { +  +  if (THIS->buffer)    free(THIS->buffer); -  THIS->buffer = NULL; -  } -  if (THIS->headers) { +  +  if (THIS->headers)    free_array(THIS->headers); -  THIS->headers = NULL; -  } -  if (THIS->trailers) { +  +  if (THIS->trailers)    free_array(THIS->trailers); -  THIS->trailers = NULL; -  } -  if (THIS->from_file) { +  +  if (THIS->from_file)    free_object(THIS->from_file); -  THIS->from_file = NULL; -  } -  if (THIS->to_file) { +  +  if (THIS->to_file)    free_object(THIS->to_file); -  THIS->to_file = NULL; -  } -  if (THIS->args) { -  free_array(THIS->args); -  THIS->args = NULL; -  } -  if (THIS->self) { +     /* This can occur if Pike exits before the backend has started. */ -  +  if (THIS->self)    free_object(THIS->self); -  THIS->self = NULL; -  } -  /* This is not required since this is a mapped variable. -  * /Hubbe -  * But we do it anyway for paranoia reasons. -  * /grubba 1999-10-14 -  */ -  free_svalue(&(THIS->callback)); -  SET_SVAL(THIS->callback, T_INT, NUMBER_NUMBER, integer, 0); -  if (THIS->backend_callback) { +  +  if (THIS->backend_callback)    remove_callback (THIS->backend_callback); -  THIS->backend_callback = NULL; +    } - } +       /*    * Fallback code    */      #ifndef HAVE_WRITEV   #define writev my_writev   static size_t writev(int fd, struct iovec *iov, int n)   {    if (n) {
pike.git/src/modules/_Stdio/sendfile.c:298:   {    ptrdiff_t sent = 0;       SF_DFPRINTF((stderr, "sendfile: send_iov(%d, %p, %d)...\n",    fd, iov, iovcnt));   #ifdef SF_DEBUG    {    int cnt;    for(cnt = 0; cnt < iovcnt; cnt++) {    SF_DFPRINTF((stderr, "sendfile: %4d: iov_base: %p, iov_len: %ld\n", -  cnt, iov[cnt].iov_base, -  DO_NOT_WARN((long)iov[cnt].iov_len))); +  cnt, iov[cnt].iov_base, (long)iov[cnt].iov_len));    }    }   #endif /* SF_DEBUG */       while (iovcnt) {    ptrdiff_t bytes;    int cnt = iovcnt;      #ifdef IOV_MAX    if (cnt > IOV_MAX) cnt = IOV_MAX;
pike.git/src/modules/_Stdio/sendfile.c:328:   #endif       bytes = writev(fd, iov, cnt);       if ((bytes < 0) && (errno == EINTR)) {    continue;    } else if (bytes < 0) {    /* Error or file closed at other end. */    SF_DFPRINTF((stderr, "sendfile: send_iov(): writev() failed with errno:%d.\n"    "sendfile: Sent %ld bytes so far.\n", -  errno, DO_NOT_WARN((long)sent))); +  errno, (long)sent));    return sent;    } else {    sent += bytes;       while (bytes) {    if ((size_t)bytes >= (size_t)iov->iov_len) {    bytes -= iov->iov_len;    iov++;    iovcnt--;    } else {
pike.git/src/modules/_Stdio/sendfile.c:552:   #endif /* HAVE_FREEBSD_SENDFILE || HAVE_HPUX_SENDFILE || HAVE_MACOSX_SENDFILE */       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);    }       SF_DFPRINTF((stderr, "sendfile: Sent %ld bytes so far.\n", -  DO_NOT_WARN((long)this->sent))); +  (long)this->sent));      #if defined(HAVE_SENDFILE) && !defined(HAVE_FREEBSD_SENDFILE) && !defined(HAVE_HPUX_SENDFILE) && !defined(HAVE_MACOSX_SENDFILE)    SF_DFPRINTF((stderr,    "sendfile: Sending file with sendfile() Linux & Solaris.\n"));    {    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 { -  this->len = MAX_LONGEST; +  this->len = MAX_INT64;    }    }    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 */
pike.git/src/modules/_Stdio/sendfile.c:660: Inside #if 0 /* mmap is slower than read/write on most if not all systems */ and #if defined(HAVE_MMAP) && defined(HAVE_MUNMAP)
   /* Shouldn't there be a goto here ? /Hubbe */    /* True. Fixed. /grubba */    goto send_trailers;    }    }    use_read_write:   #endif /* HAVE_MMAP && HAVE_MUNMAP */   #endif    SF_DFPRINTF((stderr, "sendfile: Using read() and write().\n"));    -  fd_lseek(this->from_fd, this->offset, SEEK_SET); +  while ((fd_lseek(this->from_fd, this->offset, SEEK_SET) < 0) && +  (errno == EINTR)) +  ; +     {    ptrdiff_t buflen;    ptrdiff_t len;    if ((this->len > this->buf_size) || (this->len < 0)) {    len = this->buf_size;    }    else -  len = DO_NOT_WARN ((ptrdiff_t) this->len); +  len = (ptrdiff_t) this->len;    while ((buflen = fd_read(this->from_fd, this->buffer, len)) > 0) {    char *buf = this->buffer;    this->len -= buflen;    this->offset += buflen;    while (buflen) {    ptrdiff_t wrlen = fd_write(this->to_fd, buf, buflen);    if ((wrlen < 0) && (errno == EINTR)) {    continue;    } else if (wrlen < 0) {    goto send_trailers;    }    buf += wrlen;    buflen -= wrlen;    this->sent += wrlen;    }    if ((this->len > this->buf_size) || (this->len < 0)) {    len = this->buf_size;    }    else -  len = DO_NOT_WARN ((ptrdiff_t) this->len); +  len = (ptrdiff_t) this->len;    }    }    send_trailers:    SF_DFPRINTF((stderr, "sendfile: Sent %ld bytes so far.\n", -  DO_NOT_WARN((long)this->sent))); +  (long)this->sent));       /* No more need for the buffer */    free(this->buffer);    this->buffer = NULL;       SF_DFPRINTF((stderr, "sendfile: Sending trailers.\n"));       if (this->tr_cnt) {    this->sent += send_iov(this->to_fd, this->tr_iov, this->tr_cnt);    }
pike.git/src/modules/_Stdio/sendfile.c:861:    *!    *! 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].    *! +  *! @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. +  *!    *! @seealso    *! @[Stdio.sendfile()]    */   static void sf_create(INT32 args)   {    struct pike_sendfile sf;    int iovcnt = 0;    struct svalue *cb = NULL; -  LONGEST offset, len; +  INT64 offset, len;       if (THIS->to_file) {    Pike_error("sendfile->create(): Called a second time!\n");    }       /* In case the user has succeeded in initializing _callback    * before create() is called.    */    free_svalue(&(THIS->callback));    SET_SVAL(THIS->callback, T_INT, NUMBER_NUMBER, integer, 0);       /* 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.    */    -  MEMSET(&sf, 0, sizeof(struct pike_sendfile)); +  memset(&sf, 0, sizeof(struct pike_sendfile));    SET_SVAL(sf.callback, T_INT, NUMBER_NUMBER, integer, 0);    -  get_all_args("sendfile", args, "%A%O%l%l%A%o%*", +  get_all_args(NULL, args, "%A%O%l%l%A%o%*",    &(sf.headers), &(sf.from_file), &offset,    &len, &(sf.trailers), &(sf.to_file), &cb);       sf.offset = offset;    sf.len = len;       /* We need to give 'cb' another reference /Hubbe */    /* No, we don't. We steal the reference from the stack.    * /grubba    */
pike.git/src/modules/_Stdio/sendfile.c:911:       /* Fix the trailing args */    push_array(sf.args = aggregate_array(args-7));    args = 8;       /* FIXME: Ought to fix fp so that the backtraces look right. */       /* 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); -  } else if (!(sf.to = (struct my_file *)get_storage(sf.to_file, -  file_program))) { +  } else if (!(sf.to = get_storage(sf.to_file, file_program))) {    struct svalue *sval; -  if (!(sval = (struct svalue *)get_storage(sf.to_file, file_ref_program)) || +  if (!(sval = get_storage(sf.to_file, file_ref_program)) ||    (TYPEOF(*sval) != T_OBJECT) || -  !(sf.to = (struct my_file *)get_storage(sval->u.object, file_program))) { -  SIMPLE_BAD_ARG_ERROR("sendfile", 6, "object(Stdio.File)"); +  !(sf.to = get_storage(sval->u.object, file_program))) { +  SIMPLE_ARG_TYPE_ERROR("sendfile", 6, "object(Stdio.File)");    }    add_ref(sval->u.object);   #ifdef PIKE_DEBUG    if ((TYPEOF(sp[5-args]) != T_OBJECT) ||    (sp[5-args].u.object != sf.to_file)) {    Pike_fatal("sendfile: Stack out of sync(1).\n");    }   #endif /* PIKE_DEBUG */    sf.to_file = sval->u.object;    free_object(sp[5-args].u.object);    sp[5-args].u.object = sf.to_file;    }    if ((sf.to->flags & FILE_LOCK_FD) ||    (sf.to->box.fd < 0)) { -  SIMPLE_BAD_ARG_ERROR("sendfile", 6, "object(Stdio.File)"); +  SIMPLE_ARG_TYPE_ERROR("sendfile", 6, "object(Stdio.File)");    }    sf.to_fd = sf.to->box.fd;       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;    SET_SVAL(sp[1-args], T_INT, NUMBER_NUMBER, integer, 0);    }       if (sf.from_file) {    if (sf.from_file->prog == file_program) {    sf.from = (struct my_file *)(sf.from_file->storage); -  } else if (!(sf.from = (struct my_file *)get_storage(sf.from_file, -  file_program))) { +  } else if (!(sf.from = get_storage(sf.from_file, file_program))) {    struct svalue *sval; -  if (!(sval = (struct svalue *)get_storage(sf.from_file, -  file_ref_program)) || -  !(TYPEOF(*sval) != T_OBJECT) || -  !(sf.from = (struct my_file *)get_storage(sval->u.object, file_program))) { -  SIMPLE_BAD_ARG_ERROR("sendfile", 2, "object(Stdio.File)"); +  if (!(sval = get_storage(sf.from_file, file_ref_program)) || +  (TYPEOF(*sval) != T_OBJECT) || +  !(sf.from = get_storage(sval->u.object, file_program))) { +  SIMPLE_ARG_TYPE_ERROR("sendfile", 2, "object(Stdio.File)");    }    add_ref(sval->u.object);   #ifdef PIKE_DEBUG    if ((TYPEOF(sp[1-args]) != T_OBJECT) ||    (sp[1-args].u.object != sf.from_file)) {    Pike_fatal("sendfile: Stack out of sync(2).\n");    }   #endif /* PIKE_DEBUG */    sf.from_file = sval->u.object;    free_object(sp[1-args].u.object);    sp[1-args].u.object = sf.from_file;    }    if ((sf.from->flags & FILE_LOCK_FD) ||    (sf.from->box.fd < 0)) { -  SIMPLE_BAD_ARG_ERROR("sendfile", 2, "object(Stdio.File)"); +  SIMPLE_ARG_TYPE_ERROR("sendfile", 2, "object(Stdio.File)");    }    sf.from_fd = sf.from->box.fd;    }       /* 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++) {    if ((TYPEOF(a->item[i]) != T_STRING) || (a->item[i].u.string->size_shift)) { -  SIMPLE_BAD_ARG_ERROR("sendfile", 1, "array(string)"); +  SIMPLE_ARG_TYPE_ERROR("sendfile", 1, "array(string)");    }    }    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++) {    if ((TYPEOF(a->item[i]) != T_STRING) || (a->item[i].u.string->size_shift)) { -  SIMPLE_BAD_ARG_ERROR("sendfile", 5, "array(string)"); +  SIMPLE_ARG_TYPE_ERROR("sendfile", 5, "array(string)");    }    }    iovcnt += a->size;    sf.tr_cnt = a->size;    }       /* Set up the iovec's */    if (iovcnt) {   #ifdef HAVE_HPUX_SENDFILE    iovcnt = 2;   #endif /* HAVE_HPUX_SENDFILE */    -  sf.iovs = (struct iovec *)xalloc(sizeof(struct iovec) * iovcnt); +  sf.iovs = xalloc(sizeof(struct iovec) * iovcnt);       sf.hd_iov = sf.iovs;   #ifdef HAVE_HPUX_SENDFILE    sf.tr_iov = sf.iovs + 1;   #else /* !HAVE_HPUX_SENDFILE */    sf.tr_iov = sf.iovs + sf.hd_cnt;   #endif /* HAVE_HPUX_SENDFILE */       if (sf.headers) {    int i;
pike.git/src/modules/_Stdio/sendfile.c:1113: Inside #if defined(PIKE_DEBUG)
   Pike_fatal("sendfile: Stack out of sync(4).\n");    }   #endif /* PIKE_DEBUG */    free_array(sf.trailers);    sp[4-args].u.array = a;    sf.trailers = a;    }       if (sf.from_file) {    /* We may need a buffer to hold the data */ -  if (sf.iovs) { +     ONERROR tmp;    SET_ONERROR(tmp, free, sf.iovs); -  -  sf.buffer = (char *)xalloc(BUF_SIZE); -  +  sf.buffer = xalloc(BUF_SIZE);    UNSET_ONERROR(tmp); -  } else { -  sf.buffer = (char *)xalloc(BUF_SIZE); -  } +     sf.buf_size = BUF_SIZE;    }       {    /* Threaded blocking mode possible */       /* Make sure both file objects are in blocking mode.    */    if (sf.from_file) {    /* set_blocking */
pike.git/src/modules/_Stdio/sendfile.c:1188:    /* The worker will have a ref. */    th_farm(worker, THIS);   #if 0    {    /* Failure */    sf.to->flags &= ~FILE_LOCK_FD;    if (sf.from) {    sf.from->flags &= ~FILE_LOCK_FD;    }    free_object(THIS->self); -  resource_error("Stdio.sendfile", sp, 0, "threads", 1, -  "Failed to create thread.\n"); +  Pike_error("Failed to create thread.\n");    }   #endif /* 0 */    }    return;   }      /*! @endclass    */      #endif /* _REENTRANT */      /*    * Module init code    */   void init_stdio_sendfile(void)   {   #ifdef _REENTRANT    START_NEW_PROGRAM_ID (STDIO_SENDFILE);    ADD_STORAGE(struct pike_sendfile); -  MAP_VARIABLE("_args", tArray, 0, OFFSETOF(pike_sendfile, args), -  T_ARRAY); -  MAP_VARIABLE("_callback", tFuncV(tInt,tMix,tVoid), 0, -  OFFSETOF(pike_sendfile, callback), T_MIXED); +  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);       /* 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_init_callback(init_pike_sendfile); +     set_exit_callback(exit_pike_sendfile);       pike_sendfile_prog = end_program();    add_program_constant("sendfile", pike_sendfile_prog, 0);   #endif /* _REENTRANT */   }      void exit_stdio_sendfile(void)   {   #ifdef _REENTRANT    if (pike_sendfile_prog) {    free_program(pike_sendfile_prog);    pike_sendfile_prog = NULL;    }   #endif /* _REENTRANT */   }      /*! @endmodule    */