Browse Source

Merge commit '9b34d82' into cg_merges_20130513

Conflicts:
	miner.c
Luke Dashjr 12 years ago
parent
commit
b5df3ae7cc
4 changed files with 108 additions and 52 deletions
  1. 63 26
      api.c
  2. 43 21
      miner.c
  3. 1 1
      miner.h
  4. 1 4
      util.c

+ 63 - 26
api.c

@@ -122,7 +122,6 @@ char *WSAErrorMsg(void) {
 	return &(WSAbuf[0]);
 	return &(WSAbuf[0]);
 }
 }
 #endif
 #endif
-static SOCKETTYPE sock = INVSOCK;
 
 
 static const char *UNAVAILABLE = " - API will not be available";
 static const char *UNAVAILABLE = " - API will not be available";
 static const char *INVAPIGROUPS = "Invalid --api-groups parameter";
 static const char *INVAPIGROUPS = "Invalid --api-groups parameter";
@@ -3243,8 +3242,7 @@ static void checkcommand(struct io_data *io_data, __maybe_unused SOCKETTYPE c, c
 static void send_result(struct io_data *io_data, SOCKETTYPE c, bool isjson)
 static void send_result(struct io_data *io_data, SOCKETTYPE c, bool isjson)
 {
 {
 	char buf[SOCKBUFSIZ + sizeof(JSON_CLOSE) + sizeof(JSON_END)];
 	char buf[SOCKBUFSIZ + sizeof(JSON_CLOSE) + sizeof(JSON_END)];
-	int len;
-	int n;
+	int count, res, tosend, len, n;
 
 
 	strcpy(buf, io_data->ptr);
 	strcpy(buf, io_data->ptr);
 
 
@@ -3259,28 +3257,62 @@ static void send_result(struct io_data *io_data, SOCKETTYPE c, bool isjson)
 	}
 	}
 
 
 	len = strlen(buf);
 	len = strlen(buf);
+	tosend = len+1;
 
 
-	applog(LOG_DEBUG, "API: send reply: (%d) '%.10s%s'", len+1, buf, len > 10 ? "..." : BLANK);
+	applog(LOG_DEBUG, "API: send reply: (%d) '%.10s%s'", tosend, buf, len > 10 ? "..." : BLANK);
 
 
-	// ignore failure - it's closed immediately anyway
-	n = send(c, buf, len+1, 0);
+	count = 0;
+	while (count++ < 5 && tosend > 0) {
+		// allow 50ms per attempt
+		struct timeval timeout = {0, 50000};
+		fd_set wd;
+
+		FD_ZERO(&wd);
+		FD_SET(c, &wd);
+		if ((res = select(c + 1, NULL, &wd, NULL, &timeout)) < 1) {
+			applog(LOG_WARNING, "API: send select failed (%d)", res);
+			return;
+		}
 
 
-	if (SOCKETFAIL(n))
-		applog(LOG_WARNING, "API: send failed: %s", SOCKERRMSG);
-	else
-		applog(LOG_DEBUG, "API: sent %d", n);
+		n = send(c, buf, tosend, 0);
+
+		if (SOCKETFAIL(n)) {
+			if (errno == EAGAIN || errno == EWOULDBLOCK)
+				continue;
+
+			applog(LOG_WARNING, "API: send (%d) failed: %s", tosend, SOCKERRMSG);
+
+			return;
+		} else {
+			if (count <= 1) {
+				if (n == tosend)
+					applog(LOG_DEBUG, "API: sent all of %d first go", tosend);
+				else
+					applog(LOG_DEBUG, "API: sent %d of %d first go", n, tosend);
+			} else {
+				if (n == tosend)
+					applog(LOG_DEBUG, "API: sent all of remaining %d (count=%d)", tosend, count);
+				else
+					applog(LOG_DEBUG, "API: sent %d of remaining %d (count=%d)", n, tosend, count);
+			}
+
+			tosend -= n;
+		}
+	}
 }
 }
 
 
 static void tidyup(__maybe_unused void *arg)
 static void tidyup(__maybe_unused void *arg)
 {
 {
 	mutex_lock(&quit_restart_lock);
 	mutex_lock(&quit_restart_lock);
 
 
+	SOCKETTYPE *apisock = (SOCKETTYPE *)arg;
+
 	bye = true;
 	bye = true;
 
 
-	if (sock != INVSOCK) {
-		shutdown(sock, SHUT_RDWR);
-		CLOSESOCKET(sock);
-		sock = INVSOCK;
+	if (*apisock != INVSOCK) {
+		shutdown(*apisock, SHUT_RDWR);
+		CLOSESOCKET(*apisock);
+		*apisock = INVSOCK;
 	}
 	}
 
 
 	if (ipaccess != NULL) {
 	if (ipaccess != NULL) {
@@ -3601,6 +3633,11 @@ void api(int api_thr_id)
 	bool did;
 	bool did;
 	int i;
 	int i;
 
 
+	SOCKETTYPE *apisock;
+
+	apisock = malloc(sizeof(*apisock));
+	*apisock = INVSOCK;
+
 	if (!opt_api_listen) {
 	if (!opt_api_listen) {
 		applog(LOG_DEBUG, "API not running%s", UNAVAILABLE);
 		applog(LOG_DEBUG, "API not running%s", UNAVAILABLE);
 		return;
 		return;
@@ -3610,7 +3647,7 @@ void api(int api_thr_id)
 
 
 	mutex_init(&quit_restart_lock);
 	mutex_init(&quit_restart_lock);
 
 
-	pthread_cleanup_push(tidyup, NULL);
+	pthread_cleanup_push(tidyup, (void *)apisock);
 	my_thr_id = api_thr_id;
 	my_thr_id = api_thr_id;
 
 
 	setup_groups();
 	setup_groups();
@@ -3628,8 +3665,8 @@ void api(int api_thr_id)
 	 * to ensure curl has already called WSAStartup() in windows */
 	 * to ensure curl has already called WSAStartup() in windows */
 	nmsleep(opt_log_interval*1000);
 	nmsleep(opt_log_interval*1000);
 
 
-	sock = socket(AF_INET, SOCK_STREAM, 0);
-	if (sock == INVSOCK) {
+	*apisock = socket(AF_INET, SOCK_STREAM, 0);
+	if (*apisock == INVSOCK) {
 		applog(LOG_ERR, "API1 initialisation failed (%s)%s", SOCKERRMSG, UNAVAILABLE);
 		applog(LOG_ERR, "API1 initialisation failed (%s)%s", SOCKERRMSG, UNAVAILABLE);
 		return;
 		return;
 	}
 	}
@@ -3654,7 +3691,7 @@ void api(int api_thr_id)
 	// another program has it open - which is what we want
 	// another program has it open - which is what we want
 	int optval = 1;
 	int optval = 1;
 	// If it doesn't work, we don't really care - just show a debug message
 	// If it doesn't work, we don't really care - just show a debug message
-	if (SOCKETFAIL(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)(&optval), sizeof(optval))))
+	if (SOCKETFAIL(setsockopt(*apisock, SOL_SOCKET, SO_REUSEADDR, (void *)(&optval), sizeof(optval))))
 		applog(LOG_DEBUG, "API setsockopt SO_REUSEADDR failed (ignored): %s", SOCKERRMSG);
 		applog(LOG_DEBUG, "API setsockopt SO_REUSEADDR failed (ignored): %s", SOCKERRMSG);
 #else
 #else
 	// On windows a 2nd program can bind to a port>1024 already in use unless
 	// On windows a 2nd program can bind to a port>1024 already in use unless
@@ -3666,7 +3703,7 @@ void api(int api_thr_id)
 	bound = 0;
 	bound = 0;
 	bindstart = time(NULL);
 	bindstart = time(NULL);
 	while (bound == 0) {
 	while (bound == 0) {
-		if (SOCKETFAIL(bind(sock, (struct sockaddr *)(&serv), sizeof(serv)))) {
+		if (SOCKETFAIL(bind(*apisock, (struct sockaddr *)(&serv), sizeof(serv)))) {
 			binderror = SOCKERRMSG;
 			binderror = SOCKERRMSG;
 			if ((time(NULL) - bindstart) > 61)
 			if ((time(NULL) - bindstart) > 61)
 				break;
 				break;
@@ -3683,25 +3720,25 @@ void api(int api_thr_id)
 		return;
 		return;
 	}
 	}
 
 
-	if (SOCKETFAIL(listen(sock, QUEUE))) {
+	if (SOCKETFAIL(listen(*apisock, QUEUE))) {
 		applog(LOG_ERR, "API3 initialisation failed (%s)%s", SOCKERRMSG, UNAVAILABLE);
 		applog(LOG_ERR, "API3 initialisation failed (%s)%s", SOCKERRMSG, UNAVAILABLE);
-		CLOSESOCKET(sock);
+		CLOSESOCKET(*apisock);
 		return;
 		return;
 	}
 	}
 
 
 	if (opt_api_allow)
 	if (opt_api_allow)
-		applog(LOG_WARNING, "API running in IP access mode on port %d", port);
+		applog(LOG_WARNING, "API running in IP access mode on port %d (%d)", port, *apisock);
 	else {
 	else {
 		if (opt_api_network)
 		if (opt_api_network)
-			applog(LOG_WARNING, "API running in UNRESTRICTED read access mode on port %d", port);
+			applog(LOG_WARNING, "API running in UNRESTRICTED read access mode on port %d (%d)", port, *apisock);
 		else
 		else
-			applog(LOG_WARNING, "API running in local read access mode on port %d", port);
+			applog(LOG_WARNING, "API running in local read access mode on port %d (%d)", port, *apisock);
 	}
 	}
 
 
 	while (!bye) {
 	while (!bye) {
 		clisiz = sizeof(cli);
 		clisiz = sizeof(cli);
-		if (SOCKETFAIL(c = accept(sock, (struct sockaddr *)(&cli), &clisiz))) {
-			applog(LOG_ERR, "API failed (%s)%s", SOCKERRMSG, UNAVAILABLE);
+		if (SOCKETFAIL(c = accept(*apisock, (struct sockaddr *)(&cli), &clisiz))) {
+			applog(LOG_ERR, "API failed (%s)%s (%d)", SOCKERRMSG, UNAVAILABLE, *apisock);
 			goto die;
 			goto die;
 		}
 		}
 
 

+ 43 - 21
miner.c

@@ -3086,11 +3086,23 @@ static struct pool *select_balanced(struct pool *cp)
 static bool pool_active(struct pool *, bool pinging);
 static bool pool_active(struct pool *, bool pinging);
 static void pool_died(struct pool *);
 static void pool_died(struct pool *);
 
 
+static bool pool_unusable(struct pool *pool)
+{
+	if (pool->idle)
+		return true;
+	if (pool->enabled != POOL_ENABLED)
+		return true;
+	if (pool->has_stratum && !pool->stratum_active)
+		return true;
+	return false;
+}
+
 /* Select any active pool in a rotating fashion when loadbalance is chosen */
 /* Select any active pool in a rotating fashion when loadbalance is chosen */
 static inline struct pool *select_pool(bool lagging)
 static inline struct pool *select_pool(bool lagging)
 {
 {
 	static int rotating_pool = 0;
 	static int rotating_pool = 0;
 	struct pool *pool, *cp;
 	struct pool *pool, *cp;
+	int tested;
 
 
 	cp = current_pool();
 	cp = current_pool();
 
 
@@ -3106,14 +3118,19 @@ retry:
 	else
 	else
 		pool = NULL;
 		pool = NULL;
 
 
-	while (!pool) {
+	/* Try to find the first pool in the rotation that is usable */
+	tested = 0;
+	while (!pool && tested++ < total_pools) {
 		if (++rotating_pool >= total_pools)
 		if (++rotating_pool >= total_pools)
 			rotating_pool = 0;
 			rotating_pool = 0;
 		pool = pools[rotating_pool];
 		pool = pools[rotating_pool];
-		if ((!pool->idle && pool->enabled == POOL_ENABLED) || pool == cp)
+		if (!pool_unusable(pool))
 			break;
 			break;
 		pool = NULL;
 		pool = NULL;
 	}
 	}
+	/* If still nothing is usable, use the current pool */
+	if (!pool)
+		pool = cp;
 
 
 have_pool:
 have_pool:
 	if (cp != pool)
 	if (cp != pool)
@@ -4135,7 +4152,7 @@ static void *submit_work_thread(__maybe_unused void *userdata)
 		{
 		{
 			struct pool *pool = sws->work->pool;
 			struct pool *pool = sws->work->pool;
 			int fd = pool->sock;
 			int fd = pool->sock;
-			if (fd == INVSOCK || (!pool->stratum_auth) || !pool->stratum_notify)
+			if (fd == INVSOCK || (!pool->stratum_init) || !pool->stratum_notify)
 				continue;
 				continue;
 			FD_SET(fd, &wfds);
 			FD_SET(fd, &wfds);
 			set_maxfd(&maxfd, fd);
 			set_maxfd(&maxfd, fd);
@@ -4179,7 +4196,7 @@ next_write_sws_del:
 				continue;
 				continue;
 			}
 			}
 			
 			
-			if (fd == INVSOCK || (!pool->stratum_auth) || (!pool->stratum_notify) || !FD_ISSET(fd, &wfds)) {
+			if (fd == INVSOCK || (!pool->stratum_init) || (!pool->stratum_notify) || !FD_ISSET(fd, &wfds)) {
 next_write_sws:
 next_write_sws:
 				// TODO: Check if stale, possibly discard etc
 				// TODO: Check if stale, possibly discard etc
 				swsp = &sws->next;
 				swsp = &sws->next;
@@ -4418,10 +4435,10 @@ void switch_pools(struct pool *selected)
 		case POOL_LOADBALANCE:
 		case POOL_LOADBALANCE:
 			for (i = 0; i < total_pools; i++) {
 			for (i = 0; i < total_pools; i++) {
 				pool = priority_pool(i);
 				pool = priority_pool(i);
-				if (!pool->idle && pool->enabled == POOL_ENABLED) {
-					pool_no = pool->pool_no;
-					break;
-				}
+				if (pool_unusable(pool) && pool != selected)
+					continue;
+				pool_no = pool->pool_no;
+				break;
 			}
 			}
 			break;
 			break;
 		/* Both of these simply increment and cycle */
 		/* Both of these simply increment and cycle */
@@ -4438,10 +4455,10 @@ void switch_pools(struct pool *selected)
 				if (next_pool >= total_pools)
 				if (next_pool >= total_pools)
 					next_pool = 0;
 					next_pool = 0;
 				pool = pools[next_pool];
 				pool = pools[next_pool];
-				if (!pool->idle && pool->enabled == POOL_ENABLED) {
-					pool_no = next_pool;
-					break;
-				}
+				if (pool_unusable(pool) && pool != selected)
+					continue;
+				pool_no = next_pool;
+				break;
 			}
 			}
 			break;
 			break;
 		default:
 		default:
@@ -6002,7 +6019,7 @@ static void shutdown_stratum(struct pool *pool)
 {
 {
 	// Shut down Stratum as if we never had it
 	// Shut down Stratum as if we never had it
 	pool->stratum_active = false;
 	pool->stratum_active = false;
-	pool->stratum_auth = false;
+	pool->stratum_init = false;
 	pool->has_stratum = false;
 	pool->has_stratum = false;
 	shutdown(pool->sock, SHUT_RDWR);
 	shutdown(pool->sock, SHUT_RDWR);
 	free(pool->stratum_url);
 	free(pool->stratum_url);
@@ -6373,16 +6390,21 @@ retry_stratum:
 		curl_easy_cleanup(curl);
 		curl_easy_cleanup(curl);
 		
 		
 		/* We create the stratum thread for each pool just after
 		/* We create the stratum thread for each pool just after
-		 * successful authorisation. Once the auth flag has been set
+		 * successful authorisation. Once the init flag has been set
 		 * we never unset it and the stratum thread is responsible for
 		 * we never unset it and the stratum thread is responsible for
 		 * setting/unsetting the active flag */
 		 * setting/unsetting the active flag */
-		if (pool->stratum_auth)
-			return pool->stratum_active;
-		if (!(pool->stratum_active ? auth_stratum(pool) : restart_stratum(pool)))
-			return false;
-		init_stratum_thread(pool);
-		detect_algo = 2;
-		return true;
+		bool init = pool_tset(pool, &pool->stratum_init);
+
+		if (!init) {
+			bool ret = initiate_stratum(pool) && auth_stratum(pool);
+
+			if (ret)
+				init_stratum_thread(pool);
+			else
+				pool_tclear(pool, &pool->stratum_init);
+			return ret;
+		}
+		return pool->stratum_active;
 	}
 	}
 	else if (pool->has_stratum)
 	else if (pool->has_stratum)
 		shutdown_stratum(pool);
 		shutdown_stratum(pool);

+ 1 - 1
miner.h

@@ -1074,7 +1074,7 @@ struct pool {
 	char *sessionid;
 	char *sessionid;
 	bool has_stratum;
 	bool has_stratum;
 	bool stratum_active;
 	bool stratum_active;
-	bool stratum_auth;
+	bool stratum_init;
 	bool stratum_notify;
 	bool stratum_notify;
 	struct stratum_work swork;
 	struct stratum_work swork;
 	pthread_t stratum_thread;
 	pthread_t stratum_thread;

+ 1 - 4
util.c

@@ -1535,7 +1535,7 @@ static bool parse_notify(struct pool *pool, json_t *val)
 	total_getworks++;
 	total_getworks++;
 
 
 	if ((merkles && (!pool->swork.transparency_probed || rand() <= RAND_MAX / (opt_skip_checks + 1))) || pool->swork.transparency_time != (time_t)-1)
 	if ((merkles && (!pool->swork.transparency_probed || rand() <= RAND_MAX / (opt_skip_checks + 1))) || pool->swork.transparency_time != (time_t)-1)
-		if (pool->stratum_auth)
+		if (pool->stratum_init)
 			stratum_probe_transparency(pool);
 			stratum_probe_transparency(pool);
 
 
 	ret = true;
 	ret = true;
@@ -1756,7 +1756,6 @@ bool auth_stratum(struct pool *pool)
 	ret = true;
 	ret = true;
 	applog(LOG_INFO, "Stratum authorisation success for pool %d", pool->pool_no);
 	applog(LOG_INFO, "Stratum authorisation success for pool %d", pool->pool_no);
 	pool->probed = true;
 	pool->probed = true;
-	pool->stratum_auth = true;
 	successful_connect = true;
 	successful_connect = true;
 out:
 out:
 	if (val)
 	if (val)
@@ -1786,7 +1785,6 @@ static bool setup_stratum_curl(struct pool *pool)
 	mutex_lock(&pool->stratum_lock);
 	mutex_lock(&pool->stratum_lock);
 	pool->swork.transparency_time = (time_t)-1;
 	pool->swork.transparency_time = (time_t)-1;
 	pool->stratum_active = false;
 	pool->stratum_active = false;
-	pool->stratum_auth = false;
 	pool->stratum_notify = false;
 	pool->stratum_notify = false;
 	pool->swork.transparency_probed = false;
 	pool->swork.transparency_probed = false;
 	if (pool->stratum_curl)
 	if (pool->stratum_curl)
@@ -1890,7 +1888,6 @@ void suspend_stratum(struct pool *pool)
 	applog(LOG_INFO, "Closing socket for stratum pool %d", pool->pool_no);
 	applog(LOG_INFO, "Closing socket for stratum pool %d", pool->pool_no);
 	mutex_lock(&pool->stratum_lock);
 	mutex_lock(&pool->stratum_lock);
 	pool->stratum_active = pool->stratum_notify = false;
 	pool->stratum_active = pool->stratum_notify = false;
-	pool->stratum_auth = false;
 	curl_easy_cleanup(pool->stratum_curl);
 	curl_easy_cleanup(pool->stratum_curl);
 	pool->stratum_curl = NULL;
 	pool->stratum_curl = NULL;
 	pool->sock = INVSOCK;
 	pool->sock = INVSOCK;