+/*
+ * Copyright (c) 1987-2011 by the citadel.org team
+ *
+ * This program is open source 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 3 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
#include "sysdep.h"
#include <ctype.h>
#include <errno.h>
#include <sys/types.h>
#define SHOW_ME_VAPPEND_PRINTF
#include <stdarg.h>
+#ifndef LINUX_SENDFILE
+#include <sys/sendfile.h>
+#endif
#include "libcitadel.h"
#ifdef HAVE_ICONV
#include <execinfo.h>
#endif
+#ifdef LINUX_SENDFILE
+#include <sys/sendfile.h>
+#endif
+
#ifdef HAVE_ZLIB
#include <zlib.h>
int ZEXPORT compress_gzip(Bytef * dest, size_t * destLen,
const char *aptr, *eiptr;
char *bptr, *eptr;
long len;
+ int IsUtf8Sequence;
if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) )
return -1;
(ch > 126) ||
(ch == 61) ||
(ch == '=') ||
+ (ch == '?') ||
+ (ch == '_') ||
(ch == '[') ||
(ch == ']') )
{
(*target)->BufUsed += 3;
}
else {
- (*target)->buf[(*target)->BufUsed] = ch;
+ if (ch == ' ')
+ (*target)->buf[(*target)->BufUsed] = '_';
+ else
+ (*target)->buf[(*target)->BufUsed] = ch;
(*target)->BufUsed++;
}
}
optr --;
if ((*(ptr - 1) != '\r') && (*(ptr - 1) != '\n')) {
LineBuf->BufUsed = optr - LineBuf->buf;
- *optr = '\0';
+ *optr = '\0';
+ if ((FB->ReadWritePointer != NULL) &&
+ (FB->ReadWritePointer != FB->Buf->buf))
+ {
+ /* Ok, the client application read all the data
+ it was interested in so far. Since there is more to read,
+ we now shrink the buffer, and move the rest over.
+ */
+ StrBufCutLeft(FB->Buf,
+ FB->ReadWritePointer - FB->Buf->buf);
+ FB->ReadWritePointer = FB->Buf->buf;
+ }
return eMustReadMore;
}
}
return eReadSuccess;
}
+long IOBufferStrLength(IOBuffer *FB)
+{
+ if (FB->ReadWritePointer == NULL)
+ return StrLength(FB->Buf);
+
+ return StrLength(FB->Buf) - (FB->ReadWritePointer - FB->Buf->buf);
+}
+
+void FDIOBufferInit(FDIOBuffer *FDB, IOBuffer *IO, int FD, long TotalSendSize)
+{
+ memset(FDB, 0, sizeof(FDIOBuffer));
+ FDB->ChunkSize =
+ FDB->TotalSendSize = TotalSendSize;
+ FDB->IOB = IO;
+#ifndef LINUX_SENDFILE
+ FDB->ChunkBuffer = NewStrBufPlain(NULL, TotalSendSize + 1);
+#else
+ pipe(FDB->SplicePipe);
+#endif
+ FDB->OtherFD = FD;
+}
+
+void FDIOBufferDelete(FDIOBuffer *FDB)
+{
+#ifndef LINUX_SENDFILE
+ FreeStrBuf(&FDB->ChunkBuffer);
+#else
+ close(FDB->SplicePipe[0]);
+ close(FDB->SplicePipe[1]);
+
+#endif
+ close(FDB->OtherFD);
+ memset(FDB, 0, sizeof(FDIOBuffer));
+}
+
+int FileSendChunked(FDIOBuffer *FDB, const char **Err)
+{
+ char *pRead;
+ long nRead = 0;
+
+#ifdef LINUX_SENDFILE
+ ssize_t sent;
+ sent = sendfile(FDB->IOB->fd, FDB->OtherFD, &FDB->TotalSentAlready, FDB->ChunkSendRemain);
+ if (sent == -1)
+ {
+ *Err = strerror(errno);
+ return sent;
+ }
+ FDB->ChunkSendRemain -= sent;
+ FDB->TotalSentAlready += sent;
+ return FDB->ChunkSendRemain;
+#else
+ pRead = FDB->ChunkBuffer->buf;
+ while ((FDB->ChunkBuffer->BufUsed < FDB->TotalSendSize) && (nRead >= 0))
+ {
+ nRead = read(FDB->OtherFD, pRead, FDB->TotalSendSize - FDB->ChunkBuffer->BufUsed);
+ if (nRead > 0) {
+ FDB->ChunkBuffer->BufUsed += nRead;
+ FDB->ChunkBuffer->buf[FDB->ChunkBuffer->BufUsed] = '\0';
+ }
+ else if (nRead == 0) {}
+ else return nRead;
+
+ }
+
+ nRead = write(FDB->IOB->fd, FDB->ChunkBuffer->buf + FDB->TotalSentAlready, FDB->ChunkSendRemain);
+
+ if (nRead >= 0) {
+ FDB->TotalSentAlready += nRead;
+ FDB->ChunkSendRemain -= nRead;
+ return FDB->ChunkSendRemain;
+ }
+ else {
+ return nRead;
+ }
+#endif
+}
+
+int FileRecvChunked(FDIOBuffer *FDB, const char **Err)
+{
+
+#ifdef LINUX_SENDFILE
+ ssize_t sent, pipesize;
+
+ pipesize = splice(FDB->IOB->fd, NULL,
+ FDB->SplicePipe[1], NULL,
+ FDB->ChunkSendRemain,
+ SPLICE_F_MORE | SPLICE_F_MOVE|SPLICE_F_NONBLOCK);
+ if (pipesize == -1)
+ {
+ *Err = strerror(errno);
+ return pipesize;
+ }
+
+ sent = splice(FDB->SplicePipe[0], NULL,
+ FDB->OtherFD, &FDB->TotalSentAlready,
+ pipesize, SPLICE_F_MORE | SPLICE_F_MOVE);
+ if (sent == -1)
+ {
+ *Err = strerror(errno);
+ return sent;
+ }
+ FDB->ChunkSendRemain -= sent;
+ return sent;
+#else
+#endif
+ return 0;
+}
+
+eReadState WriteIOBAlreadyRead(FDIOBuffer *FDB, const char **Error)
+{
+ int IsNonBlock;
+ int fdflags;
+ long rlen;
+ long should_write;
+ int nSuccessLess = 0;
+ struct timeval tv;
+ fd_set rfds;
+
+ fdflags = fcntl(FDB->OtherFD, F_GETFL);
+ IsNonBlock = (fdflags & O_NONBLOCK) == O_NONBLOCK;
+
+ while ((FDB->IOB->ReadWritePointer - FDB->IOB->Buf->buf < FDB->IOB->Buf->BufUsed) &&
+ (FDB->ChunkSendRemain > 0))
+ {
+ if (IsNonBlock){
+ tv.tv_sec = 1; /* selectresolution; */
+ tv.tv_usec = 0;
+
+ FD_ZERO(&rfds);
+ FD_SET(FDB->OtherFD, &rfds);
+ if (select(FDB->OtherFD + 1, NULL, &rfds, NULL, &tv) == -1) {
+ *Error = strerror(errno);
+ return eReadFail;
+ }
+ }
+ if (IsNonBlock && ! FD_ISSET(FDB->OtherFD, &rfds)) {
+ nSuccessLess ++;
+ continue;
+ }
+
+ should_write = FDB->IOB->Buf->BufUsed -
+ (FDB->IOB->ReadWritePointer - FDB->IOB->Buf->buf);
+ if (should_write > FDB->ChunkSendRemain)
+ should_write = FDB->ChunkSendRemain;
+
+ rlen = write(FDB->OtherFD,
+ FDB->IOB->ReadWritePointer,
+ should_write);
+ if (rlen < 1) {
+ *Error = strerror(errno);
+
+ return eReadFail;
+ }
+ FDB->TotalSentAlready += rlen;
+ FDB->IOB->ReadWritePointer += rlen;
+ FDB->ChunkSendRemain -= rlen;
+ }
+ if (FDB->IOB->ReadWritePointer >= FDB->IOB->Buf->buf + FDB->IOB->Buf->BufUsed)
+ {
+ FlushStrBuf(FDB->IOB->Buf);
+ FDB->IOB->ReadWritePointer = NULL;
+ }
+
+ if (FDB->ChunkSendRemain == 0)
+ return eReadSuccess;
+ else
+ return eMustReadMore;
+}
+
/*******************************************************************************
* File I/O; Prefer buffered read since its faster! *
*******************************************************************************/