Back to index

libcitadel  8.12
Functions
Buffered IO with Asynchroneous reads and no unneeded memmoves (the fast ones)
Stringbuffer, A class for manipulating strings with dynamic buffers

File IO to fill StrBufs; Works with work-buffer shared across several calls; External Cursor to maintain the current read position inside of the buffer the non-fast ones will use memove to keep the start of the buffer the read buffer (which is slower) More...

Collaboration diagram for Buffered IO with Asynchroneous reads and no unneeded memmoves (the fast ones):

Functions

int StrBufTCP_read_buffered_line (StrBuf *Line, StrBuf *buf, int *fd, int timeout, int selectresolution, const char **Error)
 Read a line from socket flushes and closes the FD on error.
int StrBufTCP_read_buffered_line_fast (StrBuf *Line, StrBuf *IOBuf, const char **Pos, int *fd, int timeout, int selectresolution, const char **Error)
 Read a line from socket flushes and closes the FD on error.
int StrBufReadBLOBBuffered (StrBuf *Blob, StrBuf *IOBuf, const char **Pos, int *fd, int append, long nBytes, int check, const char **Error)
 Input binary data from socket flushes and closes the FD on error.

Detailed Description

File IO to fill StrBufs; Works with work-buffer shared across several calls; External Cursor to maintain the current read position inside of the buffer the non-fast ones will use memove to keep the start of the buffer the read buffer (which is slower)


Function Documentation

int StrBufReadBLOBBuffered ( StrBuf Blob,
StrBuf IOBuf,
const char **  Pos,
int *  fd,
int  append,
long  nBytes,
int  check,
const char **  Error 
)

Input binary data from socket flushes and closes the FD on error.

Parameters:
Blobput binary thing here
IOBufthe buffer to get the input to
Posoffset inside of IOBuf
fdpointer to the filedescriptor to read
appendAppend to an existing string or replace?
nBytesthe maximal number of bytes to read
checkwhether we should search for '000
' terminators in case of timeouts
Errorstrerror() on error
Returns:
numbers of chars read

Definition at line 4611 of file stringbuf.c.

