diff --git a/src/libckpool.c b/src/libckpool.c index 730bf575..d305ad3e 100644 --- a/src/libckpool.c +++ b/src/libckpool.c @@ -390,7 +390,7 @@ out: int write_socket(int fd, const void *buf, size_t nbyte) { - struct timeval tv_timeout = {1, 0}; + tv_t tv_timeout = {1, 0}; fd_set writefds; int ret; @@ -414,6 +414,67 @@ out: return ret; } +/* Peek in a socket, and then receive only one line at a time, allocing enough + * memory in *buf */ +int read_socket_line(int fd, void **buf) +{ + char readbuf[PAGESIZE], *eom = NULL; + size_t buflen = 0, bufofs = 0; + tv_t timeout = {1, 0}; + int ret, bufsiz; + fd_set rd; + + *buf = NULL; +retry: + FD_ZERO(&rd); + FD_SET(fd, &rd); + ret = select(fd + 1, &rd, NULL, NULL, &timeout); + if (ret < 0 && interrupted()) + goto retry; + if (ret < 1) { + if (!ret) + LOGNOTICE("Select timed out in read_socket_line"); + else + LOGNOTICE("Select failed in read_socket_line with errno %d", errno); + goto out; + } + bufsiz = PAGESIZE; + readbuf[bufsiz - 1] = '\0'; + while (!eom) { + int extralen; + + ret = recv(fd, readbuf, bufsiz - 2, MSG_PEEK); + if (ret < 1) { + LOGNOTICE("Failed to recv in read_socket_line"); + goto out; + } + eom = strchr(readbuf, '\n'); + if (eom) + extralen = eom - readbuf + 1; + else + extralen = ret; + buflen += extralen + 1; + align_len(&buflen); + *buf = realloc(*buf, buflen); + if (unlikely(!*buf)) + quit(1, "Failed to alloc buf of %d bytes in read_socket_line", (int)buflen); + ret = recv(fd, *buf + bufofs, extralen, 0); + if (ret != extralen) { + LOGNOTICE("Failed to recv %d bytes in read_socket_line", (int)buflen); + ret = -1; + goto out; + } + bufofs += ret; + } + eom = *buf + bufofs; + eom[0] = '\0'; + ret = bufofs + 1; +out: + if (ret < 1) + dealloc(buf); + return ret; +} + /* Align a size_t to 4 byte boundaries for fussy arches */ void align_len(size_t *len) { diff --git a/src/libckpool.h b/src/libckpool.h index 4cf54dde..33c6b723 100644 --- a/src/libckpool.h +++ b/src/libckpool.h @@ -77,6 +77,8 @@ exit(status); \ } while (0) +#define PAGESIZE (4096) + /* cgminer locks, a write biased variant of rwlocks */ struct cklock { pthread_mutex_t mutex; @@ -139,6 +141,7 @@ void noblock_socket(int fd); void block_socket(int fd); int connect_socket(char *url, char *port); int write_socket(int fd, const void *buf, size_t nbyte); +int read_socket_line(int fd, void **buf); void align_len(size_t *len); void realloc_strcat(char **ptr, const char *s);