static ssize_t nc_read_chunk(struct nc_session *session, size_t len, uint32_t inact_timeout, struct timespec *ts_act_timeout, char **chunk) { ssize_t r; assert(session); assert(chunk); if (!len) { return 0; } *chunk = malloc((len + 1) * sizeof **chunk); if (!*chunk) { ERRMEM; return -1; } r = nc_read(session, *chunk, len, inact_timeout, ts_act_timeout); if (r <= 0) { free(*chunk); return -1; } /* terminating null byte */ (*chunk)[r] = 0; return r; }
ssize_t conn_recv(struct conn *conn, void *buf, size_t size) { ssize_t n; ASSERT(buf != NULL); ASSERT(size > 0); ASSERT(conn->recv_ready); for (;;) { n = nc_read(conn->sd, buf, size); log_debug(LOG_VERB, "recv on sd %d %zd of %zu", conn->sd, n, size); if (n > 0) { if (n < (ssize_t) size) { conn->recv_ready = 0; } conn->recv_bytes += (size_t)n; return n; } if (n == 0) { conn->recv_ready = 0; conn->eof = 1; log_debug(LOG_INFO, "recv on sd %d eof rb %zu sb %zu", conn->sd, conn->recv_bytes, conn->send_bytes); return n; } if (errno == EINTR) { log_debug(LOG_VERB, "recv on sd %d not ready - eintr", conn->sd); continue; } else if (errno == EAGAIN || errno == EWOULDBLOCK) { conn->recv_ready = 0; log_debug(LOG_VERB, "recv on sd %d not ready - eagain", conn->sd); return NC_EAGAIN; } else { conn->recv_ready = 0; conn->err = errno; log_error("recv on sd %d failed: %s", conn->sd, strerror(errno)); return NC_ERROR; } } NOT_REACHED(); return NC_ERROR; }
/* * TODO: return size_t , but actually we return NC_ERROR * */ static ssize_t conn_recv_buf(struct conn *conn, void *buf, size_t size) { ssize_t n; ASSERT(buf != NULL); ASSERT(size > 0); ASSERT(conn->recv_ready); for (;;) { n = nc_read(conn->fd, buf, size); log_verb("recv on conn:%p, fd:%d got %zd/%zu", conn, conn->fd, n, size); if (n > 0) { if (n < (ssize_t)size) { conn->recv_ready = 0; } conn->recv_bytes += (size_t)n; conn->recv_queue_bytes += (size_t)n; return n; } if (n == 0) { conn->recv_ready = 0; conn->eof = 1; log_info("recv on conn:%p fd:%d eof rb %zu sb %zu", conn, conn->fd, conn->recv_bytes, conn->send_bytes); return n; } if (errno == EINTR) { log_verb("recv on conn:%p fd:%d not ready - eintr", conn, conn->fd); continue; } else if (errno == EAGAIN || errno == EWOULDBLOCK) { conn->recv_ready = 0; log_verb("recv on conn:%p fd:%d not ready - eagain", conn, conn->fd); return NC_EAGAIN; } else { conn->recv_ready = 0; conn->err = errno; log_error("recv on conn:%p fd:%d failed: %s", conn, conn->fd, strerror(errno)); return NC_ERROR; } } NOT_REACHED(); return NC_ERROR; }
extern int hc_read_pieces(struct hc * hc, void (*callback)(unsigned char *, size_t, void *), void * v) { char * te; int chunked = 0; int done = 0; char * buf; size_t len, len_read; te = hc_lookup_rsp_header(hc, "Transfer-Encoding"); if (te && strcmp(te, "chunked") == 0) { chunked = 1; } while (!done) { if (chunked) { char lenstr[32]; nc_read_line(hc->nc, lenstr, sizeof lenstr); len = strtoul(lenstr, NULL, 16); } else { len = 4096; } if (len) { buf = malloc(len+1); len_read = nc_read(hc->nc, buf, len); if (len_read < len) done = 1; buf[len_read] = '\0'; callback(buf, len_read, v); } else { done = 1; } if (chunked) { char linebuf[80]; /* if done, then any non-blank lines read here are supposed to be treated as HTTP header lines, but since we didn't say we could accept trailers, the server's only allowed to send them if it's happy with us discarding them. (2616 3.7b). The Replay doesn't use trailers anyway */ while (nc_read_line(hc->nc, linebuf, sizeof linebuf) > 0) ; } } return 0; }
int nc_read_line(struct nc * nc, unsigned char * buf, size_t maxlen) { size_t r = 0; nc_dump("Reading line", NULL, maxlen); while (r < maxlen) { if (nc_read(nc, buf + r, 1) <= 0) { return r; } if (buf[r] == '\012') { buf[r] = '\0'; if (r > 0 && buf[r-1] == '\015') { r--; buf[r] = '\0'; } nc_dump("Read line", buf, r); return r; } r++; } nc_dump("Read line", buf, r); return r; }
extern int hc_read_pieces_len(struct hc * hc, void (*callback)(unsigned char *, size_t, void *), void * v, size_t len_to_read) { char * te; int chunked = 0; int done = 0; char * buf; size_t len, len_read, octets_to_go; char * cl; // NOTE: len_to_read is not currently implemented for non-chunked content. // The ReplayTV only sends chunked content so this doesn't matter here. cl = hc_lookup_rsp_header(hc, "Content-Length"); if (cl) { octets_to_go = strtoul(cl, NULL, 10); } else { octets_to_go = 0; } te = hc_lookup_rsp_header(hc, "Transfer-Encoding"); if (te && strcmp(te, "chunked") == 0) { chunked = 1; } while (!done) { if (chunked) { char lenstr[32]; if (!hc->curr_chunk_len) { nc_read_line(hc->nc, lenstr, sizeof lenstr); hc->curr_chunk_len = strtoul(lenstr, NULL, 16); } if (len_to_read > hc->curr_chunk_len) { len = hc->curr_chunk_len; } else { len = len_to_read; } } else { if (cl) { len = octets_to_go; if (len > MAX_CHUNK) len = MAX_CHUNK; } else { len = MAX_CHUNK; } } if (len) { buf = malloc(len+1); len_read = nc_read(hc->nc, buf, len); if (len_read <= len) done = 1; buf[len_read] = '\0'; callback(buf, len_read, v); if (cl) { octets_to_go -= len_read; if (octets_to_go == 0 && !chunked) { done = 1; } } hc->curr_chunk_len -= len_read; } else { done = 1; } if (chunked && !hc->curr_chunk_len) { char linebuf[80]; /* if done, then any non-blank lines read here are supposed to be treated as HTTP header lines, but since we didn't say we could accept trailers, the server's only allowed to send them if it's happy with us discarding them. (2616 3.7b). The Replay doesn't use trailers anyway */ while (nc_read_line(hc->nc, linebuf, sizeof linebuf) > 0) ; } } return 0; }
static ssize_t nc_read_until(struct nc_session *session, const char *endtag, size_t limit, uint32_t inact_timeout, struct timespec *ts_act_timeout, char **result) { char *chunk = NULL; size_t size, count = 0, r, len, i, matched = 0; assert(session); assert(endtag); if (limit && limit < BUFFERSIZE) { size = limit; } else { size = BUFFERSIZE; } chunk = malloc((size + 1) * sizeof *chunk); if (!chunk) { ERRMEM; return -1; } len = strlen(endtag); while (1) { if (limit && count == limit) { free(chunk); WRN("Session %u: reading limit (%d) reached.", session->id, limit); ERR("Session %u: invalid input data (missing \"%s\" sequence).", session->id, endtag); return -1; } /* resize buffer if needed */ if ((count + (len - matched)) >= size) { /* get more memory */ size = size + BUFFERSIZE; chunk = nc_realloc(chunk, (size + 1) * sizeof *chunk); if (!chunk) { ERRMEM; return -1; } } /* get another character */ r = nc_read(session, &(chunk[count]), len - matched, inact_timeout, ts_act_timeout); if (r != len - matched) { free(chunk); return -1; } count += len - matched; for (i = len - matched; i > 0; i--) { if (!strncmp(&endtag[matched], &(chunk[count - i]), i)) { /*part of endtag found */ matched += i; break; } else { matched = 0; } } /* whole endtag found */ if (matched == len) { break; } } /* terminating null byte */ chunk[count] = 0; if (result) { *result = chunk; } else { free(chunk); } return count; }