iobuffer.c revision 37d34c871f4be045e27bcb3b53d52eec10b6ccb1
/*
iobuffer.c : Input/output transmit buffer handling
Copyright (c) 2002 Timo Sirainen
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "lib.h"
#include "ioloop.h"
#include "iobuffer.h"
#include "mmap-util.h"
#include "sendfile-util.h"
#include "network.h"
#include <unistd.h>
typedef struct {
const char *data;
int timeout;
int last_block;
static size_t mmap_pagesize = 0;
static size_t mmap_pagemask = 0;
{
return buf;
}
{
return buf;
}
{
/* block size must be page aligned, and at least two pages long */
if (mmap_pagesize == 0) {
mmap_pagesize = getpagesize();
}
else if ((block_size & mmap_pagemask) != 0) {
block_size &= ~mmap_pagemask;
}
/* set offsets */
if (start_offset < 0 || stop_offset < 0) {
i_error("io_buffer_create_mmap(): lseek() failed: %m");
}
if (start_offset > stop_offset)
}
return buf;
}
{
return;
else {
i_error("io_buffer_destroy(): "
"munmap() failed: %m");
}
}
}
}
{
return;
}
{
i_error("io_buffer_reset(): munmap() failed: %m");
buf->buffer_size = 0;
}
}
{
}
return newbuf;
}
{
}
void *context)
{
if (max_size != 0)
}
{
if (size == 0)
return 0;
ret = 0;
return ret;
}
{
int ret;
} else {
}
if (ret < 0) {
} else {
/* everything sent */
/* call flush function */
/* remove cork */
}
}
}
}
}
{
return FALSE;
}
return TRUE;
}
{
} else {
/* send the data */
if (ret < 0) {
} else {
}
}
}
/* this can be called with both io_buffer_ioloop() or
io_buffer_read_blocking() */
{
}
{
int save_errno;
/* close old IO */
/* create a new I/O loop */
save_errno = errno;
/* remove cork */
}
}
/* call user-given timeout function */
}
}
errno = save_errno;
}
{
}
{
}
{
buf->buffer_size =
/* pool limit exceeded */
}
}
{
buf->cr_lookup_pos = 0;
else
}
{
return -1;
/* if we're corked, first try adding it to buffer. if it's larger
than the buffer, send it immediately. */
for (i = 0; i < 2; i++) {
/* buffer is empty, try to send the data immediately */
if (ret < 0) {
/* disconnected */
return -1;
}
}
if (size == 0) {
/* all sent */
return 1;
}
break;
if (corked)
else {
/* if we don't have space, we block */
}
return -2;
}
}
/* add to buffer */
}
return 1;
}
{
if (ret < 0) {
ret = 0;
}
}
{
/* first try if we can do it with a single sendfile() call */
if (ret < 0) {
return -1;
ret = 0;
}
/* yes, all sent */
return 1;
}
/* this shouldn't happen, must be a bug. It would also
mess up later if we let this pass. */
i_fatal("io_buffer_sendfile() failed: %m");
}
return ret;
}
{
unsigned char *in_data;
return;
}
/* send the data */
/* ctx->size now contains number of bytes unsent */
}
{
int ret;
/* sendfile() not supported (with this fd), fallback to
regular sending */
/* create blocking send loop */
}
{
return;
}
void *context)
{
return;
}
}
{
}
{
/* end of file */
return -1;
}
/* more bytes available without needing to mmap() */
return io_buffer_set_mmaped_pos(buf);
}
/* didn't skip enough bytes */
return -2;
}
i_error("io_buffer_read_mmaped(): munmap() failed: %m");
}
i_error("io_buffer_read_mmaped(): mmap() failed: %m");
return -1;
}
return io_buffer_set_mmaped_pos(buf);
}
{
if (offset == 0)
else {
}
}
{
return -1;
return io_buffer_read_mmaped(buf);
/* remove the unused bytes from beginning of buffer */
} else if (buf->max_buffer_size == 0 ||
/* buffer is full - grow it */
}
return -2; /* buffer full */
}
if (size == 0)
return -1;
}
}
/* fill the buffer */
} else {
if (ret == 0)
ret = 0;
}
if (ret < 0) {
/* disconnected */
return -1;
}
return ret;
}
{
/* got data / error */
}
}
{
/* first check if we can get some data */
if (ret != 0)
return ret;
/* blocking now */
/* create a new I/O loop */
}
/* call user-given timeout function */
}
}
}
{
return;
}
/* these point outside mmap now, next io_buffer_read_mmaped()
will fix them */
} else {
if (buf->buffer_size == 0)
}
}
{
if (real_offset > OFF_T_MAX) {
return FALSE;
}
/* first reset everything */
/* then set the wanted position, next read will
pick up from there */
} else {
return FALSE;
}
return TRUE;
}
/* skip the first LF, if it exists */
{
return;
buf->cr_lookup_pos++;
}
}
{
/* FIXME: buf->offset isn't updated right.. (skip_lf thing?) */
unsigned char *ret_buf;
size_t i;
return NULL;
/* got it */
i++;
break;
}
}
buf->cr_lookup_pos = i;
return ret_buf;
}
{
*size = 0;
return NULL;
}
}
{
/* we need more data */
if (ret < 0) {
if (ret == -2)
return -2;
else
break;
}
}
}
{
/* make sure we have enough space in buffer */
/* remove the unused bytes from beginning of buffer */
}
(buf->max_buffer_size == 0 ||
/* allocate more space */
}
return NULL;
}
{
/* buffer is empty, try to send the data immediately */
if (ret < 0) {
/* disconnected */
return -1;
}
/* all sent */
return 1;
}
}
}
return 1;
}
{
return -2;
}
return 1;
}
{
}