api.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844
  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/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 16384
  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 SEPARATOR = '|';
  125. #define MSG_INVGPU 1
  126. #define MSG_ALRENA 2
  127. #define MSG_ALRDIS 3
  128. #define MSG_GPUMRE 4
  129. #define MSG_GPUREN 5
  130. #define MSG_GPUNON 6
  131. #define MSG_POOL 7
  132. #define MSG_NOPOOL 8
  133. #define MSG_DEVS 9
  134. #define MSG_NODEVS 10
  135. #define MSG_SUMM 11
  136. #define MSG_GPUDIS 12
  137. #define MSG_GPUREI 13
  138. #define MSG_INVCMD 14
  139. #define MSG_MISID 15
  140. #define MSG_CPUNON 16
  141. #define MSG_GPUDEV 17
  142. #define MSG_CPUDEV 18
  143. #define MSG_INVCPU 19
  144. #define MSG_NUMGPU 20
  145. #define MSG_NUMCPU 21
  146. #define MSG_VERSION 22
  147. enum code_severity {
  148. SEVERITY_ERR,
  149. SEVERITY_WARN,
  150. SEVERITY_INFO,
  151. SEVERITY_SUCC,
  152. SEVERITY_FAIL
  153. };
  154. enum code_parameters {
  155. PARAM_GPU,
  156. PARAM_CPU,
  157. PARAM_GPUMAX,
  158. PARAM_CPUMAX,
  159. PARAM_PMAX,
  160. PARAM_GCMAX,
  161. PARAM_NONE
  162. };
  163. struct CODES {
  164. const enum code_severity severity;
  165. const int code;
  166. const enum code_parameters params;
  167. const char *description;
  168. } codes[] = {
  169. { SEVERITY_ERR, MSG_INVGPU, PARAM_GPUMAX, "Invalid GPU id %d - range is 0 - %d" },
  170. { SEVERITY_INFO, MSG_ALRENA, PARAM_GPU, "GPU %d already enabled" },
  171. { SEVERITY_INFO, MSG_ALRDIS, PARAM_GPU, "GPU %d already disabled" },
  172. { SEVERITY_WARN, MSG_GPUMRE, PARAM_GPU, "GPU %d must be restarted first" },
  173. { SEVERITY_INFO, MSG_GPUREN, PARAM_GPU, "GPU %d sent enable message" },
  174. { SEVERITY_ERR, MSG_GPUNON, PARAM_NONE, "No GPUs" },
  175. { SEVERITY_SUCC, MSG_POOL, PARAM_PMAX, "%d Pool(s)" },
  176. { SEVERITY_ERR, MSG_NOPOOL, PARAM_NONE, "No pools" },
  177. { SEVERITY_SUCC, MSG_DEVS, PARAM_GCMAX, "%d GPU(s) - %d CPU(s)" },
  178. { SEVERITY_ERR, MSG_NODEVS, PARAM_NONE, "No GPUs/CPUs" },
  179. { SEVERITY_SUCC, MSG_SUMM, PARAM_NONE, "Summary" },
  180. { SEVERITY_INFO, MSG_GPUDIS, PARAM_GPU, "GPU %d set disable flag" },
  181. { SEVERITY_INFO, MSG_GPUREI, PARAM_GPU, "GPU %d restart attempted" },
  182. { SEVERITY_ERR, MSG_INVCMD, PARAM_NONE, "Invalid command" },
  183. { SEVERITY_ERR, MSG_MISID, PARAM_NONE, "Missing device id parameter" },
  184. { SEVERITY_ERR, MSG_CPUNON, PARAM_NONE, "No CPUs" },
  185. { SEVERITY_SUCC, MSG_GPUDEV, PARAM_GPU, "GPU%d" },
  186. { SEVERITY_SUCC, MSG_CPUDEV, PARAM_CPU, "CPU%d" },
  187. { SEVERITY_ERR, MSG_INVCPU, PARAM_CPUMAX, "Invalid CPU id %d - range is 0 - %d" },
  188. { SEVERITY_SUCC, MSG_NUMGPU, PARAM_NONE, "GPU count" },
  189. { SEVERITY_SUCC, MSG_NUMCPU, PARAM_NONE, "CPU count" },
  190. { SEVERITY_SUCC, MSG_VERSION, PARAM_CPU, "CGMiner versions" },
  191. { SEVERITY_FAIL }
  192. };
  193. static const char *APIVERSION = "0.5";
  194. static const char *DEAD = "Dead";
  195. static const char *SICK = "Sick";
  196. static const char *NOSTART = "NoStart";
  197. static const char *DISABLED = "Disabled";
  198. static const char *ALIVE = "Alive";
  199. static const char *DYNAMIC = "D";
  200. static const char *YES = "Y";
  201. static const char *NO = "N";
  202. static int bye = 0;
  203. static bool ping = true;
  204. static char *message(int messageid, int gpuid)
  205. {
  206. char severity;
  207. char *ptr;
  208. int cpu;
  209. int i;
  210. for (i = 0; codes[i].severity != SEVERITY_FAIL; i++) {
  211. if (codes[i].code == messageid) {
  212. switch (codes[i].severity) {
  213. case SEVERITY_WARN:
  214. severity = 'W';
  215. break;
  216. case SEVERITY_INFO:
  217. severity = 'I';
  218. break;
  219. case SEVERITY_SUCC:
  220. severity = 'S';
  221. break;
  222. case SEVERITY_ERR:
  223. default:
  224. severity = 'E';
  225. break;
  226. }
  227. sprintf(msg_buffer, "STATUS=%c,Code=%d,Msg=", severity, messageid);
  228. ptr = msg_buffer + strlen(msg_buffer);
  229. switch(codes[i].params) {
  230. case PARAM_GPU:
  231. sprintf(ptr, codes[i].description, gpuid);
  232. break;
  233. case PARAM_CPU:
  234. sprintf(ptr, codes[i].description, gpuid);
  235. break;
  236. case PARAM_GPUMAX:
  237. sprintf(ptr, codes[i].description, gpuid, nDevs - 1);
  238. break;
  239. case PARAM_PMAX:
  240. sprintf(ptr, codes[i].description, total_pools);
  241. break;
  242. case PARAM_GCMAX:
  243. if (opt_n_threads > 0)
  244. cpu = num_processors;
  245. else
  246. cpu = 0;
  247. sprintf(ptr, codes[i].description, nDevs, cpu);
  248. break;
  249. case PARAM_NONE:
  250. default:
  251. strcpy(ptr, codes[i].description);
  252. }
  253. ptr = msg_buffer + strlen(msg_buffer);
  254. sprintf(ptr, ",Description=%s%c",
  255. opt_api_description, SEPARATOR);
  256. return msg_buffer;
  257. }
  258. }
  259. sprintf(msg_buffer, "STATUS=F,Code=-1,Msg=%d,Description=%s%c",
  260. messageid, opt_api_description, SEPARATOR);
  261. return msg_buffer;
  262. }
  263. void apiversion(SOCKETTYPE c, char *params)
  264. {
  265. sprintf(io_buffer, "%sVERSION,CGMiner=%s,API=%s%c",
  266. message(MSG_VERSION, 0),
  267. VERSION, APIVERSION, SEPARATOR);
  268. }
  269. void gpustatus(int gpu)
  270. {
  271. char intensity[20];
  272. char buf[BUFSIZ];
  273. char *enabled;
  274. char *status;
  275. float gt, gv;
  276. int ga, gf, gp, gc, gm, pt;
  277. if (gpu >= 0 && gpu < nDevs) {
  278. struct cgpu_info *cgpu = &gpus[gpu];
  279. cgpu->utility = cgpu->accepted / ( total_secs ? total_secs : 1 ) * 60;
  280. #ifdef HAVE_ADL
  281. if (!gpu_stats(gpu, &gt, &gc, &gm, &gv, &ga, &gf, &gp, &pt))
  282. #endif
  283. gt = gv = gm = gc = ga = gf = gp = pt = 0;
  284. if (gpu_devices[gpu])
  285. enabled = (char *)YES;
  286. else
  287. enabled = (char *)NO;
  288. if (cgpu->status == LIFE_DEAD)
  289. status = (char *)DEAD;
  290. else if (cgpu->status == LIFE_SICK)
  291. status = (char *)SICK;
  292. else if (cgpu->status == LIFE_NOSTART)
  293. status = (char *)NOSTART;
  294. else
  295. status = (char *)ALIVE;
  296. if (cgpu->dynamic)
  297. strcpy(intensity, DYNAMIC);
  298. else
  299. sprintf(intensity, "%d", gpus->intensity);
  300. 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=%.2f,Accepted=%d,Rejected=%d,Hardware Errors=%d,Utility=%.2f,Intensity=%s%c",
  301. gpu, enabled, status, gt, gf, gp, gc, gm, gv, ga, pt,
  302. cgpu->total_mhashes / total_secs,
  303. cgpu->accepted, cgpu->rejected, cgpu->hw_errors,
  304. cgpu->utility, intensity, SEPARATOR);
  305. strcat(io_buffer, buf);
  306. }
  307. }
  308. void cpustatus(int cpu)
  309. {
  310. char buf[BUFSIZ];
  311. if (opt_n_threads > 0 && cpu >= 0 && cpu < num_processors) {
  312. struct cgpu_info *cgpu = &cpus[cpu];
  313. cgpu->utility = cgpu->accepted / ( total_secs ? total_secs : 1 ) * 60;
  314. sprintf(buf, "CPU=%d,Status=%.2f,MHS=%.2f,Accepted=%d,Rejected=%d,Utility=%.2f%c",
  315. cpu, cgpu->rolling,
  316. cgpu->total_mhashes / total_secs,
  317. cgpu->accepted, cgpu->rejected,
  318. cgpu->utility, SEPARATOR);
  319. strcat(io_buffer, buf);
  320. }
  321. }
  322. void devstatus(SOCKETTYPE c, char *params)
  323. {
  324. int i;
  325. if (nDevs == 0 && opt_n_threads == 0) {
  326. strcpy(io_buffer, message(MSG_NODEVS, 0));
  327. return;
  328. }
  329. strcpy(io_buffer, message(MSG_DEVS, 0));
  330. for (i = 0; i < nDevs; i++)
  331. gpustatus(i);
  332. if (opt_n_threads > 0)
  333. for (i = 0; i < num_processors; i++)
  334. cpustatus(i);
  335. }
  336. void gpudev(SOCKETTYPE c, char *params)
  337. {
  338. int id;
  339. if (nDevs == 0) {
  340. strcpy(io_buffer, message(MSG_GPUNON, 0));
  341. return;
  342. }
  343. if (*params == '\0') {
  344. strcpy(io_buffer, message(MSG_MISID, 0));
  345. return;
  346. }
  347. id = atoi(params);
  348. if (id < 0 || id >= nDevs) {
  349. strcpy(io_buffer, message(MSG_INVGPU, id));
  350. return;
  351. }
  352. strcpy(io_buffer, message(MSG_GPUDEV, id));
  353. gpustatus(id);
  354. }
  355. void cpudev(SOCKETTYPE c, char *params)
  356. {
  357. int id;
  358. if (opt_n_threads == 0) {
  359. strcpy(io_buffer, message(MSG_CPUNON, 0));
  360. return;
  361. }
  362. if (*params == '\0') {
  363. strcpy(io_buffer, message(MSG_MISID, 0));
  364. return;
  365. }
  366. id = atoi(params);
  367. if (id < 0 || id >= num_processors) {
  368. strcpy(io_buffer, message(MSG_INVCPU, id));
  369. return;
  370. }
  371. strcpy(io_buffer, message(MSG_CPUDEV, id));
  372. cpustatus(id);
  373. }
  374. void poolstatus(SOCKETTYPE c, char *params)
  375. {
  376. char buf[BUFSIZ];
  377. char *status, *lp;
  378. int i;
  379. if (total_pools == 0) {
  380. strcpy(io_buffer, message(MSG_NOPOOL, 0));
  381. return;
  382. }
  383. strcpy(io_buffer, message(MSG_POOL, 0));
  384. for (i = 0; i < total_pools; i++) {
  385. struct pool *pool = pools[i];
  386. if (!pool->enabled)
  387. status = (char *)DISABLED;
  388. else
  389. {
  390. if (pool->idle)
  391. status = (char *)DEAD;
  392. else
  393. status = (char *)ALIVE;
  394. }
  395. if (pool->hdr_path)
  396. lp = (char *)YES;
  397. else
  398. lp = (char *)NO;
  399. 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",
  400. i, pool->rpc_url, status, pool->prio, lp,
  401. pool->getwork_requested,
  402. pool->accepted, pool->rejected,
  403. pool->discarded_work,
  404. pool->stale_shares,
  405. pool->getfail_occasions,
  406. pool->remotefail_occasions, SEPARATOR);
  407. strcat(io_buffer, buf);
  408. }
  409. }
  410. void summary(SOCKETTYPE c, char *params)
  411. {
  412. double utility, mhs;
  413. char *algo = (char *)(algo_names[opt_algo]);
  414. if (algo == NULL)
  415. algo = "(null)";
  416. utility = total_accepted / ( total_secs ? total_secs : 1 ) * 60;
  417. mhs = total_mhashes_done / total_secs;
  418. sprintf(io_buffer, "%sSUMMARY,Elapsed=%.0f,Algorithm=%s,MHS=%.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",
  419. message(MSG_SUMM, 0),
  420. total_secs, algo, mhs, found_blocks,
  421. total_getworks, total_accepted, total_rejected,
  422. hw_errors, utility, total_discarded, total_stale,
  423. total_go, local_work, total_ro, new_blocks, SEPARATOR);
  424. }
  425. void gpuenable(SOCKETTYPE c, char *params)
  426. {
  427. struct thr_info *thr;
  428. int gpu;
  429. int id;
  430. int i;
  431. if (gpu_threads == 0) {
  432. strcpy(io_buffer, message(MSG_GPUNON, 0));
  433. return;
  434. }
  435. if (*params == '\0') {
  436. strcpy(io_buffer, message(MSG_MISID, 0));
  437. return;
  438. }
  439. id = atoi(params);
  440. if (id < 0 || id >= nDevs) {
  441. strcpy(io_buffer, message(MSG_INVGPU, id));
  442. return;
  443. }
  444. if (gpu_devices[id]) {
  445. strcpy(io_buffer, message(MSG_ALRENA, id));
  446. return;
  447. }
  448. for (i = 0; i < gpu_threads; i++) {
  449. gpu = thr_info[i].cgpu->cpu_gpu;
  450. if (gpu == id) {
  451. thr = &thr_info[i];
  452. if (thr->cgpu->status != LIFE_WELL) {
  453. strcpy(io_buffer, message(MSG_GPUMRE, id));
  454. return;
  455. }
  456. gpu_devices[id] = true;
  457. tq_push(thr->q, &ping);
  458. }
  459. }
  460. strcpy(io_buffer, message(MSG_GPUREN, id));
  461. }
  462. void gpudisable(SOCKETTYPE c, char *params)
  463. {
  464. int id;
  465. if (nDevs == 0) {
  466. strcpy(io_buffer, message(MSG_GPUNON, 0));
  467. return;
  468. }
  469. if (*params == '\0') {
  470. strcpy(io_buffer, message(MSG_MISID, 0));
  471. return;
  472. }
  473. id = atoi(params);
  474. if (id < 0 || id >= nDevs) {
  475. strcpy(io_buffer, message(MSG_INVGPU, id));
  476. return;
  477. }
  478. if (!gpu_devices[id]) {
  479. strcpy(io_buffer, message(MSG_ALRDIS, id));
  480. return;
  481. }
  482. gpu_devices[id] = false;
  483. strcpy(io_buffer, message(MSG_GPUDIS, id));
  484. }
  485. void gpurestart(SOCKETTYPE c, char *params)
  486. {
  487. int id;
  488. if (nDevs == 0) {
  489. strcpy(io_buffer, message(MSG_GPUNON, 0));
  490. return;
  491. }
  492. if (*params == '\0') {
  493. strcpy(io_buffer, message(MSG_MISID, 0));
  494. return;
  495. }
  496. id = atoi(params);
  497. if (id < 0 || id >= nDevs) {
  498. strcpy(io_buffer, message(MSG_INVGPU, id));
  499. return;
  500. }
  501. reinit_device(&gpus[id]);
  502. strcpy(io_buffer, message(MSG_GPUREI, id));
  503. }
  504. void gpucount(SOCKETTYPE c, char *params)
  505. {
  506. char buf[BUFSIZ];
  507. strcpy(io_buffer, message(MSG_NUMGPU, 0));
  508. sprintf(buf, "GPUS,Count=%d|", nDevs);
  509. strcat(io_buffer, buf);
  510. }
  511. void cpucount(SOCKETTYPE c, char *params)
  512. {
  513. char buf[BUFSIZ];
  514. strcpy(io_buffer, message(MSG_NUMCPU, 0));
  515. sprintf(buf, "CPUS,Count=%d|", opt_n_threads > 0 ? num_processors : 0);
  516. strcat(io_buffer, buf);
  517. }
  518. void send_result(SOCKETTYPE c);
  519. void doquit(SOCKETTYPE c, char *params)
  520. {
  521. strcpy(io_buffer, "bye");
  522. send_result(c);
  523. *io_buffer = '\0';
  524. bye = 1;
  525. kill_work();
  526. }
  527. struct CMDS {
  528. char *name;
  529. void (*func)(SOCKETTYPE, char *);
  530. } cmds[] = {
  531. { "version", apiversion },
  532. { "devs", devstatus },
  533. { "pools", poolstatus },
  534. { "summary", summary },
  535. { "gpuenable", gpuenable },
  536. { "gpudisable", gpudisable },
  537. { "gpurestart", gpurestart },
  538. { "gpu", gpudev },
  539. { "cpu", cpudev },
  540. { "gpucount", gpucount },
  541. { "cpucount", cpucount },
  542. { "quit", doquit },
  543. { NULL }
  544. };
  545. void send_result(SOCKETTYPE c)
  546. {
  547. int n;
  548. int len = strlen(io_buffer);
  549. if (opt_debug)
  550. applog(LOG_DEBUG, "DBG: send reply: (%d) '%.10s%s'", len+1, io_buffer, len > 10 ? "..." : "");
  551. // ignore failure - it's closed immediately anyway
  552. n = send(c, io_buffer, len+1, 0);
  553. if (opt_debug) {
  554. if (SOCKETFAIL(n))
  555. applog(LOG_DEBUG, "DBG: send failed: %s", SOCKERRMSG);
  556. else
  557. applog(LOG_DEBUG, "DBG: sent %d", n);
  558. }
  559. }
  560. void tidyup()
  561. {
  562. bye = 1;
  563. if (sock != INVSOCK) {
  564. shutdown(sock, SHUT_RDWR);
  565. CLOSESOCKET(sock);
  566. sock = INVSOCK;
  567. }
  568. if (msg_buffer != NULL) {
  569. free(msg_buffer);
  570. msg_buffer = NULL;
  571. }
  572. if (io_buffer != NULL) {
  573. free(io_buffer);
  574. io_buffer = NULL;
  575. }
  576. }
  577. void api(void)
  578. {
  579. char buf[BUFSIZ];
  580. const char *localaddr = "127.0.0.1";
  581. SOCKETTYPE c;
  582. int n, bound;
  583. char *connectaddr;
  584. char *binderror;
  585. time_t bindstart;
  586. short int port = opt_api_port;
  587. struct sockaddr_in serv;
  588. struct sockaddr_in cli;
  589. socklen_t clisiz;
  590. char *params;
  591. bool addrok;
  592. bool did;
  593. int i;
  594. /* This should be done first to ensure curl has already called WSAStartup() in windows */
  595. sleep(opt_log_interval);
  596. if (!opt_api_listen) {
  597. applog(LOG_WARNING, "API not running%s", UNAVAILABLE);
  598. return;
  599. }
  600. sock = socket(AF_INET, SOCK_STREAM, 0);
  601. if (sock == INVSOCK) {
  602. applog(LOG_ERR, "API1 initialisation failed (%s)%s", SOCKERRMSG, UNAVAILABLE);
  603. return;
  604. }
  605. memset(&serv, 0, sizeof(serv));
  606. serv.sin_family = AF_INET;
  607. if (!opt_api_network) {
  608. serv.sin_addr.s_addr = inet_addr(localaddr);
  609. if (serv.sin_addr.s_addr == INVINETADDR) {
  610. applog(LOG_ERR, "API2 initialisation failed (%s)%s", SOCKERRMSG, UNAVAILABLE);
  611. return;
  612. }
  613. }
  614. serv.sin_port = htons(port);
  615. // try for 1 minute ... in case the old one hasn't completely gone yet
  616. bound = 0;
  617. bindstart = time(NULL);
  618. while (bound == 0) {
  619. if (SOCKETFAIL(bind(sock, (struct sockaddr *)(&serv), sizeof(serv)))) {
  620. binderror = SOCKERRMSG;
  621. if ((time(NULL) - bindstart) > 61)
  622. break;
  623. else {
  624. applog(LOG_WARNING, "API bind to port %d failed - trying again in 15sec", port);
  625. sleep(15);
  626. }
  627. }
  628. else
  629. bound = 1;
  630. }
  631. if (bound == 0) {
  632. applog(LOG_ERR, "API bind to port %d failed (%s)%s", port, binderror, UNAVAILABLE);
  633. return;
  634. }
  635. if (SOCKETFAIL(listen(sock, QUEUE))) {
  636. applog(LOG_ERR, "API3 initialisation failed (%s)%s", SOCKERRMSG, UNAVAILABLE);
  637. CLOSESOCKET(sock);
  638. return;
  639. }
  640. if (opt_api_network)
  641. applog(LOG_WARNING, "API running in UNRESTRICTED access mode");
  642. else
  643. applog(LOG_WARNING, "API running in restricted access mode");
  644. io_buffer = malloc(MYBUFSIZ+1);
  645. msg_buffer = malloc(MYBUFSIZ+1);
  646. while (bye == 0) {
  647. clisiz = sizeof(cli);
  648. if (SOCKETFAIL(c = accept(sock, (struct sockaddr *)(&cli), &clisiz))) {
  649. applog(LOG_ERR, "API failed (%s)%s", SOCKERRMSG, UNAVAILABLE);
  650. goto die;
  651. }
  652. if (opt_api_network)
  653. addrok = true;
  654. else {
  655. connectaddr = inet_ntoa(cli.sin_addr);
  656. addrok = (strcmp(connectaddr, localaddr) == 0);
  657. }
  658. if (opt_debug) {
  659. connectaddr = inet_ntoa(cli.sin_addr);
  660. applog(LOG_DEBUG, "DBG: connection from %s - %s", connectaddr, addrok ? "Accepted" : "Ignored");
  661. }
  662. if (addrok) {
  663. n = recv(c, &buf[0], BUFSIZ-1, 0);
  664. if (SOCKETFAIL(n))
  665. buf[0] = '\0';
  666. else
  667. buf[n] = '\0';
  668. if (opt_debug) {
  669. if (SOCKETFAIL(n))
  670. applog(LOG_DEBUG, "DBG: recv failed: %s", SOCKERRMSG);
  671. else
  672. applog(LOG_DEBUG, "DBG: recv command: (%d) '%s'", n, buf);
  673. }
  674. if (!SOCKETFAIL(n)) {
  675. did = false;
  676. params = strchr(buf, SEPARATOR);
  677. if (params == NULL)
  678. params = (char *)BLANK;
  679. else
  680. *(params++) = '\0';
  681. for (i = 0; cmds[i].name != NULL; i++) {
  682. if (strcmp(buf, cmds[i].name) == 0) {
  683. (cmds[i].func)(c, params);
  684. send_result(c);
  685. did = true;
  686. break;
  687. }
  688. }
  689. if (!did) {
  690. strcpy(io_buffer, message(MSG_INVCMD, 0));
  691. send_result(c);
  692. }
  693. }
  694. }
  695. CLOSESOCKET(c);
  696. }
  697. die:
  698. tidyup();
  699. }