api.c 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109
  1. /*
  2. * Copyright 2011-2012 Andrew Smith
  3. * Copyright 2011-2012 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/types.h>
  18. #include "compat.h"
  19. #include "miner.h"
  20. #if defined(unix)
  21. #include <errno.h>
  22. #include <sys/socket.h>
  23. #include <netinet/in.h>
  24. #include <arpa/inet.h>
  25. #define SOCKETTYPE int
  26. #define SOCKETFAIL(a) ((a) < 0)
  27. #define INVSOCK -1
  28. #define INVINETADDR -1
  29. #define CLOSESOCKET close
  30. #define SOCKERRMSG strerror(errno)
  31. #endif
  32. #ifdef WIN32
  33. #include <winsock2.h>
  34. #define SOCKETTYPE SOCKET
  35. #define SOCKETFAIL(a) ((a) == SOCKET_ERROR)
  36. #define INVSOCK INVALID_SOCKET
  37. #define INVINETADDR INADDR_NONE
  38. #define CLOSESOCKET closesocket
  39. static char WSAbuf[1024];
  40. struct WSAERRORS {
  41. int id;
  42. char *code;
  43. } WSAErrors[] = {
  44. { 0, "No error" },
  45. { WSAEINTR, "Interrupted system call" },
  46. { WSAEBADF, "Bad file number" },
  47. { WSAEACCES, "Permission denied" },
  48. { WSAEFAULT, "Bad address" },
  49. { WSAEINVAL, "Invalid argument" },
  50. { WSAEMFILE, "Too many open sockets" },
  51. { WSAEWOULDBLOCK, "Operation would block" },
  52. { WSAEINPROGRESS, "Operation now in progress" },
  53. { WSAEALREADY, "Operation already in progress" },
  54. { WSAENOTSOCK, "Socket operation on non-socket" },
  55. { WSAEDESTADDRREQ, "Destination address required" },
  56. { WSAEMSGSIZE, "Message too long" },
  57. { WSAEPROTOTYPE, "Protocol wrong type for socket" },
  58. { WSAENOPROTOOPT, "Bad protocol option" },
  59. { WSAEPROTONOSUPPORT, "Protocol not supported" },
  60. { WSAESOCKTNOSUPPORT, "Socket type not supported" },
  61. { WSAEOPNOTSUPP, "Operation not supported on socket" },
  62. { WSAEPFNOSUPPORT, "Protocol family not supported" },
  63. { WSAEAFNOSUPPORT, "Address family not supported" },
  64. { WSAEADDRINUSE, "Address already in use" },
  65. { WSAEADDRNOTAVAIL, "Can't assign requested address" },
  66. { WSAENETDOWN, "Network is down" },
  67. { WSAENETUNREACH, "Network is unreachable" },
  68. { WSAENETRESET, "Net connection reset" },
  69. { WSAECONNABORTED, "Software caused connection abort" },
  70. { WSAECONNRESET, "Connection reset by peer" },
  71. { WSAENOBUFS, "No buffer space available" },
  72. { WSAEISCONN, "Socket is already connected" },
  73. { WSAENOTCONN, "Socket is not connected" },
  74. { WSAESHUTDOWN, "Can't send after socket shutdown" },
  75. { WSAETOOMANYREFS, "Too many references, can't splice" },
  76. { WSAETIMEDOUT, "Connection timed out" },
  77. { WSAECONNREFUSED, "Connection refused" },
  78. { WSAELOOP, "Too many levels of symbolic links" },
  79. { WSAENAMETOOLONG, "File name too long" },
  80. { WSAEHOSTDOWN, "Host is down" },
  81. { WSAEHOSTUNREACH, "No route to host" },
  82. { WSAENOTEMPTY, "Directory not empty" },
  83. { WSAEPROCLIM, "Too many processes" },
  84. { WSAEUSERS, "Too many users" },
  85. { WSAEDQUOT, "Disc quota exceeded" },
  86. { WSAESTALE, "Stale NFS file handle" },
  87. { WSAEREMOTE, "Too many levels of remote in path" },
  88. { WSASYSNOTREADY, "Network system is unavailable" },
  89. { WSAVERNOTSUPPORTED, "Winsock version out of range" },
  90. { WSANOTINITIALISED, "WSAStartup not yet called" },
  91. { WSAEDISCON, "Graceful shutdown in progress" },
  92. { WSAHOST_NOT_FOUND, "Host not found" },
  93. { WSANO_DATA, "No host data of that type was found" },
  94. { -1, "Unknown error code" }
  95. };
  96. static char *WSAErrorMsg()
  97. {
  98. char *msg;
  99. int i;
  100. int id = WSAGetLastError();
  101. /* Assume none of them are actually -1 */
  102. for (i = 0; WSAErrors[i].id != -1; i++)
  103. if (WSAErrors[i].id == id)
  104. break;
  105. sprintf(WSAbuf, "Socket Error: (%d) %s", id, WSAErrors[i].code);
  106. return &(WSAbuf[0]);
  107. }
  108. #define SOCKERRMSG WSAErrorMsg()
  109. #ifndef SHUT_RDWR
  110. #define SHUT_RDWR SD_BOTH
  111. #endif
  112. #endif
  113. // Big enough for largest API request
  114. // though a PC with 100s of CPUs may exceed the size ...
  115. // Current code assumes it can socket send this size also
  116. #define MYBUFSIZ 32768
  117. // Number of requests to queue - normally would be small
  118. #define QUEUE 10
  119. static char *io_buffer = NULL;
  120. static char *msg_buffer = NULL;
  121. static SOCKETTYPE sock = INVSOCK;
  122. static const char *UNAVAILABLE = " - API will not be available";
  123. //static const char *BLANK = "";
  124. static const char *COMMA = ",";
  125. static const char SEPARATOR = '|';
  126. #define _DEVS "DEVS"
  127. #define _POOLS "POOLS"
  128. #define _SUMMARY "SUMMARY"
  129. #define _STATUS "STATUS"
  130. #define _VERSION "VERSION"
  131. #ifdef WANT_CPUMINE
  132. #define _CPU "CPU"
  133. #endif
  134. #define _GPU "GPU"
  135. #define _CPUS "CPUS"
  136. #define _GPUS "GPUS"
  137. #define _BYE "BYE"
  138. static const char ISJSON = '{';
  139. #define JSON0 "{"
  140. #define JSON1 "\""
  141. #define JSON2 "\":["
  142. #define JSON3 "]"
  143. #define JSON4 ",\"id\":1}"
  144. #define JSON_START JSON0
  145. #define JSON_DEVS JSON1 _DEVS JSON2
  146. #define JSON_POOLS JSON1 _POOLS JSON2
  147. #define JSON_SUMMARY JSON1 _SUMMARY JSON2
  148. #define JSON_STATUS JSON1 _STATUS JSON2
  149. #define JSON_VERSION JSON1 _VERSION JSON2
  150. #define JSON_GPU JSON1 _GPU JSON2
  151. #ifdef WANT_CPUMINE
  152. #define JSON_CPU JSON1 _CPU JSON2
  153. #endif
  154. #define JSON_GPUS JSON1 _GPUS JSON2
  155. #define JSON_CPUS JSON1 _CPUS JSON2
  156. #define JSON_BYE JSON1 _BYE JSON1
  157. #define JSON_CLOSE JSON3
  158. #define JSON_END JSON4
  159. static const char *JSON_COMMAND = "command";
  160. static const char *JSON_PARAMETER = "parameter";
  161. #define MSG_INVGPU 1
  162. #define MSG_ALRENA 2
  163. #define MSG_ALRDIS 3
  164. #define MSG_GPUMRE 4
  165. #define MSG_GPUREN 5
  166. #define MSG_GPUNON 6
  167. #define MSG_POOL 7
  168. #define MSG_NOPOOL 8
  169. #define MSG_DEVS 9
  170. #define MSG_NODEVS 10
  171. #define MSG_SUMM 11
  172. #define MSG_GPUDIS 12
  173. #define MSG_GPUREI 13
  174. #define MSG_INVCMD 14
  175. #define MSG_MISID 15
  176. #define MSG_GPUDEV 17
  177. #ifdef WANT_CPUMINE
  178. #define MSG_CPUNON 16
  179. #define MSG_CPUDEV 18
  180. #define MSG_INVCPU 19
  181. #endif
  182. #define MSG_NUMGPU 20
  183. #define MSG_NUMCPU 21
  184. #define MSG_VERSION 22
  185. #define MSG_INVJSON 23
  186. #define MSG_MISSCMD 24
  187. enum code_severity {
  188. SEVERITY_ERR,
  189. SEVERITY_WARN,
  190. SEVERITY_INFO,
  191. SEVERITY_SUCC,
  192. SEVERITY_FAIL
  193. };
  194. enum code_parameters {
  195. PARAM_GPU,
  196. PARAM_CPU,
  197. PARAM_GPUMAX,
  198. PARAM_CPUMAX,
  199. PARAM_PMAX,
  200. #ifdef WANT_CPUMINE
  201. PARAM_GCMAX,
  202. #else
  203. PARAM_GMAX,
  204. #endif
  205. PARAM_CMD,
  206. PARAM_NONE
  207. };
  208. struct CODES {
  209. const enum code_severity severity;
  210. const int code;
  211. const enum code_parameters params;
  212. const char *description;
  213. } codes[] = {
  214. { SEVERITY_ERR, MSG_INVGPU, PARAM_GPUMAX, "Invalid GPU id %d - range is 0 - %d" },
  215. { SEVERITY_INFO, MSG_ALRENA, PARAM_GPU, "GPU %d already enabled" },
  216. { SEVERITY_INFO, MSG_ALRDIS, PARAM_GPU, "GPU %d already disabled" },
  217. { SEVERITY_WARN, MSG_GPUMRE, PARAM_GPU, "GPU %d must be restarted first" },
  218. { SEVERITY_INFO, MSG_GPUREN, PARAM_GPU, "GPU %d sent enable message" },
  219. { SEVERITY_ERR, MSG_GPUNON, PARAM_NONE, "No GPUs" },
  220. { SEVERITY_SUCC, MSG_POOL, PARAM_PMAX, "%d Pool(s)" },
  221. { SEVERITY_ERR, MSG_NOPOOL, PARAM_NONE, "No pools" },
  222. #ifdef WANT_CPUMINE
  223. { SEVERITY_SUCC, MSG_DEVS, PARAM_GCMAX, "%d GPU(s) - %d CPU(s)" },
  224. { SEVERITY_ERR, MSG_NODEVS, PARAM_NONE, "No GPUs/CPUs" },
  225. #else
  226. { SEVERITY_SUCC, MSG_DEVS, PARAM_GMAX, "%d GPU(s)" },
  227. { SEVERITY_ERR, MSG_NODEVS, PARAM_NONE, "No GPUs" },
  228. #endif
  229. { SEVERITY_SUCC, MSG_SUMM, PARAM_NONE, "Summary" },
  230. { SEVERITY_INFO, MSG_GPUDIS, PARAM_GPU, "GPU %d set disable flag" },
  231. { SEVERITY_INFO, MSG_GPUREI, PARAM_GPU, "GPU %d restart attempted" },
  232. { SEVERITY_ERR, MSG_INVCMD, PARAM_NONE, "Invalid command" },
  233. { SEVERITY_ERR, MSG_MISID, PARAM_NONE, "Missing device id parameter" },
  234. { SEVERITY_SUCC, MSG_GPUDEV, PARAM_GPU, "GPU%d" },
  235. #ifdef WANT_CPUMINE
  236. { SEVERITY_ERR, MSG_CPUNON, PARAM_NONE, "No CPUs" },
  237. { SEVERITY_SUCC, MSG_CPUDEV, PARAM_CPU, "CPU%d" },
  238. { SEVERITY_ERR, MSG_INVCPU, PARAM_CPUMAX, "Invalid CPU id %d - range is 0 - %d" },
  239. #endif
  240. { SEVERITY_SUCC, MSG_NUMGPU, PARAM_NONE, "GPU count" },
  241. { SEVERITY_SUCC, MSG_NUMCPU, PARAM_NONE, "CPU count" },
  242. { SEVERITY_SUCC, MSG_VERSION, PARAM_NONE, "CGMiner versions" },
  243. { SEVERITY_ERR, MSG_INVJSON, PARAM_NONE, "Invalid JSON" },
  244. { SEVERITY_ERR, MSG_MISSCMD, PARAM_CMD, "Missing JSON '%s'" },
  245. { SEVERITY_FAIL }
  246. };
  247. static const char *APIVERSION = "0.8";
  248. static const char *DEAD = "Dead";
  249. static const char *SICK = "Sick";
  250. static const char *NOSTART = "NoStart";
  251. static const char *DISABLED = "Disabled";
  252. static const char *ALIVE = "Alive";
  253. static const char *DYNAMIC = "D";
  254. static const char *YES = "Y";
  255. static const char *NO = "N";
  256. static int bye = 0;
  257. static bool ping = true;
  258. // All replies (except BYE) start with a message
  259. // thus for JSON, message() inserts JSON_START at the front
  260. // and send_result() adds JSON_END at the end
  261. static char *message(int messageid, int gpuid, bool isjson)
  262. {
  263. char severity;
  264. char *ptr;
  265. #ifdef WANT_CPUMINE
  266. int cpu;
  267. #endif
  268. int i;
  269. for (i = 0; codes[i].severity != SEVERITY_FAIL; i++) {
  270. if (codes[i].code == messageid) {
  271. switch (codes[i].severity) {
  272. case SEVERITY_WARN:
  273. severity = 'W';
  274. break;
  275. case SEVERITY_INFO:
  276. severity = 'I';
  277. break;
  278. case SEVERITY_SUCC:
  279. severity = 'S';
  280. break;
  281. case SEVERITY_ERR:
  282. default:
  283. severity = 'E';
  284. break;
  285. }
  286. if (isjson)
  287. sprintf(msg_buffer, JSON_START JSON_STATUS "{\"" _STATUS "\":\"%c\",\"Code\":%d,\"Msg\":\"", severity, messageid);
  288. else
  289. sprintf(msg_buffer, _STATUS "=%c,Code=%d,Msg=", severity, messageid);
  290. ptr = msg_buffer + strlen(msg_buffer);
  291. switch(codes[i].params) {
  292. case PARAM_GPU:
  293. sprintf(ptr, codes[i].description, gpuid);
  294. break;
  295. case PARAM_CPU:
  296. sprintf(ptr, codes[i].description, gpuid);
  297. break;
  298. case PARAM_GPUMAX:
  299. sprintf(ptr, codes[i].description, gpuid, nDevs - 1);
  300. break;
  301. case PARAM_PMAX:
  302. sprintf(ptr, codes[i].description, total_pools);
  303. break;
  304. #ifdef WANT_CPUMINE
  305. case PARAM_GCMAX:
  306. if (opt_n_threads > 0)
  307. cpu = num_processors;
  308. else
  309. cpu = 0;
  310. sprintf(ptr, codes[i].description, nDevs, cpu);
  311. break;
  312. #else
  313. case PARAM_GMAX:
  314. sprintf(ptr, codes[i].description, nDevs);
  315. break;
  316. #endif
  317. case PARAM_CMD:
  318. sprintf(ptr, codes[i].description, JSON_COMMAND);
  319. break;
  320. case PARAM_NONE:
  321. default:
  322. strcpy(ptr, codes[i].description);
  323. }
  324. ptr = msg_buffer + strlen(msg_buffer);
  325. if (isjson)
  326. sprintf(ptr, "\",\"Description\":\"%s\"}" JSON_CLOSE, opt_api_description);
  327. else
  328. sprintf(ptr, ",Description=%s%c", opt_api_description, SEPARATOR);
  329. return msg_buffer;
  330. }
  331. }
  332. if (isjson)
  333. sprintf(msg_buffer, JSON_START JSON_STATUS "{\"" _STATUS "\":\"F\",\"Code\":-1,\"Msg\":\"%d\",\"Description\":\"%s\"}" JSON_CLOSE,
  334. messageid, opt_api_description);
  335. else
  336. sprintf(msg_buffer, _STATUS "=F,Code=-1,Msg=%d,Description=%s%c",
  337. messageid, opt_api_description, SEPARATOR);
  338. return msg_buffer;
  339. }
  340. void apiversion(SOCKETTYPE c, char *param, bool isjson)
  341. {
  342. if (isjson)
  343. sprintf(io_buffer, "%s," JSON_VERSION "{\"CGMiner\":\"%s\",\"API\":\"%s\"}" JSON_CLOSE,
  344. message(MSG_VERSION, 0, isjson),
  345. VERSION, APIVERSION);
  346. else
  347. sprintf(io_buffer, "%s" _VERSION ",CGMiner=%s,API=%s%c",
  348. message(MSG_VERSION, 0, isjson),
  349. VERSION, APIVERSION, SEPARATOR);
  350. }
  351. void gpustatus(int gpu, bool isjson)
  352. {
  353. char intensity[20];
  354. char buf[BUFSIZ];
  355. char *enabled;
  356. char *status;
  357. float gt, gv;
  358. int ga, gf, gp, gc, gm, pt;
  359. if (gpu >= 0 && gpu < nDevs) {
  360. struct cgpu_info *cgpu = &gpus[gpu];
  361. cgpu->utility = cgpu->accepted / ( total_secs ? total_secs : 1 ) * 60;
  362. #ifdef HAVE_ADL
  363. if (!gpu_stats(gpu, &gt, &gc, &gm, &gv, &ga, &gf, &gp, &pt))
  364. #endif
  365. gt = gv = gm = gc = ga = gf = gp = pt = 0;
  366. if (cgpu->enabled)
  367. enabled = (char *)YES;
  368. else
  369. enabled = (char *)NO;
  370. if (cgpu->status == LIFE_DEAD)
  371. status = (char *)DEAD;
  372. else if (cgpu->status == LIFE_SICK)
  373. status = (char *)SICK;
  374. else if (cgpu->status == LIFE_NOSTART)
  375. status = (char *)NOSTART;
  376. else
  377. status = (char *)ALIVE;
  378. if (cgpu->dynamic)
  379. strcpy(intensity, DYNAMIC);
  380. else
  381. sprintf(intensity, "%d", gpus->intensity);
  382. if (isjson)
  383. sprintf(buf, "{\"GPU\":%d,\"Enabled\":\"%s\",\"Status\":\"%s\",\"Temperature\":%.2f,\"Fan Speed\":%d,\"Fan Percent\":%d,\"GPU Clock\":%d,\"Memory Clock\":%d,\"GPU Voltage\":%.3f,\"GPU Activity\":%d,\"Powertune\":%d,\"MHS av\":%.2f,\"MHS %ds\":%.2f,\"Accepted\":%d,\"Rejected\":%d,\"Hardware Errors\":%d,\"Utility\":%.2f,\"Intensity\":\"%s\"}",
  384. gpu, enabled, status, gt, gf, gp, gc, gm, gv, ga, pt,
  385. cgpu->total_mhashes / total_secs, opt_log_interval, cgpu->rolling,
  386. cgpu->accepted, cgpu->rejected, cgpu->hw_errors,
  387. cgpu->utility, intensity);
  388. else
  389. sprintf(buf, "GPU=%d,Enabled=%s,Status=%s,Temperature=%.2f,Fan Speed=%d,Fan Percent=%d,GPU Clock=%d,Memory Clock=%d,GPU Voltage=%.3f,GPU Activity=%d,Powertune=%d,MHS av=%.2f,MHS %ds=%.2f,Accepted=%d,Rejected=%d,Hardware Errors=%d,Utility=%.2f,Intensity=%s%c",
  390. gpu, enabled, status, gt, gf, gp, gc, gm, gv, ga, pt,
  391. cgpu->total_mhashes / total_secs, opt_log_interval, cgpu->rolling,
  392. cgpu->accepted, cgpu->rejected, cgpu->hw_errors,
  393. cgpu->utility, intensity, SEPARATOR);
  394. strcat(io_buffer, buf);
  395. }
  396. }
  397. #ifdef WANT_CPUMINE
  398. void cpustatus(int cpu, bool isjson)
  399. {
  400. char buf[BUFSIZ];
  401. if (opt_n_threads > 0 && cpu >= 0 && cpu < num_processors) {
  402. struct cgpu_info *cgpu = &cpus[cpu];
  403. cgpu->utility = cgpu->accepted / ( total_secs ? total_secs : 1 ) * 60;
  404. if (isjson)
  405. sprintf(buf, "{\"CPU\":%d,\"MHS av\":%.2f,\"MHS %ds\":%.2f,\"Accepted\":%d,\"Rejected\":%d,\"Utility\":%.2f}",
  406. cpu, cgpu->total_mhashes / total_secs,
  407. opt_log_interval, cgpu->rolling,
  408. cgpu->accepted, cgpu->rejected,
  409. cgpu->utility);
  410. else
  411. sprintf(buf, "CPU=%d,MHS av=%.2f,MHS %ds=%.2f,Accepted=%d,Rejected=%d,Utility=%.2f%c",
  412. cpu, cgpu->total_mhashes / total_secs,
  413. opt_log_interval, cgpu->rolling,
  414. cgpu->accepted, cgpu->rejected,
  415. cgpu->utility, SEPARATOR);
  416. strcat(io_buffer, buf);
  417. }
  418. }
  419. #endif
  420. void devstatus(SOCKETTYPE c, char *param, bool isjson)
  421. {
  422. int i;
  423. if (nDevs == 0 && opt_n_threads == 0) {
  424. strcpy(io_buffer, message(MSG_NODEVS, 0, isjson));
  425. return;
  426. }
  427. strcpy(io_buffer, message(MSG_DEVS, 0, isjson));
  428. if (isjson) {
  429. strcat(io_buffer, COMMA);
  430. strcat(io_buffer, JSON_DEVS);
  431. }
  432. for (i = 0; i < nDevs; i++) {
  433. if (isjson && i > 0)
  434. strcat(io_buffer, COMMA);
  435. gpustatus(i, isjson);
  436. }
  437. #ifdef WANT_CPUMINE
  438. if (opt_n_threads > 0)
  439. for (i = 0; i < num_processors; i++) {
  440. if (isjson && (i > 0 || nDevs > 0))
  441. strcat(io_buffer, COMMA);
  442. cpustatus(i, isjson);
  443. }
  444. #endif
  445. if (isjson)
  446. strcat(io_buffer, JSON_CLOSE);
  447. }
  448. void gpudev(SOCKETTYPE c, char *param, bool isjson)
  449. {
  450. int id;
  451. if (nDevs == 0) {
  452. strcpy(io_buffer, message(MSG_GPUNON, 0, isjson));
  453. return;
  454. }
  455. if (param == NULL || *param == '\0') {
  456. strcpy(io_buffer, message(MSG_MISID, 0, isjson));
  457. return;
  458. }
  459. id = atoi(param);
  460. if (id < 0 || id >= nDevs) {
  461. strcpy(io_buffer, message(MSG_INVGPU, id, isjson));
  462. return;
  463. }
  464. strcpy(io_buffer, message(MSG_GPUDEV, id, isjson));
  465. if (isjson) {
  466. strcat(io_buffer, COMMA);
  467. strcat(io_buffer, JSON_GPU);
  468. }
  469. gpustatus(id, isjson);
  470. if (isjson)
  471. strcat(io_buffer, JSON_CLOSE);
  472. }
  473. #ifdef WANT_CPUMINE
  474. void cpudev(SOCKETTYPE c, char *param, bool isjson)
  475. {
  476. int id;
  477. if (opt_n_threads == 0) {
  478. strcpy(io_buffer, message(MSG_CPUNON, 0, isjson));
  479. return;
  480. }
  481. if (param == NULL || *param == '\0') {
  482. strcpy(io_buffer, message(MSG_MISID, 0, isjson));
  483. return;
  484. }
  485. id = atoi(param);
  486. if (id < 0 || id >= num_processors) {
  487. strcpy(io_buffer, message(MSG_INVCPU, id, isjson));
  488. return;
  489. }
  490. strcpy(io_buffer, message(MSG_CPUDEV, id, isjson));
  491. if (isjson) {
  492. strcat(io_buffer, COMMA);
  493. strcat(io_buffer, JSON_CPU);
  494. }
  495. cpustatus(id, isjson);
  496. if (isjson)
  497. strcat(io_buffer, JSON_CLOSE);
  498. }
  499. #endif
  500. void poolstatus(SOCKETTYPE c, char *param, bool isjson)
  501. {
  502. char buf[BUFSIZ];
  503. char *status, *lp;
  504. int i;
  505. if (total_pools == 0) {
  506. strcpy(io_buffer, message(MSG_NOPOOL, 0, isjson));
  507. return;
  508. }
  509. strcpy(io_buffer, message(MSG_POOL, 0, isjson));
  510. if (isjson) {
  511. strcat(io_buffer, COMMA);
  512. strcat(io_buffer, JSON_POOLS);
  513. }
  514. for (i = 0; i < total_pools; i++) {
  515. struct pool *pool = pools[i];
  516. if (!pool->enabled)
  517. status = (char *)DISABLED;
  518. else {
  519. if (pool->idle)
  520. status = (char *)DEAD;
  521. else
  522. status = (char *)ALIVE;
  523. }
  524. if (pool->hdr_path)
  525. lp = (char *)YES;
  526. else
  527. lp = (char *)NO;
  528. if (isjson)
  529. sprintf(buf, "%s{\"POOL\":%d,\"URL\":\"%s\",\"Status\":\"%s\",\"Priority\":%d,\"Long Poll\":\"%s\",\"Getworks\":%d,\"Accepted\":%d,\"Rejected\":%d,\"Discarded\":%d,\"Stale\":%d,\"Get Failures\":%d,\"Remote Failures\":%d}",
  530. (i > 0) ? COMMA : "",
  531. i, pool->rpc_url, status, pool->prio, lp,
  532. pool->getwork_requested,
  533. pool->accepted, pool->rejected,
  534. pool->discarded_work,
  535. pool->stale_shares,
  536. pool->getfail_occasions,
  537. pool->remotefail_occasions);
  538. else
  539. sprintf(buf, "POOL=%d,URL=%s,Status=%s,Priority=%d,Long Poll=%s,Getworks=%d,Accepted=%d,Rejected=%d,Discarded=%d,Stale=%d,Get Failures=%d,Remote Failures=%d%c",
  540. i, pool->rpc_url, status, pool->prio, lp,
  541. pool->getwork_requested,
  542. pool->accepted, pool->rejected,
  543. pool->discarded_work,
  544. pool->stale_shares,
  545. pool->getfail_occasions,
  546. pool->remotefail_occasions, SEPARATOR);
  547. strcat(io_buffer, buf);
  548. }
  549. if (isjson)
  550. strcat(io_buffer, JSON_CLOSE);
  551. }
  552. void summary(SOCKETTYPE c, char *param, bool isjson)
  553. {
  554. double utility, mhs;
  555. #ifdef WANT_CPUMINE
  556. char *algo = (char *)(algo_names[opt_algo]);
  557. if (algo == NULL)
  558. algo = "(null)";
  559. #endif
  560. utility = total_accepted / ( total_secs ? total_secs : 1 ) * 60;
  561. mhs = total_mhashes_done / total_secs;
  562. #ifdef WANT_CPUMINE
  563. if (isjson)
  564. sprintf(io_buffer, "%s," JSON_SUMMARY "{\"Elapsed\":%.0f,\"Algorithm\":\"%s\",\"MHS av\":%.2f,\"Found Blocks\":%d,\"Getworks\":%d,\"Accepted\":%d,\"Rejected\":%d,\"Hardware Errors\":%d,\"Utility\":%.2f,\"Discarded\":%d,\"Stale\":%d,\"Get Failures\":%d,\"Local Work\":%u,\"Remote Failures\":%u,\"Network Blocks\":%u}" JSON_CLOSE,
  565. message(MSG_SUMM, 0, isjson),
  566. total_secs, algo, mhs, found_blocks,
  567. total_getworks, total_accepted, total_rejected,
  568. hw_errors, utility, total_discarded, total_stale,
  569. total_go, local_work, total_ro, new_blocks);
  570. else
  571. sprintf(io_buffer, "%s" _SUMMARY ",Elapsed=%.0f,Algorithm=%s,MHS av=%.2f,Found Blocks=%d,Getworks=%d,Accepted=%d,Rejected=%d,Hardware Errors=%d,Utility=%.2f,Discarded=%d,Stale=%d,Get Failures=%d,Local Work=%u,Remote Failures=%u,Network Blocks=%u%c",
  572. message(MSG_SUMM, 0, isjson),
  573. total_secs, algo, mhs, found_blocks,
  574. total_getworks, total_accepted, total_rejected,
  575. hw_errors, utility, total_discarded, total_stale,
  576. total_go, local_work, total_ro, new_blocks, SEPARATOR);
  577. #else
  578. if (isjson)
  579. sprintf(io_buffer, "%s," JSON_SUMMARY "{\"Elapsed\":%.0f,\"MHS av\":%.2f,\"Found Blocks\":%d,\"Getworks\":%d,\"Accepted\":%d,\"Rejected\":%d,\"Hardware Errors\":%d,\"Utility\":%.2f,\"Discarded\":%d,\"Stale\":%d,\"Get Failures\":%d,\"Local Work\":%u,\"Remote Failures\":%u,\"Network Blocks\":%u}" JSON_CLOSE,
  580. message(MSG_SUMM, 0, isjson),
  581. total_secs, mhs, found_blocks,
  582. total_getworks, total_accepted, total_rejected,
  583. hw_errors, utility, total_discarded, total_stale,
  584. total_go, local_work, total_ro, new_blocks);
  585. else
  586. sprintf(io_buffer, "%s" _SUMMARY ",Elapsed=%.0f,MHS av=%.2f,Found Blocks=%d,Getworks=%d,Accepted=%d,Rejected=%d,Hardware Errors=%d,Utility=%.2f,Discarded=%d,Stale=%d,Get Failures=%d,Local Work=%u,Remote Failures=%u,Network Blocks=%u%c",
  587. message(MSG_SUMM, 0, isjson),
  588. total_secs, mhs, found_blocks,
  589. total_getworks, total_accepted, total_rejected,
  590. hw_errors, utility, total_discarded, total_stale,
  591. total_go, local_work, total_ro, new_blocks, SEPARATOR);
  592. #endif
  593. }
  594. void gpuenable(SOCKETTYPE c, char *param, bool isjson)
  595. {
  596. struct thr_info *thr;
  597. int gpu;
  598. int id;
  599. int i;
  600. if (gpu_threads == 0) {
  601. strcpy(io_buffer, message(MSG_GPUNON, 0, isjson));
  602. return;
  603. }
  604. if (param == NULL || *param == '\0') {
  605. strcpy(io_buffer, message(MSG_MISID, 0, isjson));
  606. return;
  607. }
  608. id = atoi(param);
  609. if (id < 0 || id >= nDevs) {
  610. strcpy(io_buffer, message(MSG_INVGPU, id, isjson));
  611. return;
  612. }
  613. if (gpus[id].enabled) {
  614. strcpy(io_buffer, message(MSG_ALRENA, id, isjson));
  615. return;
  616. }
  617. for (i = 0; i < gpu_threads; i++) {
  618. gpu = thr_info[i].cgpu->device_id;
  619. if (gpu == id) {
  620. thr = &thr_info[i];
  621. if (thr->cgpu->status != LIFE_WELL) {
  622. strcpy(io_buffer, message(MSG_GPUMRE, id, isjson));
  623. return;
  624. }
  625. gpus[id].enabled = true;
  626. tq_push(thr->q, &ping);
  627. }
  628. }
  629. strcpy(io_buffer, message(MSG_GPUREN, id, isjson));
  630. }
  631. void gpudisable(SOCKETTYPE c, char *param, bool isjson)
  632. {
  633. int id;
  634. if (nDevs == 0) {
  635. strcpy(io_buffer, message(MSG_GPUNON, 0, isjson));
  636. return;
  637. }
  638. if (param == NULL || *param == '\0') {
  639. strcpy(io_buffer, message(MSG_MISID, 0, isjson));
  640. return;
  641. }
  642. id = atoi(param);
  643. if (id < 0 || id >= nDevs) {
  644. strcpy(io_buffer, message(MSG_INVGPU, id, isjson));
  645. return;
  646. }
  647. if (!gpus[id].enabled) {
  648. strcpy(io_buffer, message(MSG_ALRDIS, id, isjson));
  649. return;
  650. }
  651. gpus[id].enabled = false;
  652. strcpy(io_buffer, message(MSG_GPUDIS, id, isjson));
  653. }
  654. void gpurestart(SOCKETTYPE c, char *param, bool isjson)
  655. {
  656. int id;
  657. if (nDevs == 0) {
  658. strcpy(io_buffer, message(MSG_GPUNON, 0, isjson));
  659. return;
  660. }
  661. if (param == NULL || *param == '\0') {
  662. strcpy(io_buffer, message(MSG_MISID, 0, isjson));
  663. return;
  664. }
  665. id = atoi(param);
  666. if (id < 0 || id >= nDevs) {
  667. strcpy(io_buffer, message(MSG_INVGPU, id, isjson));
  668. return;
  669. }
  670. reinit_device(&gpus[id]);
  671. strcpy(io_buffer, message(MSG_GPUREI, id, isjson));
  672. }
  673. void gpucount(SOCKETTYPE c, char *param, bool isjson)
  674. {
  675. char buf[BUFSIZ];
  676. strcpy(io_buffer, message(MSG_NUMGPU, 0, isjson));
  677. if (isjson)
  678. sprintf(buf, "," JSON_GPUS "{\"Count\":%d}" JSON_CLOSE, nDevs);
  679. else
  680. sprintf(buf, _GPUS ",Count=%d%c", nDevs, SEPARATOR);
  681. strcat(io_buffer, buf);
  682. }
  683. void cpucount(SOCKETTYPE c, char *param, bool isjson)
  684. {
  685. char buf[BUFSIZ];
  686. int count = 0;
  687. #ifdef WANT_CPUMINE
  688. count = opt_n_threads > 0 ? num_processors : 0;
  689. #endif
  690. strcpy(io_buffer, message(MSG_NUMCPU, 0, isjson));
  691. if (isjson)
  692. sprintf(buf, "," JSON_CPUS "{\"Count\":%d}" JSON_CLOSE, count);
  693. else
  694. sprintf(buf, _CPUS ",Count=%d%c", count, SEPARATOR);
  695. strcat(io_buffer, buf);
  696. }
  697. void send_result(SOCKETTYPE c, bool isjson);
  698. void doquit(SOCKETTYPE c, char *param, bool isjson)
  699. {
  700. if (isjson)
  701. strcpy(io_buffer, JSON_START JSON_BYE);
  702. else
  703. strcpy(io_buffer, _BYE);
  704. send_result(c, isjson);
  705. *io_buffer = '\0';
  706. bye = 1;
  707. kill_work();
  708. }
  709. struct CMDS {
  710. char *name;
  711. void (*func)(SOCKETTYPE, char *, bool);
  712. } cmds[] = {
  713. { "version", apiversion },
  714. { "devs", devstatus },
  715. { "pools", poolstatus },
  716. { "summary", summary },
  717. { "gpuenable", gpuenable },
  718. { "gpudisable", gpudisable },
  719. { "gpurestart", gpurestart },
  720. { "gpu", gpudev },
  721. #ifdef WANT_CPUMINE
  722. { "cpu", cpudev },
  723. #endif
  724. { "gpucount", gpucount },
  725. { "cpucount", cpucount },
  726. { "quit", doquit },
  727. { NULL }
  728. };
  729. void send_result(SOCKETTYPE c, bool isjson)
  730. {
  731. int n;
  732. int len;
  733. if (isjson)
  734. strcat(io_buffer, JSON_END);
  735. len = strlen(io_buffer);
  736. if (opt_debug)
  737. applog(LOG_DEBUG, "DBG: send reply: (%d) '%.10s%s'", len+1, io_buffer, len > 10 ? "..." : "");
  738. // ignore failure - it's closed immediately anyway
  739. n = send(c, io_buffer, len+1, 0);
  740. if (opt_debug) {
  741. if (SOCKETFAIL(n))
  742. applog(LOG_DEBUG, "DBG: send failed: %s", SOCKERRMSG);
  743. else
  744. applog(LOG_DEBUG, "DBG: sent %d", n);
  745. }
  746. }
  747. void tidyup()
  748. {
  749. bye = 1;
  750. if (sock != INVSOCK) {
  751. shutdown(sock, SHUT_RDWR);
  752. CLOSESOCKET(sock);
  753. sock = INVSOCK;
  754. }
  755. if (msg_buffer != NULL) {
  756. free(msg_buffer);
  757. msg_buffer = NULL;
  758. }
  759. if (io_buffer != NULL) {
  760. free(io_buffer);
  761. io_buffer = NULL;
  762. }
  763. }
  764. void api(void)
  765. {
  766. char buf[BUFSIZ];
  767. char param_buf[BUFSIZ];
  768. const char *localaddr = "127.0.0.1";
  769. SOCKETTYPE c;
  770. int n, bound;
  771. char *connectaddr;
  772. char *binderror;
  773. time_t bindstart;
  774. short int port = opt_api_port;
  775. struct sockaddr_in serv;
  776. struct sockaddr_in cli;
  777. socklen_t clisiz;
  778. char *cmd;
  779. char *param;
  780. bool addrok;
  781. json_error_t json_err;
  782. json_t *json_config;
  783. json_t *json_val;
  784. bool isjson;
  785. bool did;
  786. int i;
  787. /* This should be done first to ensure curl has already called WSAStartup() in windows */
  788. sleep(opt_log_interval);
  789. if (!opt_api_listen) {
  790. applog(LOG_DEBUG, "API not running%s", UNAVAILABLE);
  791. return;
  792. }
  793. sock = socket(AF_INET, SOCK_STREAM, 0);
  794. if (sock == INVSOCK) {
  795. applog(LOG_ERR, "API1 initialisation failed (%s)%s", SOCKERRMSG, UNAVAILABLE);
  796. return;
  797. }
  798. memset(&serv, 0, sizeof(serv));
  799. serv.sin_family = AF_INET;
  800. if (!opt_api_network) {
  801. serv.sin_addr.s_addr = inet_addr(localaddr);
  802. if (serv.sin_addr.s_addr == INVINETADDR) {
  803. applog(LOG_ERR, "API2 initialisation failed (%s)%s", SOCKERRMSG, UNAVAILABLE);
  804. return;
  805. }
  806. }
  807. serv.sin_port = htons(port);
  808. // try for more than 1 minute ... in case the old one hasn't completely gone yet
  809. bound = 0;
  810. bindstart = time(NULL);
  811. while (bound == 0) {
  812. if (SOCKETFAIL(bind(sock, (struct sockaddr *)(&serv), sizeof(serv)))) {
  813. binderror = SOCKERRMSG;
  814. if ((time(NULL) - bindstart) > 61)
  815. break;
  816. else {
  817. applog(LOG_WARNING, "API bind to port %d failed - trying again in 15sec", port);
  818. sleep(15);
  819. }
  820. }
  821. else
  822. bound = 1;
  823. }
  824. if (bound == 0) {
  825. applog(LOG_ERR, "API bind to port %d failed (%s)%s", port, binderror, UNAVAILABLE);
  826. return;
  827. }
  828. if (SOCKETFAIL(listen(sock, QUEUE))) {
  829. applog(LOG_ERR, "API3 initialisation failed (%s)%s", SOCKERRMSG, UNAVAILABLE);
  830. CLOSESOCKET(sock);
  831. return;
  832. }
  833. if (opt_api_network)
  834. applog(LOG_WARNING, "API running in UNRESTRICTED access mode");
  835. else
  836. applog(LOG_WARNING, "API running in restricted access mode");
  837. io_buffer = malloc(MYBUFSIZ+1);
  838. msg_buffer = malloc(MYBUFSIZ+1);
  839. while (bye == 0) {
  840. clisiz = sizeof(cli);
  841. if (SOCKETFAIL(c = accept(sock, (struct sockaddr *)(&cli), &clisiz))) {
  842. applog(LOG_ERR, "API failed (%s)%s", SOCKERRMSG, UNAVAILABLE);
  843. goto die;
  844. }
  845. if (opt_api_network)
  846. addrok = true;
  847. else {
  848. connectaddr = inet_ntoa(cli.sin_addr);
  849. addrok = (strcmp(connectaddr, localaddr) == 0);
  850. }
  851. if (opt_debug) {
  852. connectaddr = inet_ntoa(cli.sin_addr);
  853. applog(LOG_DEBUG, "DBG: connection from %s - %s", connectaddr, addrok ? "Accepted" : "Ignored");
  854. }
  855. if (addrok) {
  856. n = recv(c, &buf[0], BUFSIZ-1, 0);
  857. if (SOCKETFAIL(n))
  858. buf[0] = '\0';
  859. else
  860. buf[n] = '\0';
  861. if (opt_debug) {
  862. if (SOCKETFAIL(n))
  863. applog(LOG_DEBUG, "DBG: recv failed: %s", SOCKERRMSG);
  864. else
  865. applog(LOG_DEBUG, "DBG: recv command: (%d) '%s'", n, buf);
  866. }
  867. if (!SOCKETFAIL(n)) {
  868. did = false;
  869. if (*buf != ISJSON) {
  870. isjson = false;
  871. param = strchr(buf, SEPARATOR);
  872. if (param != NULL)
  873. *(param++) = '\0';
  874. cmd = buf;
  875. }
  876. else {
  877. isjson = true;
  878. param = NULL;
  879. json_config = json_loadb(buf, n, 0, &json_err);
  880. if (!json_is_object(json_config)) {
  881. strcpy(io_buffer, message(MSG_INVJSON, 0, isjson));
  882. send_result(c, isjson);
  883. did = true;
  884. }
  885. else {
  886. json_val = json_object_get(json_config, JSON_COMMAND);
  887. if (json_val == NULL) {
  888. strcpy(io_buffer, message(MSG_MISSCMD, 0, isjson));
  889. send_result(c, isjson);
  890. did = true;
  891. }
  892. else {
  893. if (!json_is_string(json_val)) {
  894. strcpy(io_buffer, message(MSG_INVCMD, 0, isjson));
  895. send_result(c, isjson);
  896. did = true;
  897. }
  898. else {
  899. cmd = (char *)json_string_value(json_val);
  900. json_val = json_object_get(json_config, JSON_PARAMETER);
  901. if (json_is_string(json_val))
  902. param = (char *)json_string_value(json_val);
  903. else if (json_is_integer(json_val)) {
  904. sprintf(param_buf, "%d", (int)json_integer_value(json_val));
  905. param = param_buf;
  906. } else if (json_is_real(json_val)) {
  907. sprintf(param_buf, "%f", (double)json_real_value(json_val));
  908. param = param_buf;
  909. }
  910. }
  911. }
  912. }
  913. }
  914. if (!did)
  915. for (i = 0; cmds[i].name != NULL; i++) {
  916. if (strcmp(cmd, cmds[i].name) == 0) {
  917. (cmds[i].func)(c, param, isjson);
  918. send_result(c, isjson);
  919. did = true;
  920. break;
  921. }
  922. }
  923. if (!did) {
  924. strcpy(io_buffer, message(MSG_INVCMD, 0, isjson));
  925. send_result(c, isjson);
  926. }
  927. }
  928. }
  929. CLOSESOCKET(c);
  930. }
  931. die:
  932. tidyup();
  933. }