/* ARISA - sendfile(2) linkage and drop in replacements for sendfile(2) * Copyright (C) 2004 Carl Ritson * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #define _GNU_SOURCE #define _REENTRANT #define _THREAD_SAFE #include #include #include #include #include #include #include #include "../config.h" #include "globals.h" #include "sendfile.h" /*** Linux ***/ #if defined(HAVE_LINUX) && defined(HAVE_SENDFILE64) \ && defined(HAVE_SYS_SENDFILE_H) #define SENDFILE 1 #include inline ssize_t l_sendfile(int sok, int fd, off_t *off_ptr, size_t count) { return sendfile(sok,fd,off_ptr,count); } const char *sendfile_method = "Linux sendfile(2)"; #endif /* defined(HAVE_LINUX) && defined(HAVE_SENDFILE64) && ... */ /*** FreeBSD ***/ #if defined(HAVE_FREEBSD) && defined(HAVE_SYS_UIO_H) #define SENDFILE 1 #include inline ssize_t l_sendfile(int sok, int fd, off_t *off_ptr, size_t count) { off_t done = 0; ssize_t ret = -1; if(sendfile(fd,sok,*off_ptr,count,NULL,&done,0) == 0) { ret = (ssize_t) done; (*off_ptr) += done; } return ret; } const char *sendfile_method = "FreeBSD sendfile(2)"; #endif /* defined(HAVE_FREEBSD) && defined(HAVE_SYS_UIO_H) */ /*** MMAP Based Substitute ***/ #if 0 #if !defined(SENDFILE) && defined(HAVE_MMAP64) #define SENDFILE 1 #ifdef HAVE_SYS_MMAN_H #include #endif /* HAVE_SYS_MMAN_H */ inline ssize_t l_sendfile(int sok, int fd, off_t *off_ptr, size_t count) { ssize_t ret = 0; size_t size; off_t off = *off_ptr; char *data; int shift; shift = off % (off_t) page_size; off -= (off_t) shift; size = count + shift; data = mmap(NULL,size,PROT_READ,MAP_PRIVATE,fd,off); if(data == NULL) return -1; ret = send(sok,data+shift,count,0); if(ret > 0) *off_ptr += (off_t) ret; munmap(data,size); return ret; } const char *sendfile_method = "mmap(2)"; #endif /* !defined(SENDFILE) && defined(HAVE_MMAP64) */ #endif /*** READ + SEND Based Substitute ***/ #if !defined(SENDFILE) #define SENDFILE 1 inline ssize_t l_sendfile(int sok, int fd, off_t *off_ptr, size_t count) { char buffer[4096]; ssize_t tmp, sent = 0, ret = 0; off_t ipos = lseek(fd,0,SEEK_CUR); // get present position if(ipos == (off_t)-1) return -1; if(lseek(fd,*off_ptr,SEEK_SET) == (off_t)-1) return -1; while(sent < count) { ret = read(fd,buffer, count - sent < sizeof(buffer) ? count - sent : sizeof(buffer)); if(ret <= 0) break; tmp = ret; // store the number of bytes read for later ret = send(sok,buffer,ret,0); if(ret <= 0) break; sent += ret; /* If not all bytes were sent backout, as it suggests that the * next send call will fail (with EAGAIN). * This also saves us messing about with file offsets. */ if(ret < tmp) break; } (*off_ptr) += (off_t) sent; if(ret != -1) ret = sent; lseek(fd,ipos,SEEK_SET); // restore position, if this fails *tough* return ret; } const char *sendfile_method = "read(2) + send(2)"; #endif /* ! SENDFILE */