Commit e1387dc85cd63b1bcd588fc35919210c23ff4197

Con Kolivas 2012-12-29T11:29:59

Change the pool stratum socket buffer to be dynamically allocated to accomodate any size coinbase and keep receiving data in recv line for up to 60s if no end of line has been received.

diff --git a/miner.h b/miner.h
index 50ed607..df2888e 100644
--- a/miner.h
+++ b/miner.h
@@ -859,8 +859,8 @@ struct stratum_work {
 	double diff;
 };
 
-#define RECVSIZE 8192
-#define RBUFSIZE (RECVSIZE + 4)
+#define RBUFSIZE 8192
+#define RECVSIZE (RBUFSIZE - 4)
 
 struct pool {
 	int pool_no;
@@ -929,7 +929,8 @@ struct pool {
 	char *stratum_port;
 	CURL *stratum_curl;
 	SOCKETTYPE sock;
-	char sockbuf[RBUFSIZE];
+	char *sockbuf;
+	size_t sockbuf_size;
 	char *sockaddr_url; /* stripped url used for sockaddr */
 	char *nonce1;
 	uint32_t nonce2;
diff --git a/util.c b/util.c
index 9ca31d6..e628af4 100644
--- a/util.c
+++ b/util.c
@@ -968,37 +968,59 @@ static void clear_sock(struct pool *pool)
 	strcpy(pool->sockbuf, "");
 }
 
+/* Make sure the pool sockbuf is large enough to cope with any coinbase size
+ * by reallocing it to a large enough size rounded up to a multiple of RBUFSIZE
+ * and zeroing the new memory */
+static void recalloc_sock(struct pool *pool, size_t len)
+{
+	size_t old, new;
+
+	old = strlen(pool->sockbuf);
+	new = old + len + 1;
+	if (new < pool->sockbuf_size)
+		return;
+	new = new + (RBUFSIZE - (new % RBUFSIZE));
+	applog(LOG_DEBUG, "Recallocing pool sockbuf to %d", new);
+	pool->sockbuf = realloc(pool->sockbuf, new);
+	if (!pool->sockbuf)
+		quit(1, "Failed to realloc pool sockbuf in recalloc_sock");
+	memset(pool->sockbuf + old, 0, new - old);
+	pool->sockbuf_size = new;
+}
+
 /* Peeks at a socket to find the first end of line and then reads just that
  * from the socket and returns that as a malloced char */
 char *recv_line(struct pool *pool)
 {
 	ssize_t len, buflen;
 	char *tok, *sret = NULL;
-	ssize_t n;
 
 	if (!strstr(pool->sockbuf, "\n")) {
-		char s[RBUFSIZE];
-		size_t sspace;
+		struct timeval rstart, now;
 
+		gettimeofday(&rstart, NULL);
 		if (!socket_full(pool, true)) {
 			applog(LOG_DEBUG, "Timed out waiting for data on socket_full");
 			goto out;
 		}
-		memset(s, 0, RBUFSIZE);
 
 		mutex_lock(&pool->stratum_lock);
-		n = recv(pool->sock, s, RECVSIZE, 0);
+		do {
+			char s[RBUFSIZE];
+			size_t slen, n;
+
+			memset(s, 0, RBUFSIZE);
+			n = recv(pool->sock, s, RECVSIZE, 0);
+			if (n < 1 && errno != EAGAIN && errno != EWOULDBLOCK) {
+				applog(LOG_DEBUG, "Failed to recv sock in recv_line");
+				break;
+			}
+			slen = strlen(s);
+			recalloc_sock(pool, slen);
+			strcat(pool->sockbuf, s);
+			gettimeofday(&now, NULL);
+		} while (tdiff(&now, &rstart) < 60 && !strstr(pool->sockbuf, "\n"));
 		mutex_unlock(&pool->stratum_lock);
-
-		if (n < 1 && errno != EAGAIN && errno != EWOULDBLOCK) {
-			applog(LOG_DEBUG, "Failed to recv sock in recv_line");
-			goto out;
-		}
-		/* Prevent buffer overflows, but if 8k is still not enough,
-		 * likely we have had some comms issues and the data is all
-		 * useless anyway */
-		sspace = RECVSIZE - strlen(pool->sockbuf);
-		strncat(pool->sockbuf, s, sspace);
 	}
 
 	buflen = strlen(pool->sockbuf);
@@ -1350,6 +1372,13 @@ bool initiate_stratum(struct pool *pool)
 	mutex_unlock(&pool->stratum_lock);
 	curl = pool->stratum_curl;
 
+	if (!pool->sockbuf) {
+		pool->sockbuf = calloc(RBUFSIZE, 1);
+		if (!pool->sockbuf)
+			quit(1, "Failed to calloc pool sockbuf in initiate_stratum");
+		pool->sockbuf_size = RBUFSIZE;
+	}
+
 	/* Create a http url for use with curl */
 	memset(s, 0, RBUFSIZE);
 	sprintf(s, "http://%s:%s", pool->sockaddr_url, pool->stratum_port);