]> code.citadel.org Git - citadel.git/blobdiff - libcitadel/lib/stringbuf.c
* implement buffered IO for blob-reading, so you can continue siping from the blob...
[citadel.git] / libcitadel / lib / stringbuf.c
index f64ae13b0e4b0b0acefc1cd946600c154e0a53ee..7db6017d600028d35fd366bb37272740f0bd2f31 100644 (file)
@@ -1350,6 +1350,107 @@ int StrBufTCP_read_buffered_line(StrBuf *Line,
 
 }
 
+/**
+ * \brief Read a line from socket
+ * flushes and closes the FD on error
+ * \param buf the buffer to get the input to
+ * \param Pos pointer to the current read position, should be NULL initialized!
+ * \param fd pointer to the filedescriptor to read
+ * \param append Append to an existing string or replace?
+ * \param Error strerror() on error 
+ * \returns numbers of chars read
+ */
+int StrBufTCP_read_buffered_line_fast(StrBuf *Line, 
+                                     StrBuf *buf, 
+                                     const char **Pos,
+                                     int *fd, 
+                                     int timeout, 
+                                     int selectresolution, 
+                                     const char **Error)
+{
+       int len, rlen;
+       int nSuccessLess = 0;
+       fd_set rfds;
+       const char *pch = NULL;
+        int fdflags;
+       struct timeval tv;
+
+       if ((buf->BufUsed > 0) && (Pos != NULL)) {
+               if (*Pos == NULL)
+                       *Pos = buf->buf;
+               pch = strchr(*Pos, '\n');
+               if (pch != NULL) {
+                       rlen = 0;
+                       len = pch - *Pos;
+                       if (len > 0 && (*(pch - 1) == '\r') )
+                               rlen ++;
+                       StrBufSub(Line, buf, (*Pos - buf->buf), len - rlen);
+                       *Pos = pch + 1;
+                       return len - rlen;
+               }
+       }
+       
+       if (*Pos != NULL) {
+               StrBufCutLeft(buf, (*Pos - buf->buf));
+               *Pos = NULL;
+       }
+       
+       if (buf->BufSize - buf->BufUsed < 10)
+               IncreaseBuf(buf, 1, -1);
+
+       fdflags = fcntl(*fd, F_GETFL);
+       if ((fdflags & O_NONBLOCK) == O_NONBLOCK)
+               return -1;
+
+       while ((nSuccessLess < timeout) && (pch == NULL)) {
+               tv.tv_sec = selectresolution;
+               tv.tv_usec = 0;
+               
+               FD_ZERO(&rfds);
+               FD_SET(*fd, &rfds);
+               if (select(*fd + 1, NULL, &rfds, NULL, &tv) == -1) {
+                       *Error = strerror(errno);
+                       close (*fd);
+                       *fd = -1;
+                       return -1;
+               }               
+               if (FD_ISSET(*fd, &rfds)) {
+                       rlen = read(*fd, 
+                                   &buf->buf[buf->BufUsed], 
+                                   buf->BufSize - buf->BufUsed - 1);
+                       if (rlen < 1) {
+                               *Error = strerror(errno);
+                               close(*fd);
+                               *fd = -1;
+                               return -1;
+                       }
+                       else if (rlen > 0) {
+                               nSuccessLess = 0;
+                               buf->BufUsed += rlen;
+                               buf->buf[buf->BufUsed] = '\0';
+                               if (buf->BufUsed + 10 > buf->BufSize) {
+                                       IncreaseBuf(buf, 1, -1);
+                               }
+                               pch = strchr(buf->buf, '\n');
+                               continue;
+                       }
+               }
+               nSuccessLess ++;
+       }
+       if (pch != NULL) {
+               *Pos = buf->buf;
+               rlen = 0;
+               len = pch - *Pos;
+               if (len > 0 && (*(pch - 1) == '\r') )
+                       rlen ++;
+               StrBufSub(Line, buf, 0, len - rlen);
+               *Pos = *Pos + len + 1;
+               return len - rlen;
+       }
+       return -1;
+
+}
+
 /**
  * \brief Input binary data from socket
  * flushes and closes the FD on error
@@ -1407,6 +1508,93 @@ int StrBufReadBLOB(StrBuf *Buf, int *fd, int append, long nBytes, const char **E
        return nRead;
 }
 
+/**
+ * \brief Input binary data from socket
+ * flushes and closes the FD on error
+ * \param buf the buffer to get the input to
+ * \param fd pointer to the filedescriptor to read
+ * \param append Append to an existing string or replace?
+ * \param nBytes the maximal number of bytes to read
+ * \param Error strerror() on error 
+ * \returns numbers of chars read
+ */
+int StrBufReadBLOBBuffered(StrBuf *Buf, 
+                          StrBuf *IOBuf, 
+                          const char **BufPos,
+                          int *fd, 
+                          int append, 
+                          long nBytes, 
+                          const char **Error)
+{
+        fd_set wset;
+        int fdflags;
+       int len, rlen, slen;
+       int nRead;
+       char *ptr;
+
+       if ((Buf == NULL) || (*fd == -1) || (IOBuf == NULL))
+               return -1;
+       if (!append)
+               FlushStrBuf(Buf);
+       if (Buf->BufUsed + nBytes >= Buf->BufSize)
+               IncreaseBuf(Buf, 1, Buf->BufUsed + nBytes);
+
+
+       len = *BufPos - IOBuf->buf;
+       rlen = IOBuf->BufUsed - len;
+
+       if ((IOBuf->BufUsed > 0) && 
+           ((IOBuf->BufUsed - len > 0))) {
+               if (rlen <= nBytes) {
+                       memcpy(Buf->buf + Buf->BufUsed, *BufPos, rlen);
+                       Buf->BufUsed += rlen;
+                       Buf->buf[Buf->BufUsed] = '\0';
+                       *BufPos = NULL; FlushStrBuf(IOBuf);
+                       nRead = rlen;
+                       if (nRead == nBytes)
+                               return nBytes;
+               }
+               else {
+                       memcpy(Buf->buf + Buf->BufUsed, *BufPos, nBytes);
+                       Buf->BufUsed += nBytes;
+                       Buf->buf[Buf->BufUsed] = '\0';
+                       *BufPos += nBytes;
+                       return nBytes;
+               }
+       }
+
+       ptr = Buf->buf + Buf->BufUsed;
+
+       slen = len = Buf->BufUsed;
+
+       fdflags = fcntl(*fd, F_GETFL);
+
+       while (nRead < nBytes) {
+               if ((fdflags & O_NONBLOCK) == O_NONBLOCK) {
+                        FD_ZERO(&wset);
+                        FD_SET(*fd, &wset);
+                        if (select(*fd + 1, NULL, &wset, NULL, NULL) == -1) {
+                               *Error = strerror(errno);
+                                return -1;
+                        }
+                }
+
+                if ((rlen = read(*fd, 
+                                ptr,
+                                nBytes - nRead)) == -1) {
+                       close(*fd);
+                       *fd = -1;
+                       *Error = strerror(errno);
+                        return rlen;
+                }
+               nRead += rlen;
+               ptr += rlen;
+               Buf->BufUsed += rlen;
+       }
+       Buf->buf[Buf->BufUsed] = '\0';
+       return nRead;
+}
+
 /**
  * \brief Cut nChars from the start of the string
  * \param Buf Buffer to modify