{
       const char *pos;
       int fdflags;
       int rlen = 0;
       int nRead = 0;
       int nAlreadyRead = 0;
       int IsNonBlock;
       char *ptr;
       fd_set rfds;
       struct timeval tv;
       int nSuccessLess = 0;
       int MaxTries;

       if ((Blob == NULL) || (*fd == -1) || (IOBuf == NULL) || (Pos == NULL))
       {
              if (*Pos != NULL)
                     *Pos = NULL;
              *Error = ErrRBB_BLOBFPreConditionFailed;
              return -1;
       }

       if (!append)
              FlushStrBuf(Blob);
       if (Blob->BufUsed + nBytes >= Blob->BufSize) 
              IncreaseBuf(Blob, append, Blob->BufUsed + nBytes);
       
       pos = *Pos;

       if (pos != NULL)
              rlen = pos - IOBuf->buf;
       rlen = IOBuf->BufUsed - rlen;


       if ((IOBuf->BufUsed > 0) && 
           (pos != NULL) && 
           (pos < IOBuf->buf + IOBuf->BufUsed)) 
       {
              if (rlen < nBytes) {
                     memcpy(Blob->buf + Blob->BufUsed, pos, rlen);
                     Blob->BufUsed += rlen;
                     Blob->buf[Blob->BufUsed] = '\0';
                     nAlreadyRead = nRead = rlen;
                     *Pos = NULL; 
              }
              if (rlen >= nBytes) {
                     memcpy(Blob->buf + Blob->BufUsed, pos, nBytes);
                     Blob->BufUsed += nBytes;
                     Blob->buf[Blob->BufUsed] = '\0';
                     if (rlen == nBytes) {
                            *Pos = NULL; 
                            FlushStrBuf(IOBuf);
                     }
                     else 
                            *Pos += nBytes;
                     return nBytes;
              }
       }

       FlushStrBuf(IOBuf);
       *Pos = NULL;
       if (IOBuf->BufSize < nBytes - nRead)
              IncreaseBuf(IOBuf, 0, nBytes - nRead);
       ptr = IOBuf->buf;

       fdflags = fcntl(*fd, F_GETFL);
       IsNonBlock = (fdflags & O_NONBLOCK) == O_NONBLOCK;
       if (IsNonBlock)
              MaxTries =   1000;
       else
              MaxTries = 100000;

       nBytes -= nRead;
       nRead = 0;
       while ((nSuccessLess < MaxTries) && 
              (nRead < nBytes) &&
              (*fd != -1)) {
              if (IsNonBlock)
              {
                     tv.tv_sec = 1;
                     tv.tv_usec = 0;
              
                     FD_ZERO(&rfds);
                     FD_SET(*fd, &rfds);
                     if (select(*fd + 1, &rfds, NULL, NULL, &tv) == -1) {
                            *Error = strerror(errno);
                            close (*fd);
                            *fd = -1;
                            if (*Error == NULL)
                                   *Error = ErrRBLF_SelectFailed;
                            return -1;
                     }
                     if (! FD_ISSET(*fd, &rfds) != 0) {
                            nSuccessLess ++;
                            continue;
                     }
              }
              rlen = read(*fd, 
                         ptr,
                         IOBuf->BufSize - (ptr - IOBuf->buf));
              if (rlen == -1) {
                     close(*fd);
                     *fd = -1;
                     *Error = strerror(errno);
                     return rlen;
              }
              else if (rlen == 0){
                     if ((check == NNN_TERM) && 
                         (nRead > 5) &&
                         (strncmp(IOBuf->buf + IOBuf->BufUsed - 5, "\n000\n", 5) == 0)) 
                     {
                            StrBufPlain(Blob, HKEY("\n000\n"));
                            StrBufCutRight(Blob, 5);
                            return Blob->BufUsed;
                     }
                     else if (!IsNonBlock) 
                            nSuccessLess ++;
                     else if (nSuccessLess > MaxTries) {
                            FlushStrBuf(IOBuf);
                            *Error = ErrRBB_too_many_selects;
                            return -1;
                     }
              }
              else if (rlen > 0) {
                     nSuccessLess = 0;
                     nRead += rlen;
                     ptr += rlen;
                     IOBuf->BufUsed += rlen;
              }
       }
       if (nSuccessLess >= MaxTries) {
              FlushStrBuf(IOBuf);
              *Error = ErrRBB_too_many_selects;
              return -1;
       }

       if (nRead > nBytes) {
              *Pos = IOBuf->buf + nBytes;
       }
       Blob->buf[Blob->BufUsed] = '\0';
       StrBufAppendBufPlain(Blob, IOBuf->buf, nBytes, 0);
       if (*Pos == NULL) {
              FlushStrBuf(IOBuf);
       }
       return nRead + nAlreadyRead;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int StrBufTCP_read_buffered_line ( StrBuf Line,
StrBuf buf,
int *  fd,
int  timeout,
int  selectresolution,
const char **  Error 
)

Read a line from socket flushes and closes the FD on error.

Parameters:
Linethe line to read from the fd / I/O Buffer
bufthe buffer to get the input to
fdpointer to the filedescriptor to read
timeoutnumber of successless selects until we bail out
selectresolutionhow long to wait on each select
Errorstrerror() on error
Returns:
numbers of chars read

Definition at line 4238 of file stringbuf.c.

{
       int len, rlen;
       int nSuccessLess = 0;
       fd_set rfds;
       char *pch = NULL;
        int fdflags;
       int IsNonBlock;
       struct timeval tv;

       if (buf->BufUsed > 0) {
              pch = strchr(buf->buf, '\n');
              if (pch != NULL) {
                     rlen = 0;
                     len = pch - buf->buf;
                     if (len > 0 && (*(pch - 1) == '\r') )
                            rlen ++;
                     StrBufSub(Line, buf, 0, len - rlen);
                     StrBufCutLeft(buf, len + 1);
                     return len - rlen;
              }
       }
       
       if (buf->BufSize - buf->BufUsed < 10)
              IncreaseBuf(buf, 1, -1);

       fdflags = fcntl(*fd, F_GETFL);
       IsNonBlock = (fdflags & O_NONBLOCK) == O_NONBLOCK;

       while ((nSuccessLess < timeout) && (pch == NULL)) {
              if (IsNonBlock){
                     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 (IsNonBlock && !  FD_ISSET(*fd, &rfds)) {
                     nSuccessLess ++;
                     continue;
              }
              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;
              }
              
       }
       if (pch != NULL) {
              rlen = 0;
              len = pch - buf->buf;
              if (len > 0 && (*(pch - 1) == '\r') )
                     rlen ++;
              StrBufSub(Line, buf, 0, len - rlen);
              StrBufCutLeft(buf, len + 1);
              return len - rlen;
       }
       return -1;

}

Here is the call graph for this function:

int StrBufTCP_read_buffered_line_fast ( StrBuf Line,
StrBuf IOBuf,
const char **  Pos,
int *  fd,
int  timeout,
int  selectresolution,
const char **  Error 
)

Read a line from socket flushes and closes the FD on error.

Parameters:
Linewhere to append our Line read from the fd / I/O Buffer;
IOBufthe buffer to get the input to; lifetime pair to FD
Pospointer to the current read position, should be NULL initialized on opening the FD it belongs to.!
fdpointer to the filedescriptor to read
timeoutnumber of successless selects until we bail out
selectresolutionhow long to wait on each select
Errorstrerror() on error
Returns:
numbers of chars read or -1 in case of error. "\n" will become 0

Definition at line 4340 of file stringbuf.c.

{
       const char *pche = NULL;
       const char *pos = NULL;
       const char *pLF;
       int len, rlen, retlen;
       int nSuccessLess = 0;
       fd_set rfds;
       const char *pch = NULL;
        int fdflags;
       int IsNonBlock;
       struct timeval tv;
       
       retlen = 0;
       if ((Line == NULL) ||
           (Pos == NULL) ||
           (IOBuf == NULL) ||
           (*fd == -1))
       {
              if (Pos != NULL)
                     *Pos = NULL;
              *Error = ErrRBLF_PreConditionFailed;
              return -1;
       }

       pos = *Pos;
       if ((IOBuf->BufUsed > 0) && 
           (pos != NULL) && 
           (pos < IOBuf->buf + IOBuf->BufUsed)) 
       {
              char *pcht;

              pche = IOBuf->buf + IOBuf->BufUsed;
              pch = pos;
              pcht = Line->buf;

              while ((pch < pche) && (*pch != '\n'))
              {
                     if (Line->BufUsed + 10 > Line->BufSize)
                     {
                            long apos;
                            apos = pcht - Line->buf;
                            *pcht = '\0';
                            IncreaseBuf(Line, 1, -1);
                            pcht = Line->buf + apos;
                     }
                     *pcht++ = *pch++;
                     Line->BufUsed++;
                     retlen++;
              }

              len = pch - pos;
              if (len > 0 && (*(pch - 1) == '\r') )
              {
                     retlen--;
                     len --;
                     pcht --;
                     Line->BufUsed --;
              }
              *pcht = '\0';

              if ((pch >= pche) || (*pch == '\0'))
              {
                     FlushStrBuf(IOBuf);
                     *Pos = NULL;
                     pch = NULL;
                     pos = 0;
              }

              if ((pch != NULL) && 
                  (pch <= pche)) 
              {
                     if (pch + 1 >= pche) {
                            *Pos = NULL;
                            FlushStrBuf(IOBuf);
                     }
                     else
                            *Pos = pch + 1;
                     
                     return retlen;
              }
              else 
                     FlushStrBuf(IOBuf);
       }

       /* If we come here, Pos is Unset since we read everything into Line, and now go for more. */
       
       if (IOBuf->BufSize - IOBuf->BufUsed < 10)
              IncreaseBuf(IOBuf, 1, -1);

       fdflags = fcntl(*fd, F_GETFL);
       IsNonBlock = (fdflags & O_NONBLOCK) == O_NONBLOCK;

       pLF = NULL;
       while ((nSuccessLess < timeout) && 
              (pLF == NULL) &&
              (*fd != -1)) {
              if (IsNonBlock)
              {
                     tv.tv_sec = 1;
                     tv.tv_usec = 0;
              
                     FD_ZERO(&rfds);
                     FD_SET(*fd, &rfds);
                     if (select((*fd) + 1, &rfds, NULL, NULL, &tv) == -1) {
                            *Error = strerror(errno);
                            close (*fd);
                            *fd = -1;
                            if (*Error == NULL)
                                   *Error = ErrRBLF_SelectFailed;
                            return -1;
                     }
                     if (! FD_ISSET(*fd, &rfds) != 0) {
                            nSuccessLess ++;
                            continue;
                     }
              }
              rlen = read(*fd, 
                         &IOBuf->buf[IOBuf->BufUsed], 
                         IOBuf->BufSize - IOBuf->BufUsed - 1);
              if (rlen < 1) {
                     *Error = strerror(errno);
                     close(*fd);
                     *fd = -1;
                     return -1;
              }
              else if (rlen > 0) {
                     nSuccessLess = 0;
                     pLF = IOBuf->buf + IOBuf->BufUsed;
                     IOBuf->BufUsed += rlen;
                     IOBuf->buf[IOBuf->BufUsed] = '\0';
                     
                     pche = IOBuf->buf + IOBuf->BufUsed;
                     
                     while ((pLF < pche) && (*pLF != '\n'))
                            pLF ++;
                     if ((pLF >= pche) || (*pLF == '\0'))
                            pLF = NULL;

                     if (IOBuf->BufUsed + 10 > IOBuf->BufSize)
                     {
                            long apos = 0;

                            if (pLF != NULL) apos = pLF - IOBuf->buf;
                            IncreaseBuf(IOBuf, 1, -1);  
                            if (pLF != NULL) pLF = IOBuf->buf + apos;
                     }

                     continue;
              }
       }
       *Pos = NULL;
       if (pLF != NULL) {
              pos = IOBuf->buf;
              len = pLF - pos;
              if (len > 0 && (*(pLF - 1) == '\r') )
                     len --;
              StrBufAppendBufPlain(Line, ChrPtr(IOBuf), len, 0);
              if (pLF + 1 >= IOBuf->buf + IOBuf->BufUsed)
              {
                     FlushStrBuf(IOBuf);
              }
              else 
                     *Pos = pLF + 1;
              return retlen + len;
       }
       *Error = ErrRBLF_NotEnoughSentFromServer;
       return -1;

}

Here is the call graph for this function:

Here is the caller graph for this function: