/*
* Copyright (c) 2002-2005 Sendmail, Inc. and its suppliers.
* All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*/
#include "sm/generic.h"
SM_RCSID("@(#)$Id: rcbrcv.c,v 1.21 2005/06/02 19:00:36 ca Exp $")
#include "sm/assert.h"
#include "sm/magic.h"
#include "sm/memops.h"
#include "sm/rpool.h"
#include "sm/limits.h"
#include "sm/io.h"
#include "sm/rcb.h"
#include "sm/str2rcb.h"
#include "sm/str-int.h"
#include "sm/reccom.h"
/*
** SM_RCB_RCV -- Read data from fd into rcb
**
** Parameters:
** fd -- file descriptor to receive data from
** rcb -- sm_rcb_P object to fill
** rs -- minimum record size
** timeout -- timeout
**
** Returns:
** = 0: done receiving.
** > 0: need to receive more data.
** < 0: usual sm_error code
**
** Side Effects: fill in rcb (maybe partially on error)
**
** Last code review: 2005-03-29 05:18:28
** Last code change:
*/
sm_ret_T
sm_rcb_rcv(rcb_fd_T fd, sm_rcb_P rcb, uint rs
#if SM_RCB_ST
, st_utime_t timeout
#endif
)
{
size_t l;
ssize_t r;
uint32_t val, h;
SM_IS_RCB(rcb);
#if SM_RCB_CHECK
SM_REQUIRE(rcb->sm_rcb_state == SM_RCB_RCV);
#endif
/* number of bytes to read: initially rs, otherwise rcb_rw */
#if SM_RCB_ST
again:
#endif
l = (rcb->sm_rcb_rw == -1) ? rs : (uint) rcb->sm_rcb_rw;
/* XXX ?? */
#if SM_RCB_ST
r = st_read_resid(fd, rcb->sm_rcb_base + rcb->sm_rcb_len, &l, timeout);
#else
r = read(fd, rcb->sm_rcb_base + rcb->sm_rcb_len, l);
#endif
if (r == -1)
{
if (errno == EINTR)
{
#if SM_RCB_ST
rcb->sm_rcb_rw -= l;
rcb->sm_rcb_len += l;
#endif
return rcb->sm_rcb_rw;
}
return sm_error_perm(SM_EM_RECCOM, errno == 0 ? EIO : errno);
}
#if SM_RCB_ST
r = ((rcb->sm_rcb_rw == -1) ? rs : (uint) rcb->sm_rcb_rw) - l;
#endif
if (r == 0)
{
if (errno == 0)
{
#if SM_RCB_ST
rcb->sm_rcb_rw -= l;
rcb->sm_rcb_len += l;
#endif
return SM_IO_EOF;
}
/* got no data? since fd was readable, it's an error */
return SM_IO_EOF;
}
h = rcb->sm_rcb_len;
rcb->sm_rcb_len += r;
/* did we already get the initial length? */
if (h < sizeof(int))
{
/* first call: first element contains length */
if (rcb->sm_rcb_len < sizeof(int))
{
/* still not enough */
#if SM_RCB_ST
goto again;
#else
return 1;
#endif
}
/* extract value */
sm_buf2uint32(rcb->sm_rcb_base, &val);
h = val;
if (val > rcb->sm_rcb_size)
{
/* this changes val! sm_rcb_len MUST be correct! */
SM_STR_INCREASE_R(rcb, val);
}
rcb->sm_rcb_rw = h;
if (h < sizeof(int))
return sm_error_perm(SM_EM_RECCOM, EINVAL);
}
/*
** What happens if we got more than we need?
** Shouldn't happen due to the rs parameter.
*/
if (rcb->sm_rcb_rw < r)
return sm_error_perm(SM_EM_RECCOM, EINVAL);
rcb->sm_rcb_rw -= r;
#if SM_RCB_ST
if (rcb->sm_rcb_rw != 0)
goto again;
#endif
return rcb->sm_rcb_rw;
}
syntax highlighted by Code2HTML, v. 0.9.1