/* Fill buffers from socket based on poll results. */ int buffer_poll(struct pollfd *pfd, struct buffer *in, struct buffer *out) { ssize_t n; if (pfd->revents & (POLLERR|POLLNVAL|POLLHUP)) return (-1); if (pfd->revents & POLLIN) { buffer_ensure(in, BUFSIZ); n = read(pfd->fd, BUFFER_IN(in), BUFFER_FREE(in)); if (n == 0) return (-1); if (n == -1) { if (errno != EINTR && errno != EAGAIN) return (-1); } else buffer_add(in, n); } if (BUFFER_USED(out) > 0 && pfd->revents & POLLOUT) { n = write(pfd->fd, BUFFER_OUT(out), BUFFER_USED(out)); if (n == -1) { if (errno != EINTR && errno != EAGAIN) return (-1); } else buffer_remove(out, n); } return (0); }
/* Write a line to the io write buffer from a va_list. */ void io_vwriteline(struct io *io, const char *fmt, va_list ap) { int n; va_list aq; if (io->error != NULL) return; IO_DEBUG(io, "in: wr: used=%zu, free=%zu", BUFFER_USED(io->wr), BUFFER_FREE(io->wr)); if (fmt != NULL) { va_copy(aq, ap); n = xvsnprintf(NULL, 0, fmt, aq); va_end(aq); buffer_ensure(io->wr, n + 1); xvsnprintf(BUFFER_IN(io->wr), n + 1, fmt, ap); buffer_add(io->wr, n); } else n = 0; io_write(io, io->eol, strlen(io->eol)); IO_DEBUG(io, "out: %zu bytes, wr: used=%zu, free=%zu", n + strlen(io->eol), BUFFER_USED(io->wr), BUFFER_FREE(io->wr)); }
static char *get_line(void) { if (feof(g_file)) return NULL; g_line.size = 0; int c; while ((c = fgetc(g_file)) != EOF && c != '\n') { if (g_line.size == g_line.alloc) buffer_ensure(&g_line, g_line.size + 1024); g_line.data[g_line.size++] = c; } if (g_line.alloc) g_line.data[g_line.size] = '\0'; if (ferror(g_file)) die("IO error while reading %s: %s", g_config.dataset_path, strerror(errno)); // Skip the last line if empty. if (!g_line.size) { c = fgetc(g_file); if (c == EOF) return NULL; ungetc(c, g_file); } g_line_no++; return g_line.data; }
/* Store an 8-bit value. */ void buffer_write8(struct buffer *b, uint8_t n) { buffer_ensure(b, 1); BUFFER_IN(b)[0] = n; buffer_add(b, 1); }
/* Store a 16-bit value. */ void buffer_write16(struct buffer *b, uint16_t n) { buffer_ensure(b, 2); BUFFER_IN(b)[0] = n & 0xff; BUFFER_IN(b)[1] = n >> 8; buffer_add(b, 2); }
/* Copy data into a buffer. */ void buffer_write(struct buffer *b, const void *data, size_t size) { if (size == 0) fatalx("zero size"); buffer_ensure(b, size); memcpy(BUFFER_IN(b), data, size); buffer_add(b, size); }
/* Insert a section into the buffer. */ void buffer_insert_range(struct buffer *b, size_t base, size_t size) { if (size == 0) fatalx("zero size"); if (base > b->size) fatalx("range outside buffer"); buffer_ensure(b, size); memmove(b->base + b->off + base + size, b->base + b->off + base, b->size - base); b->size += size; }
static const where * get_where( int line, const char *file ) { static int init_done = 0; static hash *cache = NULL; static buffer work; where *w; int err; size_t sz; if ( !file ) { return NULL; } if ( !init_done ) { if ( err = buffer_init( &work, 256, 64 ), ERR_None != err ) { nomem( ); } if ( err = hash_new( 1000, &cache ), ERR_None != err ) { nomem( ); } init_done = 1; } sz = sizeof( where ) + strlen( file ) + 1; if ( err = buffer_ensure( &work, sz ), ERR_None != err ) { nomem( ); } w = ( where * ) work.buf; w->line = line; strcpy( ( char * ) ( w + 1 ), file ); /* Already got it? */ if ( w = ( where * ) hash_get( cache, w, sz ), NULL != w ) { return w; } if ( w = malloc( sz ), !w ) { nomem( ); } memcpy( w, work.buf, sz ); /* Add it to cache */ if ( err = hash_put( cache, w, sz, w ), ERR_None != err ) { nomem( ); } return w; }
static void build_location(const char* dir_start, size_t dir_len, const char* name, struct buffer *buf) { size_t name_len, file_len; if (name != NULL) { name_len = strlen(name); file_len = dir_len + 1 + name_len; } else { name_len = 0; /* or GCC complains */ file_len = dir_len; } buffer_ensure(buf, file_len + 1); memcpy(buf->ptr, dir_start, dir_len); if (name != NULL) { buf->ptr[dir_len] = '/'; memcpy(buf->ptr + dir_len + 1, name, name_len); } buf->ptr[file_len] = '\0'; }
int buffer_ensure_free(buffer *b, size_t minfree) { return buffer_ensure(b, b->used + minfree); }
/* * Fill read buffer. Returns 0 for closed, -1 for error, 1 for success, * a la read(2). */ int io_fill(struct io *io) { ssize_t n; int error; again: /* Ensure there is at least some minimum space in the buffer. */ buffer_ensure(io->rd, IO_WATERMARK); /* Attempt to read as much as the buffer has available. */ if (io->ssl == NULL) { n = read(io->fd, BUFFER_IN(io->rd), BUFFER_FREE(io->rd)); IO_DEBUG(io, "read returned %zd (errno=%d)", n, errno); if (n == 0 || (n == -1 && errno == EPIPE)) return (0); if (n == -1 && errno != EINTR && errno != EAGAIN) { if (io->error != NULL) xfree(io->error); xasprintf(&io->error, "io: read: %s", strerror(errno)); return (-1); } } else { n = SSL_read(io->ssl, BUFFER_IN(io->rd), BUFFER_FREE(io->rd)); IO_DEBUG(io, "SSL_read returned %zd", n); if (n == 0) return (0); if (n < 0) { switch (error = SSL_get_error(io->ssl, n)) { case SSL_ERROR_WANT_READ: /* * A repeat is certain (poll on the socket will * still return data ready) so this can be * ignored. */ break; case SSL_ERROR_WANT_WRITE: io->flags |= IOF_NEEDFILL; break; case SSL_ERROR_SYSCALL: if (errno == EAGAIN || errno == EINTR) break; /* FALLTHROUGH */ default: if (io->error != NULL) xfree(io->error); io->error = sslerror2(error, "SSL_read"); return (-1); } } } /* Test for > 0 since SSL_read can return any -ve on error. */ if (n > 0) { IO_DEBUG(io, "read %zd bytes", n); /* Copy out the duplicate fd. Errors are just ignored. */ if (io->dup_fd != -1) { write(io->dup_fd, "< ", 2); write(io->dup_fd, BUFFER_IN(io->rd), n); } /* Adjust the buffer size. */ buffer_add(io->rd, n); /* Reset the need flags. */ io->flags &= ~IOF_NEEDFILL; goto again; } return (1); }