api.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. /*
  2. * Copyright 2011 Kano
  3. * Copyright 2011 Con Kolivas
  4. *
  5. * This program is free software; you can redistribute it and/or modify it
  6. * under the terms of the GNU General Public License as published by the Free
  7. * Software Foundation; either version 2 of the License, or (at your option)
  8. * any later version. See COPYING for more details.
  9. */
  10. #include "config.h"
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <stdbool.h>
  15. #include <stdint.h>
  16. #include <unistd.h>
  17. #include <sys/time.h>
  18. #include <time.h>
  19. #include <math.h>
  20. #include <stdarg.h>
  21. #include <assert.h>
  22. #include <sys/stat.h>
  23. #include <sys/types.h>
  24. #include "compat.h"
  25. #include "miner.h"
  26. #if defined(unix)
  27. #include <errno.h>
  28. // #include <fcntl.h>
  29. // #include <sys/wait.h>
  30. #endif
  31. #include <sys/socket.h>
  32. #include <netinet/in.h>
  33. #include <arpa/inet.h>
  34. // Big enough for largest API request
  35. // though a PC with 100s of CPUs may exceed the size ...
  36. // Current code assumes it can socket send this size also
  37. #define MYBUFSIZ 16384
  38. // Socket is on 127.0.0.1
  39. #define QUEUE 10
  40. static char *buffer = NULL;
  41. static const char *UNAVAILABLE = " - API will not be available";
  42. static const char *BLANK = "";
  43. static const char *APIVERSION = "0.1";
  44. static const char *DEAD = "DEAD";
  45. static const char *SICK = "SICK";
  46. static const char *DISABLED = "DISABLED";
  47. static const char *ALIVE = "ALIVE";
  48. static const char *YES = "Y";
  49. static const char *NO = "N";
  50. static int bye = 0;
  51. char *apiversion(char *params)
  52. {
  53. return (char *)APIVERSION;
  54. }
  55. void gpustatus(int thr_id)
  56. {
  57. char buf[BUFSIZ];
  58. char status_buf[BUFSIZ];
  59. char *status;
  60. float gt;
  61. int gf, gp;
  62. if (thr_id >= 0 && thr_id < gpu_threads) {
  63. int gpu = thr_info[thr_id].cgpu->cpu_gpu;
  64. struct cgpu_info *cgpu = &gpus[gpu];
  65. cgpu->utility = cgpu->accepted / ( total_secs ? total_secs : 1 ) * 60;
  66. #ifdef HAVE_ADL
  67. if (cgpu->has_adl) {
  68. gt = gpu_temp(gpu);
  69. gf = gpu_fanspeed(gpu);
  70. gp = gpu_fanpercent(gpu);
  71. }
  72. else
  73. #endif
  74. gt = gf = gp = 0;
  75. if (cgpu->status == LIFE_DEAD)
  76. status = (char *)DEAD;
  77. else if (cgpu->status == LIFE_SICK)
  78. status = (char *)SICK;
  79. else if (!gpu_devices[gpu])
  80. status = (char *)DISABLED;
  81. else {
  82. sprintf(status_buf, "%.1f", cgpu->rolling);
  83. status = status_buf;
  84. }
  85. sprintf(buf, "GPU=%d,GT=%.2f,FR=%d,FP=%d,STA=%s,MHS=%.2f,A=%d,R=%d,HW=%d,U=%.2f,I=%d|",
  86. gpu, gt, gf, gp, status,
  87. cgpu->total_mhashes / total_secs,
  88. cgpu->accepted, cgpu->rejected, cgpu->hw_errors,
  89. cgpu->utility, gpus->intensity);
  90. strcat(buffer, buf);
  91. }
  92. }
  93. void cpustatus(int thr_id)
  94. {
  95. char buf[BUFSIZ];
  96. if (thr_id >= gpu_threads) {
  97. int cpu = thr_info[thr_id].cgpu->cpu_gpu;
  98. struct cgpu_info *cgpu = &cpus[cpu];
  99. cgpu->utility = cgpu->accepted / ( total_secs ? total_secs : 1 ) * 60;
  100. sprintf(buf, "CPU=%d,STA=%.2f,MHS=%.2f,A=%d,R=%d,U=%.2f|",
  101. cpu, cgpu->rolling,
  102. cgpu->total_mhashes / total_secs,
  103. cgpu->accepted, cgpu->rejected,
  104. cgpu->utility);
  105. strcat(buffer, buf);
  106. }
  107. }
  108. char *devstatus(char *params)
  109. {
  110. int i;
  111. *buffer = '\0';
  112. for (i = 0; i < gpu_threads; i++)
  113. gpustatus(i);
  114. for (i = gpu_threads; i < mining_threads; i++)
  115. cpustatus(i);
  116. return buffer;
  117. }
  118. char *poolstatus(char *params)
  119. {
  120. char buf[BUFSIZ];
  121. char *status, *lp;
  122. int i;
  123. *buffer = '\0';
  124. for (i = 0; i < total_pools; i++) {
  125. struct pool *pool = pools[i];
  126. if (!pool->enabled)
  127. status = (char *)DISABLED;
  128. else
  129. {
  130. if (pool->idle)
  131. status = (char *)DEAD;
  132. else
  133. status = (char *)ALIVE;
  134. }
  135. if (pool->hdr_path)
  136. lp = (char *)YES;
  137. else
  138. lp = (char *)NO;
  139. sprintf(buf, "POOL=%d,URL=%s,STA=%s,PRI=%d,LP=%s,Q=%d,A=%d,R=%d,DW=%d,ST=%d,GF=%d,RF=%d|",
  140. i, pool->rpc_url, status, pool->prio, lp,
  141. pool->getwork_requested,
  142. pool->accepted, pool->rejected,
  143. pool->discarded_work,
  144. pool->stale_shares,
  145. pool->getfail_occasions,
  146. pool->remotefail_occasions);
  147. strcat(buffer, buf);
  148. }
  149. return buffer;
  150. }
  151. struct CMDS {
  152. char *name;
  153. char *(*func)(char *);
  154. } cmds[] = {
  155. { "apiversion", apiversion },
  156. { "dev", devstatus },
  157. { "pool", poolstatus },
  158. };
  159. #define CMDMAX 3
  160. void send_result(int c, char *result)
  161. {
  162. int n;
  163. if (result == NULL)
  164. result = (char *)BLANK;
  165. // ignore failure - it's closed immediately anyway
  166. n = write(c, result, strlen(result)+1);
  167. }
  168. void api()
  169. {
  170. char buf[BUFSIZ];
  171. const char *addr;
  172. int c, sock, n, bound;
  173. char tmpaddr[32];
  174. char *binderror;
  175. time_t bindstart;
  176. short int port = 4028;
  177. struct sockaddr_in serv;
  178. struct sockaddr_in cli;
  179. socklen_t clisiz;
  180. long long counter;
  181. char *result;
  182. char *params;
  183. int i;
  184. addr = "127.0.0.1";
  185. sock = socket(AF_INET, SOCK_STREAM, 0);
  186. if (sock < 0) {
  187. applog(LOG_ERR, "API1 initialisation failed (%s)%s", strerror(errno), UNAVAILABLE);
  188. return;
  189. }
  190. memset(&serv, 0, sizeof(serv));
  191. serv.sin_family = AF_INET;
  192. if (inet_pton(AF_INET, addr, &(serv.sin_addr)) == 0) {
  193. applog(LOG_ERR, "API2 initialisation failed (%s)%s", strerror(errno), UNAVAILABLE);
  194. return;
  195. }
  196. serv.sin_port = htons(port);
  197. // try for 1 minute ... in case the old one hasn't completely gone yet
  198. bound = 0;
  199. bindstart = time(NULL);
  200. while (bound == 0) {
  201. if (bind(sock, (struct sockaddr *)(&serv), sizeof(serv)) < 0) {
  202. binderror = strerror(errno);
  203. if ((time(NULL) - bindstart) > 61)
  204. break;
  205. else {
  206. applog(LOG_ERR, "API bind to port %d failed - trying again in 15sec", port);
  207. sleep(15);
  208. }
  209. }
  210. else
  211. bound = 1;
  212. }
  213. if (bound == 0) {
  214. applog(LOG_ERR, "API bind to port %d failed (%s)%s", port, binderror, UNAVAILABLE);
  215. return;
  216. }
  217. if (listen(sock, QUEUE) < 0) {
  218. applog(LOG_ERR, "API3 initialisation failed (%s)%s", strerror(errno), UNAVAILABLE);
  219. close(sock);
  220. return;
  221. }
  222. buffer = malloc(MYBUFSIZ+1);
  223. counter = 0;
  224. while (bye == 0) {
  225. counter++;
  226. clisiz = sizeof(cli);
  227. if ((c = accept(sock, (struct sockaddr *)(&cli), &clisiz)) < 0) {
  228. applog(LOG_ERR, "API failed (%s)%s", strerror(errno), UNAVAILABLE);
  229. close(sock);
  230. free(buffer);
  231. return;
  232. }
  233. inet_ntop(AF_INET, &(cli.sin_addr), &(tmpaddr[0]), sizeof(tmpaddr)-1);
  234. if (strcmp(tmpaddr, addr) == 0) {
  235. n = read(c, &buf[0], BUFSIZ-1);
  236. if (n >= 0) {
  237. buf[n] = '\0';
  238. params = strchr(buf, '|');
  239. if (params != NULL)
  240. *(params++) = '\0';
  241. for (i = 0; i < CMDMAX; i++) {
  242. if (strcmp(buf, cmds[i].name) == 0) {
  243. result = (cmds[i].func)(params);
  244. send_result(c, result);
  245. close(c);
  246. break;
  247. }
  248. }
  249. }
  250. }
  251. close(c);
  252. }
  253. close(sock);
  254. free(buffer);
  255. }