Browse Source

Use realloc'd data_buffer to support stratum lines longer than 8 KB, and parse stratum responses during auth

Luke Dashjr 13 years ago
parent
commit
a2c0f3665f
3 changed files with 55 additions and 46 deletions
  1. 1 1
      cgminer.c
  2. 7 1
      miner.h
  3. 47 44
      util.c

+ 1 - 1
cgminer.c

@@ -4247,7 +4247,7 @@ static void stratum_share_result(json_t *val, json_t *res_val, json_t *err_val,
 
 /* Parses stratum json responses and tries to find the id that the request
  * matched to and treat it accordingly. */
-static bool parse_stratum_response(struct pool *pool, char *s)
+bool parse_stratum_response(struct pool *pool, char *s)
 {
 	json_t *val = NULL, *err_val, *res_val, *id_val;
 	struct stratum_share *sshare;

+ 7 - 1
miner.h

@@ -806,6 +806,12 @@ struct stratum_work {
 #define RECVSIZE 8192
 #define RBUFSIZE (RECVSIZE + 4)
 
+struct data_buffer {
+	void		*buf;
+	size_t		len;
+	curl_socket_t	*idlemarker;
+};
+
 struct pool {
 	int pool_no;
 	int prio;
@@ -874,7 +880,7 @@ struct pool {
 	char *stratum_port;
 	CURL *stratum_curl;
 	SOCKETTYPE sock;
-	char sockbuf[RBUFSIZE];
+	struct data_buffer readbuf;
 	char *sockaddr_url; /* stripped url used for sockaddr */
 	char *nonce1;
 	uint32_t nonce2;

+ 47 - 44
util.c

@@ -41,11 +41,6 @@
 bool successful_connect = false;
 struct timeval nettime;
 
-struct data_buffer {
-	void		*buf;
-	size_t		len;
-};
-
 struct upload_buffer {
 	const void	*buf;
 	size_t		len;
@@ -281,7 +276,7 @@ json_t *json_rpc_call(CURL *curl, const char *url,
 		      struct pool *pool, bool share)
 {
 	long timeout = longpoll ? (60 * 60) : 60;
-	struct data_buffer all_data = {NULL, 0};
+	struct data_buffer all_data = {.len = 0};
 	struct header_info hi = {NULL, 0, NULL, NULL, false, false, false};
 	char len_hdr[64], user_agent_hdr[128];
 	char curl_err_str[CURL_ERROR_SIZE];
@@ -924,13 +919,14 @@ bool stratum_send(struct pool *pool, char *s, ssize_t len)
 static void clear_sock(struct pool *pool)
 {
 	size_t n = 0;
+	char buf[RECVSIZE];
 
 	mutex_lock(&pool->stratum_lock);
 	/* Ignore return code of curl_easy_recv since we're just clearing
 	 * anything in the socket if it's still alive */
-	curl_easy_recv(pool->stratum_curl, pool->sockbuf, RECVSIZE, &n);
+	while (CURLE_AGAIN != curl_easy_recv(pool->stratum_curl, buf, RECVSIZE, &n))
+	{}
 	mutex_unlock(&pool->stratum_lock);
-	strcpy(pool->sockbuf, "");
 }
 
 /* Check to see if Santa's been good to you */
@@ -940,7 +936,7 @@ static bool sock_full(struct pool *pool, bool wait)
 	struct timeval timeout;
 	fd_set rd;
 
-	if (strlen(pool->sockbuf))
+	if (pool->readbuf.buf && strchr(pool->readbuf.buf, '\n'))
 		return true;
 
 	FD_ZERO(&rd);
@@ -959,13 +955,12 @@ static bool sock_full(struct pool *pool, bool wait)
  * from the socket and returns that as a malloced char */
 char *recv_line(struct pool *pool)
 {
-	ssize_t len, buflen;
+	ssize_t len;
 	char *tok, *sret = NULL;
 	size_t n = 0;
 
-	if (!strstr(pool->sockbuf, "\n")) {
+	while (!(pool->readbuf.buf && strchr(pool->readbuf.buf, '\n'))) {
 		char s[RBUFSIZE];
-		size_t sspace;
 		CURLcode rc;
 
 		if (!sock_full(pool, true)) {
@@ -979,31 +974,29 @@ char *recv_line(struct pool *pool)
 		mutex_unlock(&pool->stratum_lock);
 
 		if (rc != CURLE_OK) {
-			applog(LOG_DEBUG, "Failed to recv sock in recv_line");
+			applog(LOG_DEBUG, "Failed to recv sock in recv_line: %d", rc);
 			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);
-	tok = strtok(pool->sockbuf, "\n");
-	if (!tok) {
-		applog(LOG_DEBUG, "Failed to parse a \\n terminated string in recv_line");
-		goto out;
+		len = all_data_cb(s, n, 1, &pool->readbuf);
+		pool->readbuf.buf = realloc(pool->readbuf.buf, pool->readbuf.len + 1);
+		((char*)pool->readbuf.buf)[pool->readbuf.len] = '\0';
+
+		if (n != (size_t)len) {
+			applog(LOG_DEBUG, "Error appending readbuf in recv_line");
+			goto out;
+		}
 	}
-	sret = strdup(tok);
-	len = strlen(sret);
 
-	/* Copy what's left in the buffer after the \n, including the
-	 * terminating \0 */
-	if (buflen > len + 1)
-		memmove(pool->sockbuf, pool->sockbuf + len + 1, buflen - len + 1);
-	else
-		strcpy(pool->sockbuf, "");
+	// Assuming the bulk of the data will be in the line, steal the buffer and return it
+	tok = strchr(pool->readbuf.buf, '\n');
+	*tok = '\0';
+	len = tok - (char*)pool->readbuf.buf;
+	pool->readbuf.len -= len + 1;
+	tok = memcpy(malloc(pool->readbuf.len), tok + 1, pool->readbuf.len);
+	sret = realloc(pool->readbuf.buf, len + 1);
+	pool->readbuf.buf = tok;
+
 out:
 	if (!sret)
 		clear_sock(pool);
@@ -1269,6 +1262,8 @@ out:
 	return ret;
 }
 
+extern bool parse_stratum_response(struct pool *, char *s);
+
 bool auth_stratum(struct pool *pool)
 {
 	json_t *val = NULL, *res_val, *err_val;
@@ -1276,13 +1271,28 @@ bool auth_stratum(struct pool *pool)
 	json_error_t err;
 	bool ret = false;
 
-	sprintf(s, "{\"id\": %d, \"method\": \"mining.authorize\", \"params\": [\"%s\", \"%s\"]}",
-		swork_id++, pool->rpc_user, pool->rpc_pass);
+	sprintf(s, "{\"id\": \"auth\", \"method\": \"mining.authorize\", \"params\": [\"%s\", \"%s\"]}",
+	        pool->rpc_user, pool->rpc_pass);
+
+	if (!stratum_send(pool, s, strlen(s)))
+		goto out;
 
-	/* Parse all data prior sending auth request */
-	while (sock_full(pool, false)) {
+	while (1) {
+		if (!sock_full(pool, true)) {
+			applog(LOG_ERR, "Stratum authentication timed out for pool %d", pool->pool_no);
+			goto out;
+		}
 		sret = recv_line(pool);
-		if (!parse_method(pool, sret)) {
+		if (!parse_method(pool, sret) && !parse_stratum_response(pool, sret)) {
+			// Check for auth response
+			val = JSON_LOADS(sret, &err);
+			if (val) {
+				json_t *id_val = json_object_get(val, "id");
+				if (json_is_string(id_val) && !strcmp(json_string_value(id_val), "auth"))
+					break;
+				json_decref(val);
+			}
+
 			clear_sock(pool);
 			applog(LOG_INFO, "Failed to parse stratum buffer");
 			free(sret);
@@ -1291,13 +1301,6 @@ bool auth_stratum(struct pool *pool)
 		free(sret);
 	}
 
-	if (!stratum_send(pool, s, strlen(s)))
-		goto out;
-
-	sret = recv_line(pool);
-	if (!sret)
-		goto out;
-	val = JSON_LOADS(sret, &err);
 	free(sret);
 	res_val = json_object_get(val, "result");
 	err_val = json_object_get(val, "error");