123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- // SPDX-License-Identifier: GPL-3.0-or-later
- #include "../libnetdata.h"
- #ifndef NETDATA_BUFFERED_READER_H
- #define NETDATA_BUFFERED_READER_H
- struct buffered_reader {
- ssize_t read_len;
- ssize_t pos;
- char read_buffer[PLUGINSD_LINE_MAX + 1];
- };
- static inline void buffered_reader_init(struct buffered_reader *reader) {
- reader->read_buffer[0] = '\0';
- reader->read_len = 0;
- reader->pos = 0;
- }
- typedef enum {
- BUFFERED_READER_READ_OK = 0,
- BUFFERED_READER_READ_FAILED = -1,
- BUFFERED_READER_READ_BUFFER_FULL = -2,
- BUFFERED_READER_READ_POLLERR = -3,
- BUFFERED_READER_READ_POLLHUP = -4,
- BUFFERED_READER_READ_POLLNVAL = -5,
- BUFFERED_READER_READ_POLL_UNKNOWN = -6,
- BUFFERED_READER_READ_POLL_TIMEOUT = -7,
- BUFFERED_READER_READ_POLL_FAILED = -8,
- } buffered_reader_ret_t;
- static inline buffered_reader_ret_t buffered_reader_read(struct buffered_reader *reader, int fd) {
- #ifdef NETDATA_INTERNAL_CHECKS
- if(reader->read_buffer[reader->read_len] != '\0')
- fatal("read_buffer does not start with zero");
- #endif
- char *read_at = reader->read_buffer + reader->read_len;
- ssize_t remaining = sizeof(reader->read_buffer) - reader->read_len - 1;
- if(unlikely(remaining <= 0))
- return BUFFERED_READER_READ_BUFFER_FULL;
- ssize_t bytes_read = read(fd, read_at, remaining);
- if(unlikely(bytes_read <= 0))
- return BUFFERED_READER_READ_FAILED;
- reader->read_len += bytes_read;
- reader->read_buffer[reader->read_len] = '\0';
- return BUFFERED_READER_READ_OK;
- }
- static inline buffered_reader_ret_t buffered_reader_read_timeout(struct buffered_reader *reader, int fd, int timeout_ms, bool log_error) {
- errno = 0;
- struct pollfd fds[1];
- fds[0].fd = fd;
- fds[0].events = POLLIN;
- int ret = poll(fds, 1, timeout_ms);
- if (ret > 0) {
- /* There is data to read */
- if (fds[0].revents & POLLIN)
- return buffered_reader_read(reader, fd);
- else if(fds[0].revents & POLLERR) {
- if(log_error)
- netdata_log_error("PARSER: read failed: POLLERR.");
- return BUFFERED_READER_READ_POLLERR;
- }
- else if(fds[0].revents & POLLHUP) {
- if(log_error)
- netdata_log_error("PARSER: read failed: POLLHUP.");
- return BUFFERED_READER_READ_POLLHUP;
- }
- else if(fds[0].revents & POLLNVAL) {
- if(log_error)
- netdata_log_error("PARSER: read failed: POLLNVAL.");
- return BUFFERED_READER_READ_POLLNVAL;
- }
- if(log_error)
- netdata_log_error("PARSER: poll() returned positive number, but POLLIN|POLLERR|POLLHUP|POLLNVAL are not set.");
- return BUFFERED_READER_READ_POLL_UNKNOWN;
- }
- else if (ret == 0) {
- if(log_error)
- netdata_log_error("PARSER: timeout while waiting for data.");
- return BUFFERED_READER_READ_POLL_TIMEOUT;
- }
- if(log_error)
- netdata_log_error("PARSER: poll() failed with code %d.", ret);
- return BUFFERED_READER_READ_POLL_FAILED;
- }
- /* Produce a full line if one exists, statefully return where we start next time.
- * When we hit the end of the buffer with a partial line move it to the beginning for the next fill.
- */
- static inline bool buffered_reader_next_line(struct buffered_reader *reader, BUFFER *dst) {
- buffer_need_bytes(dst, reader->read_len - reader->pos + 2);
- size_t start = reader->pos;
- char *ss = &reader->read_buffer[start];
- char *se = &reader->read_buffer[reader->read_len];
- char *ds = &dst->buffer[dst->len];
- char *de = &ds[dst->size - dst->len - 2];
- if(ss >= se) {
- *ds = '\0';
- reader->pos = 0;
- reader->read_len = 0;
- reader->read_buffer[reader->read_len] = '\0';
- return false;
- }
- // copy all bytes to buffer
- while(ss < se && ds < de && *ss != '\n') {
- *ds++ = *ss++;
- dst->len++;
- }
- // if we have a newline, return the buffer
- if(ss < se && ds < de && *ss == '\n') {
- // newline found in the r->read_buffer
- *ds++ = *ss++; // copy the newline too
- dst->len++;
- *ds = '\0';
- reader->pos = ss - reader->read_buffer;
- return true;
- }
- reader->pos = 0;
- reader->read_len = 0;
- reader->read_buffer[reader->read_len] = '\0';
- return false;
- }
- #endif //NETDATA_BUFFERED_READER_H
|