/* * 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; }