/* Tries to copy block <blk> at once into the channel's buffer after length * controls. The chn->o and to_forward pointers are updated. If the channel * input is closed, -2 is returned. If the block is too large for this buffer, * -3 is returned. If there is not enough room left in the buffer, -1 is * returned. Otherwise the number of bytes copied is returned (0 being a valid * number). Channel flag READ_PARTIAL is updated if some data can be * transferred. */ int ci_putblk(struct channel *chn, const char *blk, int len) { int max; if (unlikely(channel_input_closed(chn))) return -2; if (len < 0) return -3; max = channel_recv_limit(chn); if (unlikely(len > max - c_data(chn))) { /* we can't write this chunk right now because the buffer is * almost full or because the block is too large. Return the * available space or -2 if impossible. */ if (len > max) return -3; return -1; } if (unlikely(len == 0)) return 0; /* OK so the data fits in the buffer in one or two blocks */ max = b_contig_space(&chn->buf); memcpy(ci_tail(chn), blk, MIN(len, max)); if (len > max) memcpy(c_orig(chn), blk + max, len - max); b_add(&chn->buf, len); channel_add_input(chn, len); return len; }
/* Tries to copy block <blk> at once into the channel's buffer after length * controls. The chn->o and to_forward pointers are updated. If the channel * input is closed, -2 is returned. If the block is too large for this buffer, * -3 is returned. If there is not enough room left in the buffer, -1 is * returned. Otherwise the number of bytes copied is returned (0 being a valid * number). Channel flag READ_PARTIAL is updated if some data can be * transferred. */ int ci_putblk(struct channel *chn, const char *blk, int len) { int max; if (unlikely(channel_input_closed(chn))) return -2; if (len < 0) return -3; max = channel_recv_limit(chn); if (unlikely(len > max - c_data(chn))) { /* we can't write this chunk right now because the buffer is * almost full or because the block is too large. Return the * available space or -2 if impossible. */ if (len > max) return -3; return -1; } if (unlikely(len == 0)) return 0; /* OK so the data fits in the buffer in one or two blocks */ max = b_contig_space(&chn->buf); memcpy(ci_tail(chn), blk, MIN(len, max)); if (len > max) memcpy(c_orig(chn), blk + max, len - max); b_add(&chn->buf, len); chn->total += len; if (chn->to_forward) { unsigned long fwd = len; if (chn->to_forward != CHN_INFINITE_FORWARD) { if (fwd > chn->to_forward) fwd = chn->to_forward; chn->to_forward -= fwd; } c_adv(chn, fwd); } /* notify that some data was read from the SI into the buffer */ chn->flags |= CF_READ_PARTIAL; return len; }
/* Gets one full block of data at once from a channel's input buffer. * This function can return the data slitted in one or two blocks. * Return values : * >0 : number of blocks returned (1 or 2). blk1 is always filled before blk2. * =0 : not enough data available. * <0 : no more bytes readable because input is shut. */ int ci_getblk_nc(const struct channel *chn, char **blk1, size_t *len1, char **blk2, size_t *len2) { if (unlikely(ci_data(chn) == 0)) { if (chn->flags & CF_SHUTR) return -1; return 0; } if (unlikely(ci_head(chn) + ci_data(chn) > c_wrap(chn))) { *blk1 = ci_head(chn); *len1 = c_wrap(chn) - ci_head(chn); *blk2 = c_orig(chn); *len2 = ci_data(chn) - *len1; return 2; } *blk1 = ci_head(chn); *len1 = ci_data(chn); return 1; }