Merge branch '201402_opencl_cleanup' into bfgminer
[bitcoin:bfgminer.git] / api.c
1 /*
2  * Copyright 2011-2013 Andrew Smith
3  * Copyright 2011-2013 Con Kolivas
4  * Copyright 2012-2013 Luke Dashjr
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the Free
8  * Software Foundation; either version 3 of the License, or (at your option)
9  * any later version.  See COPYING for more details.
10  *
11  * Note: the code always includes GPU support even if there are no GPUs
12  *      this simplifies handling multiple other device code being included
13  *      depending on compile options
14  */
15 #define _MEMORY_DEBUG_MASTER 1
16
17 #include "config.h"
18
19 #include <stdio.h>
20 #include <ctype.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <stdbool.h>
24 #include <stdint.h>
25 #include <unistd.h>
26 #include <sys/types.h>
27
28 #include "compat.h"
29 #include "deviceapi.h"
30 #ifdef USE_LIBMICROHTTPD
31 #include "httpsrv.h"
32 #endif
33 #include "miner.h"
34 #include "util.h"
35 #include "driver-cpu.h" /* for algo_names[], TODO: re-factor dependency */
36 #include "driver-opencl.h"
37
38 #define HAVE_AN_FPGA 1
39
40 // Max amount of data to buffer before sending on the socket
41 #define RPC_SOCKBUFSIZ     0x10000
42
43 // BUFSIZ varies on Windows and Linux
44 #define TMPBUFSIZ       8192
45
46 // Number of requests to queue - normally would be small
47 // However lots of PGA's may mean more
48 #define QUEUE   100
49
50 static const char *UNAVAILABLE = " - API will not be available";
51 static const char *MUNAVAILABLE = " - API multicast listener will not be available";
52
53 static const char *BLANK = "";
54 static const char *COMMA = ",";
55 #define COMSTR ","
56 static const char SEPARATOR = '|';
57 #define SEPSTR "|"
58 static const char GPUSEP = ',';
59 #define CMDJOIN '+'
60 #define JOIN_CMD "CMD="
61 #define BETWEEN_JOIN SEPSTR
62
63 static const char *APIVERSION = "3.1";
64 static const char *DEAD = "Dead";
65 static const char *SICK = "Sick";
66 static const char *NOSTART = "NoStart";
67 static const char *INIT = "Initialising";
68 static const char *WAIT = "Waiting";
69 static const char *DISABLED = "Disabled";
70 static const char *ALIVE = "Alive";
71 static const char *REJECTING = "Rejecting";
72 static const char *UNKNOWN = "Unknown";
73 #define _DYNAMIC "D"
74 #ifdef HAVE_OPENCL
75 static const char *DYNAMIC = _DYNAMIC;
76 #endif
77
78 static const char *YES = "Y";
79 static const char *NO = "N";
80 static const char *NULLSTR = "(null)";
81
82 static const char *TRUESTR = "true";
83 static const char *FALSESTR = "false";
84
85 #ifdef USE_SCRYPT
86 static const char *SCRYPTSTR = "scrypt";
87 #endif
88 static const char *SHA256STR = "sha256";
89
90 static const char *OSINFO =
91 #if defined(__linux)
92                         "Linux";
93 #else
94 #if defined(__APPLE__)
95                         "Apple";
96 #else
97 #if defined (__CYGWIN__)
98                         "Cygwin";
99 #elif defined (WIN32)
100                         "Windows";
101 #else
102 #if defined(unix)
103                         "Unix";
104 #else
105                         "Unknown";
106 #endif
107 #endif
108 #endif
109 #endif
110
111 #define _DEVS           "DEVS"
112 #define _POOLS          "POOLS"
113 #define _SUMMARY        "SUMMARY"
114 #define _STATUS         "STATUS"
115 #define _VERSION        "VERSION"
116 #define _MINECONFIG     "CONFIG"
117 #define _GPU            "GPU"
118
119 #ifdef HAVE_AN_FPGA
120 #define _PGA            "PGA"
121 #endif
122
123 #ifdef WANT_CPUMINE
124 #define _CPU            "CPU"
125 #endif
126
127 #define _GPUS           "GPUS"
128 #define _PGAS           "PGAS"
129 #define _CPUS           "CPUS"
130 #define _NOTIFY         "NOTIFY"
131 #define _DEVDETAILS     "DEVDETAILS"
132 #define _BYE            "BYE"
133 #define _RESTART        "RESTART"
134 #define _MINESTATS      "STATS"
135 #define _CHECK          "CHECK"
136 #define _MINECOIN       "COIN"
137 #define _DEBUGSET       "DEBUG"
138 #define _SETCONFIG      "SETCONFIG"
139
140 static const char ISJSON = '{';
141 #define JSON0           "{"
142 #define JSON1           "\""
143 #define JSON2           "\":["
144 #define JSON3           "]"
145 #define JSON4           ",\"id\":1"
146 // If anyone cares, id=0 for truncated output
147 #define JSON4_TRUNCATED ",\"id\":0"
148 #define JSON5           "}"
149
150 #define JSON_START      JSON0
151 #define JSON_DEVS       JSON1 _DEVS JSON2
152 #define JSON_POOLS      JSON1 _POOLS JSON2
153 #define JSON_SUMMARY    JSON1 _SUMMARY JSON2
154 #define JSON_STATUS     JSON1 _STATUS JSON2
155 #define JSON_VERSION    JSON1 _VERSION JSON2
156 #define JSON_MINECONFIG JSON1 _MINECONFIG JSON2
157 #define JSON_GPU        JSON1 _GPU JSON2
158
159 #ifdef HAVE_AN_FPGA
160 #define JSON_PGA        JSON1 _PGA JSON2
161 #endif
162
163 #ifdef WANT_CPUMINE
164 #define JSON_CPU        JSON1 _CPU JSON2
165 #endif
166
167 #define JSON_GPUS       JSON1 _GPUS JSON2
168 #define JSON_PGAS       JSON1 _PGAS JSON2
169 #define JSON_CPUS       JSON1 _CPUS JSON2
170 #define JSON_NOTIFY     JSON1 _NOTIFY JSON2
171 #define JSON_DEVDETAILS JSON1 _DEVDETAILS JSON2
172 #define JSON_BYE        JSON1 _BYE JSON1
173 #define JSON_RESTART    JSON1 _RESTART JSON1
174 #define JSON_CLOSE      JSON3
175 #define JSON_MINESTATS  JSON1 _MINESTATS JSON2
176 #define JSON_CHECK      JSON1 _CHECK JSON2
177 #define JSON_MINECOIN   JSON1 _MINECOIN JSON2
178 #define JSON_DEBUGSET   JSON1 _DEBUGSET JSON2
179 #define JSON_SETCONFIG  JSON1 _SETCONFIG JSON2
180 #define JSON_END        JSON4 JSON5
181 #define JSON_END_TRUNCATED      JSON4_TRUNCATED JSON5
182 #define JSON_BETWEEN_JOIN       ","
183
184 static const char *JSON_COMMAND = "command";
185 static const char *JSON_PARAMETER = "parameter";
186
187 #define MSG_INVGPU 1
188 #define MSG_ALRENA 2
189 #define MSG_ALRDIS 3
190 #define MSG_GPUMRE 4
191 #define MSG_GPUREN 5
192 #define MSG_GPUNON 6
193 #define MSG_POOL 7
194 #define MSG_NOPOOL 8
195 #define MSG_DEVS 9
196 #define MSG_NODEVS 10
197 #define MSG_SUMM 11
198 #define MSG_GPUDIS 12
199 #define MSG_GPUREI 13
200 #define MSG_INVCMD 14
201 #define MSG_MISID 15
202 #define MSG_GPUDEV 17
203
204 #ifdef WANT_CPUMINE
205 #define MSG_CPUNON 16
206 #define MSG_CPUDEV 18
207 #define MSG_INVCPU 19
208 #define MSG_ALRENAC 98
209 #define MSG_ALRDISC 99
210 #define MSG_CPUMRE 100
211 #define MSG_CPUREN 101
212 #define MSG_CPUDIS 102
213 #define MSG_CPUREI 103
214 #endif
215
216 #define MSG_NUMGPU 20
217 #define MSG_NUMCPU 21
218 #define MSG_VERSION 22
219 #define MSG_INVJSON 23
220 #define MSG_MISCMD 24
221 #define MSG_MISPID 25
222 #define MSG_INVPID 26
223 #define MSG_SWITCHP 27
224 #define MSG_MISVAL 28
225 #define MSG_NOADL 29
226 #define MSG_NOGPUADL 30
227 #define MSG_INVINT 31
228 #define MSG_GPUINT 32
229 #define MSG_MINECONFIG 33
230 #define MSG_GPUMERR 34
231 #define MSG_GPUMEM 35
232 #define MSG_GPUEERR 36
233 #define MSG_GPUENG 37
234 #define MSG_GPUVERR 38
235 #define MSG_GPUVDDC 39
236 #define MSG_GPUFERR 40
237 #define MSG_GPUFAN 41
238 #define MSG_MISFN 42
239 #define MSG_BADFN 43
240 #define MSG_SAVED 44
241 #define MSG_ACCDENY 45
242 #define MSG_ACCOK 46
243 #define MSG_ENAPOOL 47
244 #define MSG_DISPOOL 48
245 #define MSG_ALRENAP 49
246 #define MSG_ALRDISP 50
247 #define MSG_DISLASTP 51
248 #define MSG_MISPDP 52
249 #define MSG_INVPDP 53
250 #define MSG_TOOMANYP 54
251 #define MSG_ADDPOOL 55
252
253 #ifdef HAVE_AN_FPGA
254 #define MSG_PGANON 56
255 #define MSG_PGADEV 57
256 #define MSG_INVPGA 58
257 #endif
258
259 #define MSG_NUMPGA 59
260 #define MSG_NOTIFY 60
261
262 #ifdef HAVE_AN_FPGA
263 #define MSG_PGALRENA 61
264 #define MSG_PGALRDIS 62
265 #define MSG_PGAENA 63
266 #define MSG_PGADIS 64
267 #define MSG_PGAREI 0x101
268 #define MSG_PGAUNW 65
269 #endif
270
271 #define MSG_REMLASTP 66
272 #define MSG_ACTPOOL 67
273 #define MSG_REMPOOL 68
274 #define MSG_DEVDETAILS 69
275 #define MSG_MINESTATS 70
276 #define MSG_MISCHK 71
277 #define MSG_CHECK 72
278 #define MSG_POOLPRIO 73
279 #define MSG_DUPPID 74
280 #define MSG_MISBOOL 75
281 #define MSG_INVBOOL 76
282 #define MSG_FOO 77
283 #define MSG_MINECOIN 78
284 #define MSG_DEBUGSET 79
285 #define MSG_PGAIDENT 80
286 #define MSG_PGANOID 81
287
288 #define MSG_SETCONFIG 82
289 #define MSG_UNKCON 83
290 #define MSG_INVNUM 84
291 #define MSG_CONPAR 85
292 #define MSG_CONVAL 86
293
294 #ifdef HAVE_AN_FPGA
295 #define MSG_MISPGAOPT 89
296 #define MSG_PGANOSET 90
297 #define MSG_PGAHELP 91
298 #define MSG_PGASETOK 92
299 #define MSG_PGASETERR 93
300 #endif
301
302 #define MSG_ZERMIS 94
303 #define MSG_ZERINV 95
304 #define MSG_ZERSUM 96
305 #define MSG_ZERNOSUM 97
306
307 #define MSG_DEVSCAN 0x100
308
309 #define MSG_INVNEG 121
310 #define MSG_SETQUOTA 122
311
312 #define USE_ALTMSG 0x4000
313
314 enum code_severity {
315         SEVERITY_ERR,
316         SEVERITY_WARN,
317         SEVERITY_INFO,
318         SEVERITY_SUCC,
319         SEVERITY_FAIL
320 };
321
322 enum code_parameters {
323         PARAM_COUNT,
324         PARAM_GPU,
325         PARAM_PGA,
326         PARAM_CPU,
327         PARAM_PID,
328         PARAM_GPUMAX,
329         PARAM_PGAMAX,
330         PARAM_CPUMAX,
331         PARAM_PMAX,
332         PARAM_POOLMAX,
333
334 // Single generic case: have the code resolve it - see below
335         PARAM_DMAX,
336
337         PARAM_CMD,
338         PARAM_POOL,
339         PARAM_STR,
340         PARAM_BOTH,
341         PARAM_BOOL,
342         PARAM_SET,
343         PARAM_NONE
344 };
345
346 struct CODES {
347         const enum code_severity severity;
348         const int code;
349         const enum code_parameters params;
350         const char *description;
351 } codes[] = {
352 #ifdef HAVE_OPENCL
353  { SEVERITY_ERR,   MSG_INVGPU,  PARAM_GPUMAX,   "Invalid GPU id %d - range is 0 - %d" },
354  { SEVERITY_INFO,  MSG_ALRENA,  PARAM_GPU,      "GPU %d already enabled" },
355  { SEVERITY_INFO,  MSG_ALRDIS,  PARAM_GPU,      "GPU %d already disabled" },
356  { SEVERITY_WARN,  MSG_GPUMRE,  PARAM_GPU,      "GPU %d must be restarted first" },
357  { SEVERITY_INFO,  MSG_GPUREN,  PARAM_GPU,      "GPU %d sent enable message" },
358 #endif
359  { SEVERITY_ERR,   MSG_GPUNON,  PARAM_NONE,     "No GPUs" },
360  { SEVERITY_SUCC,  MSG_POOL,    PARAM_PMAX,     "%d Pool(s)" },
361  { SEVERITY_ERR,   MSG_NOPOOL,  PARAM_NONE,     "No pools" },
362
363  { SEVERITY_SUCC,  MSG_DEVS,    PARAM_DMAX,
364                                                 "%d PGA(s)"
365  },
366
367  { SEVERITY_ERR,   MSG_NODEVS,  PARAM_NONE,     "No PGAs"
368  },
369
370  { SEVERITY_SUCC,  MSG_SUMM,    PARAM_NONE,     "Summary" },
371 #ifdef HAVE_OPENCL
372  { SEVERITY_INFO,  MSG_GPUDIS,  PARAM_GPU,      "GPU %d set disable flag" },
373  { SEVERITY_INFO,  MSG_GPUREI,  PARAM_GPU,      "GPU %d restart attempted" },
374 #endif
375  { SEVERITY_ERR,   MSG_INVCMD,  PARAM_NONE,     "Invalid command" },
376  { SEVERITY_ERR,   MSG_MISID,   PARAM_NONE,     "Missing device id parameter" },
377 #ifdef HAVE_OPENCL
378  { SEVERITY_SUCC,  MSG_GPUDEV,  PARAM_GPU,      "GPU%d" },
379 #endif
380 #ifdef HAVE_AN_FPGA
381  { SEVERITY_ERR,   MSG_PGANON,  PARAM_NONE,     "No PGAs" },
382  { SEVERITY_SUCC,  MSG_PGADEV,  PARAM_PGA,      "PGA%d" },
383  { SEVERITY_ERR,   MSG_INVPGA,  PARAM_PGAMAX,   "Invalid PGA id %d - range is 0 - %d" },
384  { SEVERITY_INFO,  MSG_PGALRENA,PARAM_PGA,      "PGA %d already enabled" },
385  { SEVERITY_INFO,  MSG_PGALRDIS,PARAM_PGA,      "PGA %d already disabled" },
386  { SEVERITY_INFO,  MSG_PGAENA,  PARAM_PGA,      "PGA %d sent enable message" },
387  { SEVERITY_INFO,  MSG_PGADIS,  PARAM_PGA,      "PGA %d set disable flag" },
388  { SEVERITY_ERR,   MSG_PGAUNW,  PARAM_PGA,      "PGA %d is not flagged WELL, cannot enable" },
389 #endif
390 #ifdef WANT_CPUMINE
391  { SEVERITY_ERR,   MSG_CPUNON,  PARAM_NONE,     "No CPUs" },
392  { SEVERITY_SUCC,  MSG_CPUDEV,  PARAM_CPU,      "CPU%d" },
393  { SEVERITY_ERR,   MSG_INVCPU,  PARAM_CPUMAX,   "Invalid CPU id %d - range is 0 - %d" },
394  { SEVERITY_INFO,  MSG_ALRENAC, PARAM_CPU,      "CPU %d already enabled" },
395  { SEVERITY_INFO,  MSG_ALRDISC, PARAM_CPU,      "CPU %d already disabled" },
396  { SEVERITY_WARN,  MSG_CPUMRE,  PARAM_CPU,      "CPU %d must be restarted first" },
397  { SEVERITY_INFO,  MSG_CPUREN,  PARAM_CPU,      "CPU %d sent enable message" },
398  { SEVERITY_INFO,  MSG_CPUDIS,  PARAM_CPU,      "CPU %d set disable flag" },
399  { SEVERITY_INFO,  MSG_CPUREI,  PARAM_CPU,      "CPU %d restart attempted" },
400 #endif
401  { SEVERITY_SUCC,  MSG_NUMGPU,  PARAM_NONE,     "GPU count" },
402  { SEVERITY_SUCC,  MSG_NUMPGA,  PARAM_NONE,     "PGA count" },
403  { SEVERITY_SUCC,  MSG_NUMCPU,  PARAM_NONE,     "CPU count" },
404  { SEVERITY_SUCC,  MSG_VERSION, PARAM_NONE,     "BFGMiner versions" },
405  { SEVERITY_ERR,   MSG_INVJSON, PARAM_NONE,     "Invalid JSON" },
406  { SEVERITY_ERR,   MSG_MISCMD,  PARAM_CMD,      "Missing JSON '%s'" },
407  { SEVERITY_ERR,   MSG_MISPID,  PARAM_NONE,     "Missing pool id parameter" },
408  { SEVERITY_ERR,   MSG_INVPID,  PARAM_POOLMAX,  "Invalid pool id %d - range is 0 - %d" },
409  { SEVERITY_SUCC,  MSG_SWITCHP, PARAM_POOL,     "Switching to pool %d:'%s'" },
410  { SEVERITY_ERR,   MSG_MISVAL,  PARAM_NONE,     "Missing comma after GPU number" },
411  { SEVERITY_ERR,   MSG_NOADL,   PARAM_NONE,     "ADL is not available" },
412  { SEVERITY_ERR,   MSG_NOGPUADL,PARAM_GPU,      "GPU %d does not have ADL" },
413  { SEVERITY_ERR,   MSG_INVINT,  PARAM_STR,      "Invalid intensity (%s) - must be '" _DYNAMIC  "' or range " MIN_SHA_INTENSITY_STR " - " MAX_SCRYPT_INTENSITY_STR },
414  { SEVERITY_INFO,  MSG_GPUINT,  PARAM_BOTH,     "GPU %d set new intensity to %s" },
415  { SEVERITY_SUCC,  MSG_MINECONFIG,PARAM_NONE,   "BFGMiner config" },
416 #ifdef HAVE_OPENCL
417  { SEVERITY_ERR,   MSG_GPUMERR, PARAM_BOTH,     "Setting GPU %d memoryclock to (%s) reported failure" },
418  { SEVERITY_SUCC,  MSG_GPUMEM,  PARAM_BOTH,     "Setting GPU %d memoryclock to (%s) reported success" },
419  { SEVERITY_ERR,   MSG_GPUEERR, PARAM_BOTH,     "Setting GPU %d clock to (%s) reported failure" },
420  { SEVERITY_SUCC,  MSG_GPUENG,  PARAM_BOTH,     "Setting GPU %d clock to (%s) reported success" },
421  { SEVERITY_ERR,   MSG_GPUVERR, PARAM_BOTH,     "Setting GPU %d vddc to (%s) reported failure" },
422  { SEVERITY_SUCC,  MSG_GPUVDDC, PARAM_BOTH,     "Setting GPU %d vddc to (%s) reported success" },
423  { SEVERITY_ERR,   MSG_GPUFERR, PARAM_BOTH,     "Setting GPU %d fan to (%s) reported failure" },
424  { SEVERITY_SUCC,  MSG_GPUFAN,  PARAM_BOTH,     "Setting GPU %d fan to (%s) reported success" },
425 #endif
426  { SEVERITY_ERR,   MSG_MISFN,   PARAM_NONE,     "Missing save filename parameter" },
427  { SEVERITY_ERR,   MSG_BADFN,   PARAM_STR,      "Can't open or create save file '%s'" },
428  { SEVERITY_SUCC,  MSG_SAVED,   PARAM_STR,      "Configuration saved to file '%s'" },
429  { SEVERITY_ERR,   MSG_ACCDENY, PARAM_STR,      "Access denied to '%s' command" },
430  { SEVERITY_SUCC,  MSG_ACCOK,   PARAM_NONE,     "Privileged access OK" },
431  { SEVERITY_SUCC,  MSG_ENAPOOL, PARAM_POOL,     "Enabling pool %d:'%s'" },
432  { SEVERITY_SUCC,  MSG_POOLPRIO,PARAM_NONE,     "Changed pool priorities" },
433  { SEVERITY_ERR,   MSG_DUPPID,  PARAM_PID,      "Duplicate pool specified %d" },
434  { SEVERITY_SUCC,  MSG_DISPOOL, PARAM_POOL,     "Disabling pool %d:'%s'" },
435  { SEVERITY_INFO,  MSG_ALRENAP, PARAM_POOL,     "Pool %d:'%s' already enabled" },
436  { SEVERITY_INFO,  MSG_ALRDISP, PARAM_POOL,     "Pool %d:'%s' already disabled" },
437  { SEVERITY_ERR,   MSG_DISLASTP,PARAM_POOL,     "Cannot disable last active pool %d:'%s'" },
438  { SEVERITY_ERR,   MSG_MISPDP,  PARAM_NONE,     "Missing addpool details" },
439  { SEVERITY_ERR,   MSG_INVPDP,  PARAM_STR,      "Invalid addpool details '%s'" },
440  { SEVERITY_ERR,   MSG_TOOMANYP,PARAM_NONE,     "Reached maximum number of pools (%d)" },
441  { SEVERITY_SUCC,  MSG_ADDPOOL, PARAM_STR,      "Added pool '%s'" },
442  { SEVERITY_ERR,   MSG_REMLASTP,PARAM_POOL,     "Cannot remove last pool %d:'%s'" },
443  { SEVERITY_ERR,   MSG_ACTPOOL, PARAM_POOL,     "Cannot remove active pool %d:'%s'" },
444  { SEVERITY_SUCC,  MSG_REMPOOL, PARAM_BOTH,     "Removed pool %d:'%s'" },
445  { SEVERITY_SUCC,  MSG_NOTIFY,  PARAM_NONE,     "Notify" },
446  { SEVERITY_SUCC,  MSG_DEVDETAILS,PARAM_NONE,   "Device Details" },
447  { SEVERITY_SUCC,  MSG_MINESTATS,PARAM_NONE,    "BFGMiner stats" },
448  { SEVERITY_ERR,   MSG_MISCHK,  PARAM_NONE,     "Missing check cmd" },
449  { SEVERITY_SUCC,  MSG_CHECK,   PARAM_NONE,     "Check command" },
450  { SEVERITY_ERR,   MSG_MISBOOL, PARAM_NONE,     "Missing parameter: true/false" },
451  { SEVERITY_ERR,   MSG_INVBOOL, PARAM_NONE,     "Invalid parameter should be true or false" },
452  { SEVERITY_SUCC,  MSG_FOO,     PARAM_BOOL,     "Failover-Only set to %s" },
453  { SEVERITY_SUCC,  MSG_MINECOIN,PARAM_NONE,     "BFGMiner coin" },
454  { SEVERITY_SUCC,  MSG_DEBUGSET,PARAM_NONE,     "Debug settings" },
455 #ifdef HAVE_AN_FPGA
456  { SEVERITY_SUCC,  MSG_PGAIDENT,PARAM_PGA,      "Identify command sent to PGA%d" },
457  { SEVERITY_WARN,  MSG_PGANOID, PARAM_PGA,      "PGA%d does not support identify" },
458 #endif
459  { SEVERITY_SUCC,  MSG_SETCONFIG,PARAM_SET,     "Set config '%s' to %d" },
460  { SEVERITY_ERR,   MSG_UNKCON,  PARAM_STR,      "Unknown config '%s'" },
461  { SEVERITY_ERR,   MSG_INVNUM,  PARAM_BOTH,     "Invalid number (%d) for '%s' range is 0-9999" },
462  { SEVERITY_ERR,   MSG_INVNEG,  PARAM_BOTH,     "Invalid negative number (%d) for '%s'" },
463  { SEVERITY_SUCC,  MSG_SETQUOTA,PARAM_SET,      "Set pool '%s' to quota %d'" },
464  { SEVERITY_ERR,   MSG_CONPAR,  PARAM_NONE,     "Missing config parameters 'name,N'" },
465  { SEVERITY_ERR,   MSG_CONVAL,  PARAM_STR,      "Missing config value N for '%s,N'" },
466 #ifdef HAVE_AN_FPGA
467  { SEVERITY_ERR,   MSG_MISPGAOPT, PARAM_NONE,   "Missing option after PGA number" },
468  { SEVERITY_WARN,  MSG_PGANOSET, PARAM_PGA,     "PGA %d does not support pgaset" },
469  { SEVERITY_INFO,  MSG_PGAHELP, PARAM_BOTH,     "PGA %d set help: %s" },
470  { SEVERITY_SUCC,  MSG_PGASETOK, PARAM_PGA,     "PGA %d set OK" },
471  { SEVERITY_SUCC,  MSG_PGASETOK | USE_ALTMSG, PARAM_BOTH,       "PGA %d set OK: %s" },
472  { SEVERITY_ERR,   MSG_PGASETERR, PARAM_BOTH,   "PGA %d set failed: %s" },
473 #endif
474  { SEVERITY_ERR,   MSG_ZERMIS,  PARAM_NONE,     "Missing zero parameters" },
475  { SEVERITY_ERR,   MSG_ZERINV,  PARAM_STR,      "Invalid zero parameter '%s'" },
476  { SEVERITY_SUCC,  MSG_ZERSUM,  PARAM_STR,      "Zeroed %s stats with summary" },
477  { SEVERITY_SUCC,  MSG_ZERNOSUM, PARAM_STR,     "Zeroed %s stats without summary" },
478  { SEVERITY_SUCC,  MSG_DEVSCAN, PARAM_COUNT,    "Added %d new device(s)" },
479  { SEVERITY_FAIL, 0, 0, NULL }
480 };
481
482 static const char *localaddr = "127.0.0.1";
483
484 static int my_thr_id = 0;
485 static bool bye;
486
487 // Used to control quit restart access to shutdown variables
488 static pthread_mutex_t quit_restart_lock;
489
490 static bool do_a_quit;
491 static bool do_a_restart;
492
493 static time_t when = 0; // when the request occurred
494 static bool per_proc;
495
496 struct IP4ACCESS {
497         in_addr_t ip;
498         in_addr_t mask;
499         char group;
500 };
501
502 #define GROUP(g) (toupper(g))
503 #define PRIVGROUP GROUP('W')
504 #define NOPRIVGROUP GROUP('R')
505 #define ISPRIVGROUP(g) (GROUP(g) == PRIVGROUP)
506 #define GROUPOFFSET(g) (GROUP(g) - GROUP('A'))
507 #define VALIDGROUP(g) (GROUP(g) >= GROUP('A') && GROUP(g) <= GROUP('Z'))
508 #define COMMANDS(g) (apigroups[GROUPOFFSET(g)].commands)
509 #define DEFINEDGROUP(g) (ISPRIVGROUP(g) || COMMANDS(g) != NULL)
510
511 struct APIGROUPS {
512         // This becomes a string like: "|cmd1|cmd2|cmd3|" so it's quick to search
513         char *commands;
514 } apigroups['Z' - 'A' + 1]; // only A=0 to Z=25 (R: noprivs, W: allprivs)
515
516 static struct IP4ACCESS *ipaccess = NULL;
517 static int ips = 0;
518
519 struct io_data {
520         bytes_t data;
521         SOCKETTYPE sock;
522         
523         // Whether to add various things
524         bool close;
525 };
526 static struct io_data *rpc_io_data;
527
528 static void io_reinit(struct io_data *io_data)
529 {
530         bytes_reset(&io_data->data);
531         io_data->close = false;
532 }
533
534 static
535 struct io_data *sock_io_new()
536 {
537         struct io_data *io_data = malloc(sizeof(struct io_data));
538         bytes_init(&io_data->data);
539         io_data->sock = INVSOCK;
540         io_reinit(io_data);
541         return io_data;
542 }
543
544 static
545 size_t io_flush(struct io_data *io_data, bool complete)
546 {
547         size_t sent = 0, tosend = bytes_len(&io_data->data);
548         ssize_t n;
549         struct timeval timeout = {0, complete ? 50000: 0}, tv;
550         fd_set wd;
551         int count = 0;
552         
553         while (tosend)
554         {
555                 FD_ZERO(&wd);
556                 FD_SET(io_data->sock, &wd);
557                 tv = timeout;
558                 if (select(io_data->sock + 1, NULL, &wd, NULL, &tv) < 1)
559                         break;
560                 
561                 n = send(io_data->sock, (void*)&bytes_buf(&io_data->data)[sent], tosend, 0);
562                 if (SOCKETFAIL(n))
563                 {
564                         if (!sock_blocks())
565                                 applog(LOG_WARNING, "API: send (%lu) failed: %s", (unsigned long)tosend, SOCKERRMSG);
566                         break;
567                 }
568                 if (count <= 1)
569                 {
570                         if (n == tosend)
571                                 applog(LOG_DEBUG, "API: sent all of %lu first go", (unsigned long)tosend);
572                         else
573                                 applog(LOG_DEBUG, "API: sent %ld of %lu first go", (long)n, (unsigned long)tosend);
574                 }
575                 else
576                 {
577                         if (n == tosend)
578                                 applog(LOG_DEBUG, "API: sent all of remaining %lu (count=%d)", (unsigned long)tosend, count);
579                         else
580                                 applog(LOG_DEBUG, "API: sent %ld of remaining %lu (count=%d)", (long)n, (unsigned long)tosend, count);
581                 }
582                 sent += n;
583                 tosend -= n;
584         }
585         
586         bytes_shift(&io_data->data, sent);
587         
588         return sent;
589 }
590
591 static bool io_add(struct io_data *io_data, char *buf)
592 {
593         size_t len = strlen(buf);
594         if (bytes_len(&io_data->data) + len > RPC_SOCKBUFSIZ)
595                 io_flush(io_data, false);
596         bytes_append(&io_data->data, buf, len);
597         return true;
598 }
599
600 static bool io_put(struct io_data *io_data, char *buf)
601 {
602         bytes_reset(&io_data->data);
603         return io_add(io_data, buf);
604 }
605
606 static void io_close(struct io_data *io_data)
607 {
608         io_data->close = true;
609 }
610
611 static void io_free()
612 {
613         bytes_free(&rpc_io_data->data);
614         free(rpc_io_data);
615         rpc_io_data = NULL;
616 }
617
618 // This is only called when expected to be needed (rarely)
619 // i.e. strings outside of the codes control (input from the user)
620 static char *escape_string(char *str, bool isjson)
621 {
622         char *buf, *ptr;
623         int count;
624
625         count = 0;
626         for (ptr = str; *ptr; ptr++) {
627                 switch (*ptr) {
628                         case ',':
629                         case '|':
630                         case '=':
631                                 if (!isjson)
632                                         count++;
633                                 break;
634                         case '"':
635                                 if (isjson)
636                                         count++;
637                                 break;
638                         case '\\':
639                                 count++;
640                                 break;
641                 }
642         }
643
644         if (count == 0)
645                 return str;
646
647         buf = malloc(strlen(str) + count + 1);
648         if (unlikely(!buf))
649                 quit(1, "Failed to malloc escape buf");
650
651         ptr = buf;
652         while (*str)
653                 switch (*str) {
654                         case ',':
655                         case '|':
656                         case '=':
657                                 if (!isjson)
658                                         *(ptr++) = '\\';
659                                 *(ptr++) = *(str++);
660                                 break;
661                         case '"':
662                                 if (isjson)
663                                         *(ptr++) = '\\';
664                                 *(ptr++) = *(str++);
665                                 break;
666                         case '\\':
667                                 *(ptr++) = '\\';
668                                 *(ptr++) = *(str++);
669                                 break;
670                         default:
671                                 *(ptr++) = *(str++);
672                                 break;
673                 }
674
675         *ptr = '\0';
676
677         return buf;
678 }
679
680 static struct api_data *api_add_extra(struct api_data *root, struct api_data *extra)
681 {
682         struct api_data *tmp;
683
684         if (root) {
685                 if (extra) {
686                         // extra tail
687                         tmp = extra->prev;
688
689                         // extra prev = root tail
690                         extra->prev = root->prev;
691
692                         // root tail next = extra
693                         root->prev->next = extra;
694
695                         // extra tail next = root
696                         tmp->next = root;
697
698                         // root prev = extra tail
699                         root->prev = tmp;
700                 }
701         } else
702                 root = extra;
703
704         return root;
705 }
706
707 static struct api_data *api_add_data_full(struct api_data *root, char *name, enum api_data_type type, void *data, bool copy_data)
708 {
709         struct api_data *api_data;
710
711         api_data = (struct api_data *)malloc(sizeof(struct api_data));
712
713         api_data->name = strdup(name);
714         api_data->type = type;
715
716         if (root == NULL) {
717                 root = api_data;
718                 root->prev = root;
719                 root->next = root;
720         }
721         else {
722                 api_data->prev = root->prev;
723                 root->prev = api_data;
724                 api_data->next = root;
725                 api_data->prev->next = api_data;
726         }
727
728         api_data->data_was_malloc = copy_data;
729
730         // Avoid crashing on bad data
731         if (data == NULL) {
732                 api_data->type = type = API_CONST;
733                 data = (void *)NULLSTR;
734                 api_data->data_was_malloc = copy_data = false;
735         }
736
737         if (!copy_data)
738         {
739                 api_data->data = data;
740                 if (type == API_JSON)
741                         json_incref((json_t *)data);
742         }
743         else
744                 switch(type) {
745                         case API_ESCAPE:
746                         case API_STRING:
747                         case API_CONST:
748                                 api_data->data = (void *)malloc(strlen((char *)data) + 1);
749                                 strcpy((char*)(api_data->data), (char *)data);
750                                 break;
751                         case API_UINT8:
752                                 /* Most OSs won't really alloc less than 4 */
753                                 api_data->data = malloc(4);
754                                 *(uint8_t *)api_data->data = *(uint8_t *)data;
755                                 break;
756                         case API_UINT16:
757                                 /* Most OSs won't really alloc less than 4 */
758                                 api_data->data = malloc(4);
759                                 *(uint16_t *)api_data->data = *(uint16_t *)data;
760                                 break;
761                         case API_INT:
762                                 api_data->data = (void *)malloc(sizeof(int));
763                                 *((int *)(api_data->data)) = *((int *)data);
764                                 break;
765                         case API_UINT:
766                                 api_data->data = (void *)malloc(sizeof(unsigned int));
767                                 *((unsigned int *)(api_data->data)) = *((unsigned int *)data);
768                                 break;
769                         case API_UINT32:
770                                 api_data->data = (void *)malloc(sizeof(uint32_t));
771                                 *((uint32_t *)(api_data->data)) = *((uint32_t *)data);
772                                 break;
773                         case API_UINT64:
774                                 api_data->data = (void *)malloc(sizeof(uint64_t));
775                                 *((uint64_t *)(api_data->data)) = *((uint64_t *)data);
776                                 break;
777                         case API_DOUBLE:
778                         case API_ELAPSED:
779                         case API_MHS:
780                         case API_MHTOTAL:
781                         case API_UTILITY:
782                         case API_FREQ:
783                         case API_HS:
784                         case API_DIFF:
785                         case API_PERCENT:
786                                 api_data->data = (void *)malloc(sizeof(double));
787                                 *((double *)(api_data->data)) = *((double *)data);
788                                 break;
789                         case API_BOOL:
790                                 api_data->data = (void *)malloc(sizeof(bool));
791                                 *((bool *)(api_data->data)) = *((bool *)data);
792                                 break;
793                         case API_TIMEVAL:
794                                 api_data->data = (void *)malloc(sizeof(struct timeval));
795                                 memcpy(api_data->data, data, sizeof(struct timeval));
796                                 break;
797                         case API_TIME:
798                                 api_data->data = (void *)malloc(sizeof(time_t));
799                                 *(time_t *)(api_data->data) = *((time_t *)data);
800                                 break;
801                         case API_VOLTS:
802                         case API_TEMP:
803                                 api_data->data = (void *)malloc(sizeof(float));
804                                 *((float *)(api_data->data)) = *((float *)data);
805                                 break;
806                         case API_JSON:
807                                 api_data->data_was_malloc = false;
808                                 api_data->data = (void *)json_deep_copy((json_t *)data);
809                                 break;
810                         default:
811                                 applog(LOG_ERR, "API: unknown1 data type %d ignored", type);
812                                 api_data->type = API_STRING;
813                                 api_data->data_was_malloc = false;
814                                 api_data->data = (void *)UNKNOWN;
815                                 break;
816                 }
817
818         return root;
819 }
820
821 struct api_data *api_add_escape(struct api_data *root, char *name, char *data, bool copy_data)
822 {
823         return api_add_data_full(root, name, API_ESCAPE, (void *)data, copy_data);
824 }
825
826 struct api_data *api_add_string(struct api_data *root, char *name, const char *data, bool copy_data)
827 {
828         return api_add_data_full(root, name, API_STRING, (void *)data, copy_data);
829 }
830
831 struct api_data *api_add_const(struct api_data *root, char *name, const char *data, bool copy_data)
832 {
833         return api_add_data_full(root, name, API_CONST, (void *)data, copy_data);
834 }
835
836 struct api_data *api_add_uint8(struct api_data *root, char *name, uint8_t *data, bool copy_data)
837 {
838         return api_add_data_full(root, name, API_UINT8, (void *)data, copy_data);
839 }
840
841 struct api_data *api_add_uint16(struct api_data *root, char *name, uint16_t *data, bool copy_data)
842 {
843         return api_add_data_full(root, name, API_UINT16, (void *)data, copy_data);
844 }
845
846 struct api_data *api_add_int(struct api_data *root, char *name, int *data, bool copy_data)
847 {
848         return api_add_data_full(root, name, API_INT, (void *)data, copy_data);
849 }
850
851 struct api_data *api_add_uint(struct api_data *root, char *name, unsigned int *data, bool copy_data)
852 {
853         return api_add_data_full(root, name, API_UINT, (void *)data, copy_data);
854 }
855
856 struct api_data *api_add_uint32(struct api_data *root, char *name, uint32_t *data, bool copy_data)
857 {
858         return api_add_data_full(root, name, API_UINT32, (void *)data, copy_data);
859 }
860
861 struct api_data *api_add_uint64(struct api_data *root, char *name, uint64_t *data, bool copy_data)
862 {
863         return api_add_data_full(root, name, API_UINT64, (void *)data, copy_data);
864 }
865
866 struct api_data *api_add_double(struct api_data *root, char *name, double *data, bool copy_data)
867 {
868         return api_add_data_full(root, name, API_DOUBLE, (void *)data, copy_data);
869 }
870
871 struct api_data *api_add_elapsed(struct api_data *root, char *name, double *data, bool copy_data)
872 {
873         return api_add_data_full(root, name, API_ELAPSED, (void *)data, copy_data);
874 }
875
876 struct api_data *api_add_bool(struct api_data *root, char *name, bool *data, bool copy_data)
877 {
878         return api_add_data_full(root, name, API_BOOL, (void *)data, copy_data);
879 }
880
881 struct api_data *api_add_timeval(struct api_data *root, char *name, struct timeval *data, bool copy_data)
882 {
883         return api_add_data_full(root, name, API_TIMEVAL, (void *)data, copy_data);
884 }
885
886 struct api_data *api_add_time(struct api_data *root, char *name, time_t *data, bool copy_data)
887 {
888         return api_add_data_full(root, name, API_TIME, (void *)data, copy_data);
889 }
890
891 struct api_data *api_add_mhs(struct api_data *root, char *name, double *data, bool copy_data)
892 {
893         return api_add_data_full(root, name, API_MHS, (void *)data, copy_data);
894 }
895
896 struct api_data *api_add_mhtotal(struct api_data *root, char *name, double *data, bool copy_data)
897 {
898         return api_add_data_full(root, name, API_MHTOTAL, (void *)data, copy_data);
899 }
900
901 struct api_data *api_add_temp(struct api_data *root, char *name, float *data, bool copy_data)
902 {
903         return api_add_data_full(root, name, API_TEMP, (void *)data, copy_data);
904 }
905
906 struct api_data *api_add_utility(struct api_data *root, char *name, double *data, bool copy_data)
907 {
908         return api_add_data_full(root, name, API_UTILITY, (void *)data, copy_data);
909 }
910
911 struct api_data *api_add_freq(struct api_data *root, char *name, double *data, bool copy_data)
912 {
913         return api_add_data_full(root, name, API_FREQ, (void *)data, copy_data);
914 }
915
916 struct api_data *api_add_volts(struct api_data *root, char *name, float *data, bool copy_data)
917 {
918         return api_add_data_full(root, name, API_VOLTS, (void *)data, copy_data);
919 }
920
921 struct api_data *api_add_hs(struct api_data *root, char *name, double *data, bool copy_data)
922 {
923         return api_add_data_full(root, name, API_HS, (void *)data, copy_data);
924 }
925
926 struct api_data *api_add_diff(struct api_data *root, char *name, double *data, bool copy_data)
927 {
928         return api_add_data_full(root, name, API_DIFF, (void *)data, copy_data);
929 }
930
931 struct api_data *api_add_json(struct api_data *root, char *name, json_t *data, bool copy_data)
932 {
933         return api_add_data_full(root, name, API_JSON, (void *)data, copy_data);
934 }
935
936 struct api_data *api_add_percent(struct api_data *root, char *name, double *data, bool copy_data)
937 {
938         return api_add_data_full(root, name, API_PERCENT, (void *)data, copy_data);
939 }
940
941 static struct api_data *print_data(struct api_data *root, char *buf, bool isjson, bool precom)
942 {
943         struct api_data *tmp;
944         bool first = true;
945         char *original, *escape;
946         char *quote;
947
948         *buf = '\0';
949
950         if (precom) {
951                 *(buf++) = *COMMA;
952                 *buf = '\0';
953         }
954
955         if (isjson) {
956                 strcpy(buf, JSON0);
957                 buf = strchr(buf, '\0');
958                 quote = JSON1;
959         } else
960                 quote = (char *)BLANK;
961
962         while (root) {
963                 if (!first)
964                         *(buf++) = *COMMA;
965                 else
966                         first = false;
967
968                 sprintf(buf, "%s%s%s%s", quote, root->name, quote, isjson ? ":" : "=");
969
970                 buf = strchr(buf, '\0');
971
972                 switch(root->type) {
973                         case API_STRING:
974                         case API_CONST:
975                                 sprintf(buf, "%s%s%s", quote, (char *)(root->data), quote);
976                                 break;
977                         case API_ESCAPE:
978                                 original = (char *)(root->data);
979                                 escape = escape_string((char *)(root->data), isjson);
980                                 sprintf(buf, "%s%s%s", quote, escape, quote);
981                                 if (escape != original)
982                                         free(escape);
983                                 break;
984                         case API_UINT8:
985                                 sprintf(buf, "%u", *(uint8_t *)root->data);
986                                 break;
987                         case API_UINT16:
988                                 sprintf(buf, "%u", *(uint16_t *)root->data);
989                                 break;
990                         case API_INT:
991                                 sprintf(buf, "%d", *((int *)(root->data)));
992                                 break;
993                         case API_UINT:
994                                 sprintf(buf, "%u", *((unsigned int *)(root->data)));
995                                 break;
996                         case API_UINT32:
997                                 sprintf(buf, "%"PRIu32, *((uint32_t *)(root->data)));
998                                 break;
999                         case API_UINT64:
1000                                 sprintf(buf, "%"PRIu64, *((uint64_t *)(root->data)));
1001                                 break;
1002                         case API_TIME:
1003                                 sprintf(buf, "%lu", *((unsigned long *)(root->data)));
1004                                 break;
1005                         case API_DOUBLE:
1006                                 sprintf(buf, "%f", *((double *)(root->data)));
1007                                 break;
1008                         case API_ELAPSED:
1009                                 sprintf(buf, "%.0f", *((double *)(root->data)));
1010                                 break;
1011                         case API_UTILITY:
1012                         case API_FREQ:
1013                         case API_MHS:
1014                                 sprintf(buf, "%.3f", *((double *)(root->data)));
1015                                 break;
1016                         case API_VOLTS:
1017                                 sprintf(buf, "%.3f", *((float *)(root->data)));
1018                                 break;
1019                         case API_MHTOTAL:
1020                                 sprintf(buf, "%.4f", *((double *)(root->data)));
1021                                 break;
1022                         case API_HS:
1023                                 sprintf(buf, "%.15f", *((double *)(root->data)));
1024                                 break;
1025                         case API_DIFF:
1026                                 sprintf(buf, "%.8f", *((double *)(root->data)));
1027                                 break;
1028                         case API_BOOL:
1029                                 sprintf(buf, "%s", *((bool *)(root->data)) ? TRUESTR : FALSESTR);
1030                                 break;
1031                         case API_TIMEVAL:
1032                                 sprintf(buf, "%"PRIu64".%06lu",
1033                                         (uint64_t)((struct timeval *)(root->data))->tv_sec,
1034                                         (unsigned long)((struct timeval *)(root->data))->tv_usec);
1035                                 break;
1036                         case API_TEMP:
1037                                 sprintf(buf, "%.2f", *((float *)(root->data)));
1038                                 break;
1039                         case API_JSON:
1040                                 escape = json_dumps((json_t *)(root->data), JSON_COMPACT);
1041                                 strcpy(buf, escape);
1042                                 free(escape);
1043                                 break;
1044                         case API_PERCENT:
1045                                 sprintf(buf, "%.4f", *((double *)(root->data)) * 100.0);
1046                                 break;
1047                         default:
1048                                 applog(LOG_ERR, "API: unknown2 data type %d ignored", root->type);
1049                                 sprintf(buf, "%s%s%s", quote, UNKNOWN, quote);
1050                                 break;
1051                 }
1052
1053                 buf = strchr(buf, '\0');
1054
1055                 free(root->name);
1056                 if (root->type == API_JSON)
1057                         json_decref((json_t *)root->data);
1058                 if (root->data_was_malloc)
1059                         free(root->data);
1060
1061                 if (root->next == root) {
1062                         free(root);
1063                         root = NULL;
1064                 } else {
1065                         tmp = root;
1066                         root = tmp->next;
1067                         root->prev = tmp->prev;
1068                         root->prev->next = root;
1069                         free(tmp);
1070                 }
1071         }
1072
1073         strcpy(buf, isjson ? JSON5 : SEPSTR);
1074
1075         return root;
1076 }
1077
1078 #ifdef HAVE_AN_FPGA
1079 static int numpgas()
1080 {
1081         int count = 0;
1082         int i;
1083
1084         rd_lock(&devices_lock);
1085         for (i = 0; i < total_devices; i++) {
1086                 if (devices[i]->device != devices[i] && !per_proc)
1087                         continue;
1088                 ++count;
1089         }
1090         rd_unlock(&devices_lock);
1091         return count;
1092 }
1093
1094 static int pgadevice(int pgaid)
1095 {
1096         int count = 0;
1097         int i;
1098
1099         rd_lock(&devices_lock);
1100         for (i = 0; i < total_devices; i++) {
1101                 if (devices[i]->device != devices[i] && !per_proc)
1102                         continue;
1103                 ++count;
1104                 if (count == (pgaid + 1))
1105                         goto foundit;
1106         }
1107
1108         rd_unlock(&devices_lock);
1109         return -1;
1110
1111 foundit:
1112
1113         rd_unlock(&devices_lock);
1114         return i;
1115 }
1116 #endif
1117
1118 // All replies (except BYE and RESTART) start with a message
1119 //  thus for JSON, message() inserts JSON_START at the front
1120 //  and send_result() adds JSON_END at the end
1121 static void message(struct io_data * const io_data, const int messageid2, const int paramid, const char * const param2, const bool isjson)
1122 {
1123         struct api_data *root = NULL;
1124         char buf[TMPBUFSIZ];
1125         char buf2[TMPBUFSIZ];
1126         char severity[2];
1127 #ifdef HAVE_AN_FPGA
1128         int pga;
1129 #endif
1130 #ifdef WANT_CPUMINE
1131         int cpu;
1132 #endif
1133         int i;
1134         int messageid = messageid2 & ~USE_ALTMSG;
1135
1136         if (isjson)
1137                 io_add(io_data, JSON_START JSON_STATUS);
1138
1139         for (i = 0; codes[i].severity != SEVERITY_FAIL; i++) {
1140                 if (codes[i].code == messageid2) {
1141                         switch (codes[i].severity) {
1142                                 case SEVERITY_WARN:
1143                                         severity[0] = 'W';
1144                                         break;
1145                                 case SEVERITY_INFO:
1146                                         severity[0] = 'I';
1147                                         break;
1148                                 case SEVERITY_SUCC:
1149                                         severity[0] = 'S';
1150                                         break;
1151                                 case SEVERITY_ERR:
1152                                 default:
1153                                         severity[0] = 'E';
1154                                         break;
1155                         }
1156                         severity[1] = '\0';
1157
1158                         switch(codes[i].params) {
1159                                 case PARAM_COUNT:
1160                                 case PARAM_GPU:
1161                                 case PARAM_PGA:
1162                                 case PARAM_CPU:
1163                                 case PARAM_PID:
1164                                         sprintf(buf, codes[i].description, paramid);
1165                                         break;
1166                                 case PARAM_POOL:
1167                                         sprintf(buf, codes[i].description, paramid, pools[paramid]->rpc_url);
1168                                         break;
1169 #ifdef HAVE_OPENCL
1170                                 case PARAM_GPUMAX:
1171                                         sprintf(buf, codes[i].description, paramid, nDevs - 1);
1172                                         break;
1173 #endif
1174 #ifdef HAVE_AN_FPGA
1175                                 case PARAM_PGAMAX:
1176                                         pga = numpgas();
1177                                         sprintf(buf, codes[i].description, paramid, pga - 1);
1178                                         break;
1179 #endif
1180 #ifdef WANT_CPUMINE
1181                                 case PARAM_CPUMAX:
1182                                         if (opt_n_threads > 0)
1183                                                 cpu = num_processors;
1184                                         else
1185                                                 cpu = 0;
1186                                         sprintf(buf, codes[i].description, paramid, cpu - 1);
1187                                         break;
1188 #endif
1189                                 case PARAM_PMAX:
1190                                         sprintf(buf, codes[i].description, total_pools);
1191                                         break;
1192                                 case PARAM_POOLMAX:
1193                                         sprintf(buf, codes[i].description, paramid, total_pools - 1);
1194                                         break;
1195                                 case PARAM_DMAX:
1196                                         pga = numpgas();
1197
1198                                         sprintf(buf, codes[i].description
1199                                                 , pga
1200                                                 );
1201                                         break;
1202                                 case PARAM_CMD:
1203                                         sprintf(buf, codes[i].description, JSON_COMMAND);
1204                                         break;
1205                                 case PARAM_STR:
1206                                         sprintf(buf, codes[i].description, param2);
1207                                         break;
1208                                 case PARAM_BOTH:
1209                                         sprintf(buf, codes[i].description, paramid, param2);
1210                                         break;
1211                                 case PARAM_BOOL:
1212                                         sprintf(buf, codes[i].description, paramid ? TRUESTR : FALSESTR);
1213                                         break;
1214                                 case PARAM_SET:
1215                                         sprintf(buf, codes[i].description, param2, paramid);
1216                                         break;
1217                                 case PARAM_NONE:
1218                                 default:
1219                                         strcpy(buf, codes[i].description);
1220                         }
1221
1222                         root = api_add_string(root, _STATUS, severity, false);
1223                         root = api_add_time(root, "When", &when, false);
1224                         root = api_add_int(root, "Code", &messageid, false);
1225                         root = api_add_escape(root, "Msg", buf, false);
1226                         root = api_add_escape(root, "Description", opt_api_description, false);
1227
1228                         root = print_data(root, buf2, isjson, false);
1229                         io_add(io_data, buf2);
1230                         if (isjson)
1231                                 io_add(io_data, JSON_CLOSE);
1232                         return;
1233                 }
1234         }
1235
1236         root = api_add_string(root, _STATUS, "F", false);
1237         root = api_add_time(root, "When", &when, false);
1238         int id = -1;
1239         root = api_add_int(root, "Code", &id, false);
1240         sprintf(buf, "%d", messageid);
1241         root = api_add_escape(root, "Msg", buf, false);
1242         root = api_add_escape(root, "Description", opt_api_description, false);
1243
1244         root = print_data(root, buf2, isjson, false);
1245         io_add(io_data, buf2);
1246         if (isjson)
1247                 io_add(io_data, JSON_CLOSE);
1248 }
1249
1250 static void apiversion(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
1251 {
1252         struct api_data *root = NULL;
1253         char buf[TMPBUFSIZ];
1254         bool io_open;
1255
1256         message(io_data, MSG_VERSION, 0, NULL, isjson);
1257         io_open = io_add(io_data, isjson ? COMSTR JSON_VERSION : _VERSION COMSTR);
1258
1259         root = api_add_string(root, "CGMiner", VERSION, false);
1260         root = api_add_const(root, "API", APIVERSION, false);
1261
1262         root = print_data(root, buf, isjson, false);
1263         io_add(io_data, buf);
1264         if (isjson && io_open)
1265                 io_close(io_data);
1266 }
1267
1268 static void minerconfig(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
1269 {
1270         struct api_data *root = NULL;
1271         char buf[TMPBUFSIZ];
1272         bool io_open;
1273         struct driver_registration *reg, *regtmp;
1274         int pgacount = 0;
1275         char *adlinuse = (char *)NO;
1276 #ifdef HAVE_ADL
1277         const char *adl = YES;
1278         int i;
1279
1280         for (i = 0; i < nDevs; i++) {
1281                 struct opencl_device_data * const data = gpus[i].device_data;
1282                 if (data->has_adl) {
1283                         adlinuse = (char *)YES;
1284                         break;
1285                 }
1286         }
1287 #else
1288         const char *adl = NO;
1289 #endif
1290
1291 #ifdef HAVE_AN_FPGA
1292         pgacount = numpgas();
1293 #endif
1294
1295         message(io_data, MSG_MINECONFIG, 0, NULL, isjson);
1296         io_open = io_add(io_data, isjson ? COMSTR JSON_MINECONFIG : _MINECONFIG COMSTR);
1297
1298         root = api_add_int(root, "PGA Count", &pgacount, false);
1299         root = api_add_int(root, "Pool Count", &total_pools, false);
1300         root = api_add_const(root, "ADL", (char *)adl, false);
1301         root = api_add_string(root, "ADL in use", adlinuse, false);
1302         root = api_add_const(root, "Strategy", strategies[pool_strategy].s, false);
1303         root = api_add_int(root, "Log Interval", &opt_log_interval, false);
1304         
1305         strcpy(buf, ""
1306 #ifdef USE_LIBMICROHTTPD
1307                         " SGW"
1308 #endif
1309 #ifdef USE_LIBEVENT
1310                         " SSM"
1311 #endif
1312         );
1313
1314         BFG_FOREACH_DRIVER_BY_DNAME(reg, regtmp)
1315         {
1316                 const struct device_drv * const drv = reg->drv;
1317                 tailsprintf(buf, sizeof(buf), " %s", drv->name);
1318         }
1319         root = api_add_const(root, "Device Code", &buf[1], true);
1320         
1321         root = api_add_const(root, "OS", OSINFO, false);
1322         root = api_add_bool(root, "Failover-Only", &opt_fail_only, false);
1323         root = api_add_int(root, "ScanTime", &opt_scantime, false);
1324         root = api_add_int(root, "Queue", &opt_queue, false);
1325         root = api_add_int(root, "Expiry", &opt_expiry, false);
1326 #if BLKMAKER_VERSION > 0
1327         root = api_add_string(root, "Coinbase-Sig", opt_coinbase_sig, true);
1328 #endif
1329
1330         root = print_data(root, buf, isjson, false);
1331         io_add(io_data, buf);
1332         if (isjson && io_open)
1333                 io_close(io_data);
1334 }
1335
1336 static const char*
1337 bool2str(bool b)
1338 {
1339         return b ? YES : NO;
1340 }
1341
1342 static const char *status2str(enum alive status)
1343 {
1344         switch (status) {
1345                 case LIFE_WELL:
1346                         return ALIVE;
1347                 case LIFE_SICK:
1348                         return SICK;
1349                 case LIFE_DEAD:
1350                 case LIFE_DEAD2:
1351                         return DEAD;
1352                 case LIFE_NOSTART:
1353                         return NOSTART;
1354                 case LIFE_INIT:
1355                 case LIFE_INIT2:
1356                         return INIT;
1357                 case LIFE_WAIT:
1358                         return WAIT;
1359                 case LIFE_MIXED:
1360                         return "Mixed";
1361                 default:
1362                         return UNKNOWN;
1363         }
1364 }
1365
1366 static
1367 struct api_data *api_add_device_identifier(struct api_data *root, struct cgpu_info *cgpu)
1368 {
1369         root = api_add_string(root, "Name", cgpu->drv->name, false);
1370         root = api_add_int(root, "ID", &(cgpu->device_id), false);
1371         if (per_proc)
1372                 root = api_add_int(root, "ProcID", &(cgpu->proc_id), false);
1373         return root;
1374 }
1375
1376 static
1377 int find_index_by_cgpu(struct cgpu_info *cgpu)
1378 {
1379         if (per_proc)
1380                 return cgpu->cgminer_id;
1381         
1382         int n = 0, i;
1383         
1384         // Quickly traverse the devices array backward until we reach the 0th device, counting as we go
1385         rd_lock(&devices_lock);
1386         while (true)
1387         {
1388                 i = cgpu->device->cgminer_id;
1389                 if (!i)
1390                         break;
1391                 cgpu = devices[--i];
1392                 ++n;
1393         }
1394         rd_unlock(&devices_lock);
1395         return n;
1396 }
1397
1398 static void devdetail_an(struct io_data *io_data, struct cgpu_info *cgpu, bool isjson, bool precom)
1399 {
1400         struct api_data *root = NULL;
1401         char buf[TMPBUFSIZ];
1402         int n;
1403
1404         cgpu_utility(cgpu);
1405
1406         n = find_index_by_cgpu(cgpu);
1407
1408         root = api_add_int(root, "DEVDETAILS", &n, true);
1409         root = api_add_device_identifier(root, cgpu);
1410         if (!per_proc)
1411                 root = api_add_int(root, "Processors", &cgpu->procs, false);
1412         root = api_add_string(root, "Driver", cgpu->drv->dname, false);
1413         if (cgpu->kname)
1414                 root = api_add_string(root, "Kernel", cgpu->kname, false);
1415         if (cgpu->name)
1416                 root = api_add_string(root, "Model", cgpu->name, false);
1417         if (cgpu->dev_manufacturer)
1418                 root = api_add_string(root, "Manufacturer", cgpu->dev_manufacturer, false);
1419         if (cgpu->dev_product)
1420                 root = api_add_string(root, "Product", cgpu->dev_product, false);
1421         if (cgpu->dev_serial)
1422                 root = api_add_string(root, "Serial", cgpu->dev_serial, false);
1423         if (cgpu->device_path)
1424                 root = api_add_string(root, "Device Path", cgpu->device_path, false);
1425         
1426         root = api_add_int(root, "Target Temperature", &cgpu->targettemp, false);
1427         root = api_add_int(root, "Cutoff Temperature", &cgpu->cutofftemp, false);
1428
1429         if (cgpu->drv->get_api_extra_device_detail)
1430                 root = api_add_extra(root, cgpu->drv->get_api_extra_device_detail(cgpu));
1431
1432         root = print_data(root, buf, isjson, precom);
1433         io_add(io_data, buf);
1434 }
1435
1436 static
1437 void devstatus_an(struct io_data *io_data, struct cgpu_info *cgpu, bool isjson, bool precom)
1438 {
1439         struct cgpu_info *proc;
1440         struct api_data *root = NULL;
1441         char buf[TMPBUFSIZ];
1442         int n;
1443
1444         n = find_index_by_cgpu(cgpu);
1445
1446         double runtime = cgpu_runtime(cgpu);
1447         bool enabled = false;
1448         double total_mhashes = 0, rolling = 0, utility = 0;
1449         enum alive status = cgpu->status;
1450         float temp = -1;
1451         int accepted = 0, rejected = 0, stale = 0, hw_errors = 0;
1452         double diff1 = 0, bad_diff1 = 0;
1453         double diff_accepted = 0, diff_rejected = 0, diff_stale = 0;
1454         int last_share_pool = -1;
1455         time_t last_share_pool_time = -1, last_device_valid_work = -1;
1456         double last_share_diff = -1;
1457         int procs = per_proc ? 1 : cgpu->procs, i;
1458         for (i = 0, proc = cgpu; i < procs; ++i, proc = proc->next_proc)
1459         {
1460                 cgpu_utility(proc);
1461                 if (proc->deven != DEV_DISABLED)
1462                         enabled = true;
1463                 total_mhashes += proc->total_mhashes;
1464                 rolling += proc->rolling;
1465                 utility += proc->utility;
1466                 accepted += proc->accepted;
1467                 rejected += proc->rejected;
1468                 stale += proc->stale;
1469                 hw_errors += proc->hw_errors;
1470                 diff1 += proc->diff1;
1471                 diff_accepted += proc->diff_accepted;
1472                 diff_rejected += proc->diff_rejected;
1473                 diff_stale += proc->diff_stale;
1474                 bad_diff1 += proc->bad_diff1;
1475                 if (status != proc->status)
1476                         status = LIFE_MIXED;
1477                 if (proc->temp > temp)
1478                         temp = proc->temp;
1479                 if (proc->last_share_pool_time > last_share_pool_time)
1480                 {
1481                         last_share_pool_time = proc->last_share_pool_time;
1482                         last_share_pool = proc->last_share_pool;
1483                         last_share_diff = proc->last_share_diff;
1484                 }
1485                 if (proc->last_device_valid_work > last_device_valid_work)
1486                         last_device_valid_work = proc->last_device_valid_work;
1487                 if (per_proc)
1488                         break;
1489         }
1490
1491         root = api_add_int(root, "PGA", &n, true);
1492         root = api_add_device_identifier(root, cgpu);
1493         root = api_add_string(root, "Enabled", bool2str(enabled), false);
1494         root = api_add_string(root, "Status", status2str(status), false);
1495         if (temp > 0)
1496                 root = api_add_temp(root, "Temperature", &temp, false);
1497         
1498         root = api_add_elapsed(root, "Device Elapsed", &runtime, false);
1499         double mhs = total_mhashes / runtime;
1500         root = api_add_mhs(root, "MHS av", &mhs, false);
1501         char mhsname[27];
1502         sprintf(mhsname, "MHS %ds", opt_log_interval);
1503         root = api_add_mhs(root, mhsname, &rolling, false);
1504         root = api_add_mhs(root, "MHS rolling", &rolling, false);
1505         root = api_add_int(root, "Accepted", &accepted, false);
1506         root = api_add_int(root, "Rejected", &rejected, false);
1507         root = api_add_int(root, "Hardware Errors", &hw_errors, false);
1508         root = api_add_utility(root, "Utility", &utility, false);
1509         root = api_add_int(root, "Stale", &stale, false);
1510         if (last_share_pool != -1)
1511         {
1512                 root = api_add_int(root, "Last Share Pool", &last_share_pool, false);
1513                 root = api_add_time(root, "Last Share Time", &last_share_pool_time, false);
1514         }
1515         root = api_add_mhtotal(root, "Total MH", &total_mhashes, false);
1516         double work_utility = diff1 / runtime * 60;
1517         root = api_add_diff(root, "Diff1 Work", &diff1, false);
1518         root = api_add_utility(root, "Work Utility", &work_utility, false);
1519         root = api_add_diff(root, "Difficulty Accepted", &diff_accepted, false);
1520         root = api_add_diff(root, "Difficulty Rejected", &diff_rejected, false);
1521         root = api_add_diff(root, "Difficulty Stale", &diff_stale, false);
1522         if (last_share_diff > 0)
1523                 root = api_add_diff(root, "Last Share Difficulty", &last_share_diff, false);
1524         if (last_device_valid_work != -1)
1525                 root = api_add_time(root, "Last Valid Work", &last_device_valid_work, false);
1526         double hwp = (bad_diff1 + diff1) ?
1527                         (double)(bad_diff1) / (double)(bad_diff1 + diff1) : 0;
1528         root = api_add_percent(root, "Device Hardware%", &hwp, false);
1529         double rejp = diff1 ?
1530                         (double)(diff_rejected) / (double)(diff1) : 0;
1531         root = api_add_percent(root, "Device Rejected%", &rejp, false);
1532
1533         if ((per_proc || cgpu->procs <= 1) && cgpu->drv->get_api_extra_device_status)
1534                 root = api_add_extra(root, cgpu->drv->get_api_extra_device_status(cgpu));
1535
1536         root = print_data(root, buf, isjson, precom);
1537         io_add(io_data, buf);
1538 }
1539
1540 #ifdef HAVE_OPENCL
1541 static void gpustatus(struct io_data *io_data, int gpu, bool isjson, bool precom)
1542 {
1543         if (gpu < 0 || gpu >= nDevs)
1544                 return;
1545         devstatus_an(io_data, &gpus[gpu], isjson, precom);
1546 }
1547 #endif
1548
1549 #ifdef HAVE_AN_FPGA
1550 static void pgastatus(struct io_data *io_data, int pga, bool isjson, bool precom)
1551 {
1552         int dev = pgadevice(pga);
1553         if (dev < 0) // Should never happen
1554                 return;
1555         devstatus_an(io_data, get_devices(dev), isjson, precom);
1556 }
1557 #endif
1558
1559 #ifdef WANT_CPUMINE
1560 static void cpustatus(struct io_data *io_data, int cpu, bool isjson, bool precom)
1561 {
1562         if (opt_n_threads <= 0 || cpu < 0 || cpu >= num_processors)
1563                 return;
1564         devstatus_an(io_data, &cpus[cpu], isjson, precom);
1565 }
1566 #endif
1567
1568 static void
1569 devinfo_internal(void (*func)(struct io_data *, struct cgpu_info*, bool, bool), int msg, struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
1570 {
1571         struct cgpu_info *cgpu;
1572         bool io_open = false;
1573         int i;
1574
1575         if (total_devices == 0) {
1576                 message(io_data, MSG_NODEVS, 0, NULL, isjson);
1577                 return;
1578         }
1579
1580
1581         message(io_data, msg, 0, NULL, isjson);
1582         if (isjson)
1583                 io_open = io_add(io_data, COMSTR JSON_DEVS);
1584
1585         for (i = 0; i < total_devices; ++i) {
1586                 cgpu = get_devices(i);
1587                 if (per_proc || cgpu->device == cgpu)
1588                         func(io_data, cgpu, isjson, isjson && i > 0);
1589         }
1590
1591         if (isjson && io_open)
1592                 io_close(io_data);
1593 }
1594
1595 static void devdetail(struct io_data *io_data, SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
1596 {
1597         return devinfo_internal(devdetail_an, MSG_DEVDETAILS, io_data, c, param, isjson, group);
1598 }
1599
1600 static void devstatus(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
1601 {
1602         return devinfo_internal(devstatus_an, MSG_DEVS, io_data, c, param, isjson, group);
1603 }
1604
1605 #ifdef HAVE_OPENCL
1606 static void gpudev(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
1607 {
1608         bool io_open = false;
1609         int id;
1610
1611         if (nDevs == 0) {
1612                 message(io_data, MSG_GPUNON, 0, NULL, isjson);
1613                 return;
1614         }
1615
1616         if (param == NULL || *param == '\0') {
1617                 message(io_data, MSG_MISID, 0, NULL, isjson);
1618                 return;
1619         }
1620
1621         id = atoi(param);
1622         if (id < 0 || id >= nDevs) {
1623                 message(io_data, MSG_INVGPU, id, NULL, isjson);
1624                 return;
1625         }
1626
1627         message(io_data, MSG_GPUDEV, id, NULL, isjson);
1628
1629         if (isjson)
1630                 io_open = io_add(io_data, COMSTR JSON_GPU);
1631
1632         gpustatus(io_data, id, isjson, false);
1633
1634         if (isjson && io_open)
1635                 io_close(io_data);
1636 }
1637 #endif
1638
1639 static void devscan(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
1640 {
1641         int n;
1642         bool io_open = false;
1643         
1644         applog(LOG_DEBUG, "RPC: request to scan %s for devices",
1645                param);
1646         
1647         if (param && !param[0])
1648                 param = NULL;
1649         
1650         n = scan_serial(param);
1651         
1652         message(io_data, MSG_DEVSCAN, n, NULL, isjson);
1653         
1654         io_open = io_add(io_data, isjson ? COMSTR JSON_DEVS : _DEVS COMSTR);
1655
1656         n = total_devices - n;
1657         for (int i = n; i < total_devices; ++i)
1658                 devdetail_an(io_data, get_devices(i), isjson, i > n);
1659         
1660         if (isjson && io_open)
1661                 io_close(io_data);
1662 }
1663
1664 #ifdef HAVE_AN_FPGA
1665 static
1666 struct cgpu_info *get_pga_cgpu(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group, int *id_p, int *dev_p)
1667 {
1668         int numpga = numpgas();
1669         
1670         if (numpga == 0) {
1671                 message(io_data, MSG_PGANON, 0, NULL, isjson);
1672                 return NULL;
1673         }
1674         
1675         if (param == NULL || *param == '\0') {
1676                 message(io_data, MSG_MISID, 0, NULL, isjson);
1677                 return NULL;
1678         }
1679         
1680         *id_p = atoi(param);
1681         if (*id_p < 0 || *id_p >= numpga) {
1682                 message(io_data, MSG_INVPGA, *id_p, NULL, isjson);
1683                 return NULL;
1684         }
1685         
1686         *dev_p = pgadevice(*id_p);
1687         if (*dev_p < 0) { // Should never happen
1688                 message(io_data, MSG_INVPGA, *id_p, NULL, isjson);
1689                 return NULL;
1690         }
1691         
1692         return get_devices(*dev_p);
1693 }
1694
1695 static void pgadev(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
1696 {
1697         bool io_open = false;
1698         int id, dev;
1699
1700         if (!get_pga_cgpu(io_data, c, param, isjson, group, &id, &dev))
1701                 return;
1702         
1703         message(io_data, MSG_PGADEV, id, NULL, isjson);
1704
1705         if (isjson)
1706                 io_open = io_add(io_data, COMSTR JSON_PGA);
1707
1708         pgastatus(io_data, id, isjson, false);
1709
1710         if (isjson && io_open)
1711                 io_close(io_data);
1712 }
1713
1714 static void pgaenable(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
1715 {
1716         struct cgpu_info *cgpu, *proc;
1717         int id, dev;
1718         bool already;
1719
1720         cgpu = get_pga_cgpu(io_data, c, param, isjson, group, &id, &dev);
1721         if (!cgpu)
1722                 return;
1723         
1724         applog(LOG_DEBUG, "API: request to pgaenable %s id %d device %d %s",
1725                         per_proc ? "proc" : "dev", id, dev, cgpu->proc_repr_ns);
1726
1727         already = true;
1728         int procs = per_proc ? 1 : cgpu->procs, i;
1729         for (i = 0, proc = cgpu; i < procs; ++i, proc = proc->next_proc)
1730         {
1731                 if (proc->deven == DEV_DISABLED)
1732                 {
1733                         proc_enable(proc);
1734                         already = false;
1735                 }
1736         }
1737         
1738         if (already)
1739         {
1740                 message(io_data, MSG_PGALRENA, id, NULL, isjson);
1741                 return;
1742         }
1743
1744 #if 0 /* A DISABLED device wont change status FIXME: should disabling make it WELL? */
1745         if (cgpu->status != LIFE_WELL) {
1746                 message(io_data, MSG_PGAUNW, id, NULL, isjson);
1747                 return;
1748         }
1749 #endif
1750
1751         message(io_data, MSG_PGAENA, id, NULL, isjson);
1752 }
1753
1754 static void pgadisable(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
1755 {
1756         struct cgpu_info *cgpu, *proc;
1757         int id, dev;
1758         bool already;
1759
1760         cgpu = get_pga_cgpu(io_data, c, param, isjson, group, &id, &dev);
1761         if (!cgpu)
1762                 return;
1763         
1764         applog(LOG_DEBUG, "API: request to pgadisable %s id %d device %d %s",
1765                         per_proc ? "proc" : "dev", id, dev, cgpu->proc_repr_ns);
1766
1767         already = true;
1768         int procs = per_proc ? 1 : cgpu->procs, i;
1769         for (i = 0, proc = cgpu; i < procs; ++i, proc = proc->next_proc)
1770         {
1771                 if (proc->deven != DEV_DISABLED)
1772                 {
1773                         cgpu->deven = DEV_DISABLED;
1774                         already = false;
1775                 }
1776         }
1777         
1778         if (already)
1779         {
1780                 message(io_data, MSG_PGALRDIS, id, NULL, isjson);
1781                 return;
1782         }
1783
1784         message(io_data, MSG_PGADIS, id, NULL, isjson);
1785 }
1786
1787 static void pgarestart(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
1788 {
1789         struct cgpu_info *cgpu;
1790         int id, dev;
1791         
1792         cgpu = get_pga_cgpu(io_data, c, param, isjson, group, &id, &dev);
1793         if (!cgpu)
1794                 return;
1795         
1796         applog(LOG_DEBUG, "API: request to pgarestart dev id %d device %d %s",
1797                         id, dev, cgpu->dev_repr);
1798         
1799         reinit_device(cgpu);
1800         
1801         message(io_data, MSG_PGAREI, id, NULL, isjson);
1802 }
1803
1804 static void pgaidentify(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
1805 {
1806         struct cgpu_info *cgpu;
1807         struct device_drv *drv;
1808         int id, dev;
1809
1810         cgpu = get_pga_cgpu(io_data, c, param, isjson, group, &id, &dev);
1811         if (!cgpu)
1812                 return;
1813         
1814         drv = cgpu->drv;
1815
1816         if (drv->identify_device && drv->identify_device(cgpu))
1817                 message(io_data, MSG_PGAIDENT, id, NULL, isjson);
1818         else
1819                 message(io_data, MSG_PGANOID, id, NULL, isjson);
1820 }
1821 #endif
1822
1823 #ifdef WANT_CPUMINE
1824 static void cpudev(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
1825 {
1826         bool io_open = false;
1827         int id;
1828
1829         if (opt_n_threads == 0) {
1830                 message(io_data, MSG_CPUNON, 0, NULL, isjson);
1831                 return;
1832         }
1833
1834         if (param == NULL || *param == '\0') {
1835                 message(io_data, MSG_MISID, 0, NULL, isjson);
1836                 return;
1837         }
1838
1839         id = atoi(param);
1840         if (id < 0 || id >= num_processors) {
1841                 message(io_data, MSG_INVCPU, id, NULL, isjson);
1842                 return;
1843         }
1844
1845         message(io_data, MSG_CPUDEV, id, NULL, isjson);
1846
1847         if (isjson)
1848                 io_open = io_add(io_data, COMSTR JSON_CPU);
1849
1850         cpustatus(io_data, id, isjson, false);
1851
1852         if (isjson && io_open)
1853                 io_close(io_data);
1854 }
1855 #endif
1856
1857 static void poolstatus(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
1858 {
1859         struct api_data *root = NULL;
1860         char buf[TMPBUFSIZ];
1861         bool io_open = false;
1862         char *status, *lp;
1863         int i;
1864
1865         if (total_pools == 0) {
1866                 message(io_data, MSG_NOPOOL, 0, NULL, isjson);
1867                 return;
1868         }
1869
1870         message(io_data, MSG_POOL, 0, NULL, isjson);
1871
1872         if (isjson)
1873                 io_open = io_add(io_data, COMSTR JSON_POOLS);
1874
1875         for (i = 0; i < total_pools; i++) {
1876                 struct pool *pool = pools[i];
1877
1878                 if (pool->removed)
1879                         continue;
1880
1881                 switch (pool->enabled) {
1882                         case POOL_DISABLED:
1883                                 status = (char *)DISABLED;
1884                                 break;
1885                         case POOL_REJECTING:
1886                                 status = (char *)REJECTING;
1887                                 break;
1888                         case POOL_ENABLED:
1889                                 if (pool->idle)
1890                                         status = (char *)DEAD;
1891                                 else
1892                                         status = (char *)ALIVE;
1893                                 break;
1894                         default:
1895                                 status = (char *)UNKNOWN;
1896                                 break;
1897                 }
1898
1899                 if (pool->hdr_path)
1900                         lp = (char *)YES;
1901                 else
1902                         lp = (char *)NO;
1903
1904                 root = api_add_int(root, "POOL", &i, false);
1905                 root = api_add_escape(root, "URL", pool->rpc_url, false);
1906                 root = api_add_string(root, "Status", status, false);
1907                 root = api_add_int(root, "Priority", &(pool->prio), false);
1908                 root = api_add_int(root, "Quota", &pool->quota, false);
1909                 root = api_add_string(root, "Long Poll", lp, false);
1910                 root = api_add_uint(root, "Getworks", &(pool->getwork_requested), false);
1911                 root = api_add_int(root, "Accepted", &(pool->accepted), false);
1912                 root = api_add_int(root, "Rejected", &(pool->rejected), false);
1913                 root = api_add_int(root, "Works", &pool->works, false);
1914                 root = api_add_uint(root, "Discarded", &(pool->discarded_work), false);
1915                 root = api_add_uint(root, "Stale", &(pool->stale_shares), false);
1916                 root = api_add_uint(root, "Get Failures", &(pool->getfail_occasions), false);
1917                 root = api_add_uint(root, "Remote Failures", &(pool->remotefail_occasions), false);
1918                 root = api_add_escape(root, "User", pool->rpc_user, false);
1919                 root = api_add_time(root, "Last Share Time", &(pool->last_share_time), false);
1920                 root = api_add_diff(root, "Diff1 Shares", &(pool->diff1), false);
1921                 if (pool->rpc_proxy) {
1922                         root = api_add_escape(root, "Proxy", pool->rpc_proxy, false);
1923                 } else {
1924                         root = api_add_const(root, "Proxy", BLANK, false);
1925                 }
1926                 root = api_add_diff(root, "Difficulty Accepted", &(pool->diff_accepted), false);
1927                 root = api_add_diff(root, "Difficulty Rejected", &(pool->diff_rejected), false);
1928                 root = api_add_diff(root, "Difficulty Stale", &(pool->diff_stale), false);
1929                 root = api_add_diff(root, "Last Share Difficulty", &(pool->last_share_diff), false);
1930                 root = api_add_bool(root, "Has Stratum", &(pool->has_stratum), false);
1931                 root = api_add_bool(root, "Stratum Active", &(pool->stratum_active), false);
1932                 if (pool->stratum_active)
1933                         root = api_add_escape(root, "Stratum URL", pool->stratum_url, false);
1934                 else
1935                         root = api_add_const(root, "Stratum URL", BLANK, false);
1936                 root = api_add_uint64(root, "Best Share", &(pool->best_diff), true);
1937                 if (pool->admin_msg)
1938                         root = api_add_escape(root, "Message", pool->admin_msg, true);
1939                 double rejp = (pool->diff_accepted + pool->diff_rejected + pool->diff_stale) ?
1940                                 (double)(pool->diff_rejected) / (double)(pool->diff_accepted + pool->diff_rejected + pool->diff_stale) : 0;
1941                 root = api_add_percent(root, "Pool Rejected%", &rejp, false);
1942                 double stalep = (pool->diff_accepted + pool->diff_rejected + pool->diff_stale) ?
1943                                 (double)(pool->diff_stale) / (double)(pool->diff_accepted + pool->diff_rejected + pool->diff_stale) : 0;
1944                 root = api_add_percent(root, "Pool Stale%", &stalep, false);
1945
1946                 root = print_data(root, buf, isjson, isjson && (i > 0));
1947                 io_add(io_data, buf);
1948         }
1949
1950         if (isjson && io_open)
1951                 io_close(io_data);
1952 }
1953
1954 static void summary(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
1955 {
1956         struct api_data *root = NULL;
1957         char buf[TMPBUFSIZ];
1958         bool io_open;
1959         double utility, mhs, work_utility;
1960
1961 #ifdef WANT_CPUMINE
1962         char *algo = (char *)(algo_names[opt_algo]);
1963         if (algo == NULL)
1964                 algo = (char *)NULLSTR;
1965 #endif
1966
1967         message(io_data, MSG_SUMM, 0, NULL, isjson);
1968         io_open = io_add(io_data, isjson ? COMSTR JSON_SUMMARY : _SUMMARY COMSTR);
1969
1970         // stop hashmeter() changing some while copying
1971         mutex_lock(&hash_lock);
1972
1973         utility = total_accepted / ( total_secs ? total_secs : 1 ) * 60;
1974         mhs = total_mhashes_done / total_secs;
1975         work_utility = total_diff1 / ( total_secs ? total_secs : 1 ) * 60;
1976
1977         root = api_add_elapsed(root, "Elapsed", &(total_secs), true);
1978 #ifdef WANT_CPUMINE
1979         if (opt_n_threads)
1980         root = api_add_string(root, "Algorithm", algo, false);
1981 #endif
1982         root = api_add_mhs(root, "MHS av", &(mhs), false);
1983         char mhsname[27];
1984         sprintf(mhsname, "MHS %ds", opt_log_interval);
1985         root = api_add_mhs(root, mhsname, &(total_rolling), false);
1986         root = api_add_uint(root, "Found Blocks", &(found_blocks), true);
1987         root = api_add_int(root, "Getworks", &(total_getworks), true);
1988         root = api_add_int(root, "Accepted", &(total_accepted), true);
1989         root = api_add_int(root, "Rejected", &(total_rejected), true);
1990         root = api_add_int(root, "Hardware Errors", &(hw_errors), true);
1991         root = api_add_utility(root, "Utility", &(utility), false);
1992         root = api_add_int(root, "Discarded", &(total_discarded), true);
1993         root = api_add_int(root, "Stale", &(total_stale), true);
1994         root = api_add_uint(root, "Get Failures", &(total_go), true);
1995         root = api_add_uint(root, "Local Work", &(local_work), true);
1996         root = api_add_uint(root, "Remote Failures", &(total_ro), true);
1997         root = api_add_uint(root, "Network Blocks", &(new_blocks), true);
1998         root = api_add_mhtotal(root, "Total MH", &(total_mhashes_done), true);
1999         root = api_add_diff(root, "Diff1 Work", &total_diff1, true);
2000         root = api_add_utility(root, "Work Utility", &(work_utility), false);
2001         root = api_add_diff(root, "Difficulty Accepted", &(total_diff_accepted), true);
2002         root = api_add_diff(root, "Difficulty Rejected", &(total_diff_rejected), true);
2003         root = api_add_diff(root, "Difficulty Stale", &(total_diff_stale), true);
2004         root = api_add_uint64(root, "Best Share", &(best_diff), true);
2005         double hwp = (total_bad_diff1 + total_diff1) ?
2006                         (double)(total_bad_diff1) / (double)(total_bad_diff1 + total_diff1) : 0;
2007         root = api_add_percent(root, "Device Hardware%", &hwp, false);
2008         double rejp = total_diff1 ?
2009                         (double)(total_diff_rejected) / (double)(total_diff1) : 0;
2010         root = api_add_percent(root, "Device Rejected%", &rejp, false);
2011         double prejp = (total_diff_accepted + total_diff_rejected + total_diff_stale) ?
2012                         (double)(total_diff_rejected) / (double)(total_diff_accepted + total_diff_rejected + total_diff_stale) : 0;
2013         root = api_add_percent(root, "Pool Rejected%", &prejp, false);
2014         double stalep = (total_diff_accepted + total_diff_rejected + total_diff_stale) ?
2015                         (double)(total_diff_stale) / (double)(total_diff_accepted + total_diff_rejected + total_diff_stale) : 0;
2016         root = api_add_percent(root, "Pool Stale%", &stalep, false);
2017         root = api_add_time(root, "Last getwork", &last_getwork, false);
2018
2019         mutex_unlock(&hash_lock);
2020
2021         root = print_data(root, buf, isjson, false);
2022         io_add(io_data, buf);
2023         if (isjson && io_open)
2024                 io_close(io_data);
2025 }
2026
2027 #ifdef HAVE_OPENCL
2028 static void gpuenable(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
2029 {
2030         int id;
2031
2032         if (!nDevs) {
2033                 message(io_data, MSG_GPUNON, 0, NULL, isjson);
2034                 return;
2035         }
2036
2037         if (param == NULL || *param == '\0') {
2038                 message(io_data, MSG_MISID, 0, NULL, isjson);
2039                 return;
2040         }
2041
2042         id = atoi(param);
2043         if (id < 0 || id >= nDevs) {
2044                 message(io_data, MSG_INVGPU, id, NULL, isjson);
2045                 return;
2046         }
2047
2048         applog(LOG_DEBUG, "API: request to gpuenable gpuid %d %s",
2049                         id, gpus[id].proc_repr_ns);
2050
2051         if (gpus[id].deven != DEV_DISABLED) {
2052                 message(io_data, MSG_ALRENA, id, NULL, isjson);
2053                 return;
2054         }
2055
2056         if (gpus[id].status != LIFE_WELL)
2057         {
2058                 message(io_data, MSG_GPUMRE, id, NULL, isjson);
2059                 return;
2060         }
2061         proc_enable(&gpus[id]);
2062
2063         message(io_data, MSG_GPUREN, id, NULL, isjson);
2064 }
2065
2066 static void gpudisable(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
2067 {
2068         int id;
2069
2070         if (nDevs == 0) {
2071                 message(io_data, MSG_GPUNON, 0, NULL, isjson);
2072                 return;
2073         }
2074
2075         if (param == NULL || *param == '\0') {
2076                 message(io_data, MSG_MISID, 0, NULL, isjson);
2077                 return;
2078         }
2079
2080         id = atoi(param);
2081         if (id < 0 || id >= nDevs) {
2082                 message(io_data, MSG_INVGPU, id, NULL, isjson);
2083                 return;
2084         }
2085
2086         applog(LOG_DEBUG, "API: request to gpudisable gpuid %d %s",
2087                         id, gpus[id].proc_repr_ns);
2088
2089         if (gpus[id].deven == DEV_DISABLED) {
2090                 message(io_data, MSG_ALRDIS, id, NULL, isjson);
2091                 return;
2092         }
2093
2094         gpus[id].deven = DEV_DISABLED;
2095
2096         message(io_data, MSG_GPUDIS, id, NULL, isjson);
2097 }
2098
2099 static void gpurestart(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
2100 {
2101         int id;
2102
2103         if (nDevs == 0) {
2104                 message(io_data, MSG_GPUNON, 0, NULL, isjson);
2105                 return;
2106         }
2107
2108         if (param == NULL || *param == '\0') {
2109                 message(io_data, MSG_MISID, 0, NULL, isjson);
2110                 return;
2111         }
2112
2113         id = atoi(param);
2114         if (id < 0 || id >= nDevs) {
2115                 message(io_data, MSG_INVGPU, id, NULL, isjson);
2116                 return;
2117         }
2118
2119         reinit_device(&gpus[id]);
2120
2121         message(io_data, MSG_GPUREI, id, NULL, isjson);
2122 }
2123 #endif
2124
2125 static void gpucount(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
2126 {
2127         struct api_data *root = NULL;
2128         char buf[TMPBUFSIZ];
2129         bool io_open;
2130         int numgpu = 0;
2131
2132 #ifdef HAVE_OPENCL
2133         numgpu = nDevs;
2134 #endif
2135
2136         message(io_data, MSG_NUMGPU, 0, NULL, isjson);
2137         io_open = io_add(io_data, isjson ? COMSTR JSON_GPUS : _GPUS COMSTR);
2138
2139         root = api_add_int(root, "Count", &numgpu, false);
2140
2141         root = print_data(root, buf, isjson, false);
2142         io_add(io_data, buf);
2143         if (isjson && io_open)
2144                 io_close(io_data);
2145 }
2146
2147 static void pgacount(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
2148 {
2149         struct api_data *root = NULL;
2150         char buf[TMPBUFSIZ];
2151         bool io_open;
2152         int count = 0;
2153
2154 #ifdef HAVE_AN_FPGA
2155         count = numpgas();
2156 #endif
2157
2158         message(io_data, MSG_NUMPGA, 0, NULL, isjson);
2159         io_open = io_add(io_data, isjson ? COMSTR JSON_PGAS : _PGAS COMSTR);
2160
2161         root = api_add_int(root, "Count", &count, false);
2162
2163         root = print_data(root, buf, isjson, false);
2164         io_add(io_data, buf);
2165         if (isjson && io_open)
2166                 io_close(io_data);
2167 }
2168
2169 #ifdef WANT_CPUMINE
2170 static void cpuenable(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
2171 {
2172         int id;
2173
2174         if (opt_n_threads == 0) {
2175                 message(io_data, MSG_CPUNON, 0, NULL, isjson);
2176                 return;
2177         }
2178
2179         if (param == NULL || *param == '\0') {
2180                 message(io_data, MSG_MISID, 0, NULL, isjson);
2181                 return;
2182         }
2183
2184         id = atoi(param);
2185         if (id < 0 || id >= opt_n_threads) {
2186                 message(io_data, MSG_INVCPU, id, NULL, isjson);
2187                 return;
2188         }
2189
2190         applog(LOG_DEBUG, "API: request to cpuenable cpuid %d %s",
2191                         id, cpus[id].proc_repr_ns);
2192
2193         if (cpus[id].deven != DEV_DISABLED) {
2194                 message(io_data, MSG_ALRENAC, id, NULL, isjson);
2195                 return;
2196         }
2197
2198         if (cpus[id].status != LIFE_WELL)
2199         {
2200                 message(io_data, MSG_CPUMRE, id, NULL, isjson);
2201                 return;
2202         }
2203         proc_enable(&cpus[id]);
2204
2205         message(io_data, MSG_CPUREN, id, NULL, isjson);
2206 }
2207
2208 static void cpudisable(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
2209 {
2210         int id;
2211
2212         if (opt_n_threads == 0) {
2213                 message(io_data, MSG_CPUNON, 0, NULL, isjson);
2214                 return;
2215         }
2216
2217         if (param == NULL || *param == '\0') {
2218                 message(io_data, MSG_MISID, 0, NULL, isjson);
2219                 return;
2220         }
2221
2222         id = atoi(param);
2223         if (id < 0 || id >= opt_n_threads) {
2224                 message(io_data, MSG_INVCPU, id, NULL, isjson);
2225                 return;
2226         }
2227
2228         applog(LOG_DEBUG, "API: request to cpudisable cpuid %d %s",
2229                         id, cpus[id].proc_repr_ns);
2230
2231         if (cpus[id].deven == DEV_DISABLED) {
2232                 message(io_data, MSG_ALRDISC, id, NULL, isjson);
2233                 return;
2234         }
2235
2236         cpus[id].deven = DEV_DISABLED;
2237
2238         message(io_data, MSG_CPUDIS, id, NULL, isjson);
2239 }
2240
2241 static void cpurestart(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
2242 {
2243         int id;
2244
2245         if (opt_n_threads == 0) {
2246                 message(io_data, MSG_CPUNON, 0, NULL, isjson);
2247                 return;
2248         }
2249
2250         if (param == NULL || *param == '\0') {
2251                 message(io_data, MSG_MISID, 0, NULL, isjson);
2252                 return;
2253         }
2254
2255         id = atoi(param);
2256         if (id < 0 || id >= opt_n_threads) {
2257                 message(io_data, MSG_INVCPU, id, NULL, isjson);
2258                 return;
2259         }
2260
2261         reinit_device(&cpus[id]);
2262
2263         message(io_data, MSG_CPUREI, id, NULL, isjson);
2264 }
2265 #endif
2266
2267 static void cpucount(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
2268 {
2269         struct api_data *root = NULL;
2270         char buf[TMPBUFSIZ];
2271         bool io_open;
2272         int count = 0;
2273
2274 #ifdef WANT_CPUMINE
2275         count = opt_n_threads > 0 ? num_processors : 0;
2276 #endif
2277
2278         message(io_data, MSG_NUMCPU, 0, NULL, isjson);
2279         io_open = io_add(io_data, isjson ? COMSTR JSON_CPUS : _CPUS COMSTR);
2280
2281         root = api_add_int(root, "Count", &count, false);
2282
2283         root = print_data(root, buf, isjson, false);
2284         io_add(io_data, buf);
2285         if (isjson && io_open)
2286                 io_close(io_data);
2287 }
2288
2289 static void switchpool(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
2290 {
2291         struct pool *pool;
2292         int id;
2293
2294         if (total_pools == 0) {
2295                 message(io_data, MSG_NOPOOL, 0, NULL, isjson);
2296                 return;
2297         }
2298
2299         if (param == NULL || *param == '\0') {
2300                 message(io_data, MSG_MISPID, 0, NULL, isjson);
2301                 return;
2302         }
2303
2304         id = atoi(param);
2305         cg_rlock(&control_lock);
2306         if (id < 0 || id >= total_pools) {
2307                 cg_runlock(&control_lock);
2308                 message(io_data, MSG_INVPID, id, NULL, isjson);
2309                 return;
2310         }
2311
2312         pool = pools[id];
2313         pool->enabled = POOL_ENABLED;
2314         cg_runlock(&control_lock);
2315         switch_pools(pool);
2316
2317         message(io_data, MSG_SWITCHP, id, NULL, isjson);
2318 }
2319
2320 static void copyadvanceafter(char ch, char **param, char **buf)
2321 {
2322 #define src_p (*param)
2323 #define dst_b (*buf)
2324
2325         while (*src_p && *src_p != ch) {
2326                 if (*src_p == '\\' && *(src_p+1) != '\0')
2327                         src_p++;
2328
2329                 *(dst_b++) = *(src_p++);
2330         }
2331         if (*src_p)
2332                 src_p++;
2333
2334         *(dst_b++) = '\0';
2335 }
2336
2337 static bool pooldetails(char *param, char **url, char **user, char **pass)
2338 {
2339         char *ptr, *buf;
2340
2341         ptr = buf = malloc(strlen(param)+1);
2342         if (unlikely(!buf))
2343                 quit(1, "Failed to malloc pooldetails buf");
2344
2345         *url = buf;
2346
2347         // copy url
2348         copyadvanceafter(',', &param, &buf);
2349
2350         if (!(*param)) // missing user
2351                 goto exitsama;
2352
2353         *user = buf;
2354
2355         // copy user
2356         copyadvanceafter(',', &param, &buf);
2357
2358         if (!*param) // missing pass
2359                 goto exitsama;
2360
2361         *pass = buf;
2362
2363         // copy pass
2364         copyadvanceafter(',', &param, &buf);
2365
2366         return true;
2367
2368 exitsama:
2369         free(ptr);
2370         return false;
2371 }
2372
2373 static void addpool(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
2374 {
2375         char *url, *user, *pass;
2376         struct pool *pool;
2377         char *ptr;
2378
2379         if (param == NULL || *param == '\0') {
2380                 message(io_data, MSG_MISPDP, 0, NULL, isjson);
2381                 return;
2382         }
2383
2384         if (!pooldetails(param, &url, &user, &pass)) {
2385                 ptr = escape_string(param, isjson);
2386                 message(io_data, MSG_INVPDP, 0, ptr, isjson);
2387                 if (ptr != param)
2388                         free(ptr);
2389                 ptr = NULL;
2390                 return;
2391         }
2392
2393         pool = add_pool();
2394         detect_stratum(pool, url);
2395         add_pool_details(pool, true, url, user, pass);
2396
2397         ptr = escape_string(url, isjson);
2398         message(io_data, MSG_ADDPOOL, 0, ptr, isjson);
2399         if (ptr != url)
2400                 free(ptr);
2401         ptr = NULL;
2402 }
2403
2404 static void enablepool(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
2405 {
2406         struct pool *pool;
2407         int id;
2408
2409         if (total_pools == 0) {
2410                 message(io_data, MSG_NOPOOL, 0, NULL, isjson);
2411                 return;
2412         }
2413
2414         if (param == NULL || *param == '\0') {
2415                 message(io_data, MSG_MISPID, 0, NULL, isjson);
2416                 return;
2417         }
2418
2419         id = atoi(param);
2420         if (id < 0 || id >= total_pools) {
2421                 message(io_data, MSG_INVPID, id, NULL, isjson);
2422                 return;
2423         }
2424
2425         pool = pools[id];
2426         if (pool->enabled == POOL_ENABLED) {
2427                 message(io_data, MSG_ALRENAP, id, NULL, isjson);
2428                 return;
2429         }
2430
2431         pool->enabled = POOL_ENABLED;
2432         if (pool->prio < current_pool()->prio)
2433                 switch_pools(pool);
2434
2435         message(io_data, MSG_ENAPOOL, id, NULL, isjson);
2436 }
2437
2438 static void poolpriority(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
2439 {
2440         int i;
2441
2442         switch (prioritize_pools(param, &i)) {
2443                 case MSG_NOPOOL:
2444                         message(io_data, MSG_NOPOOL, 0, NULL, isjson);
2445                         return;
2446                 case MSG_MISPID:
2447                         message(io_data, MSG_MISPID, 0, NULL, isjson);
2448                         return;
2449                 case MSG_INVPID:
2450                         message(io_data, MSG_INVPID, i, NULL, isjson);
2451                         return;
2452                 case MSG_DUPPID:
2453                         message(io_data, MSG_DUPPID, i, NULL, isjson);
2454                         return;
2455                 case MSG_POOLPRIO:
2456                 default:
2457                         message(io_data, MSG_POOLPRIO, 0, NULL, isjson);
2458                         return;
2459         }
2460 }
2461
2462 static void poolquota(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
2463 {
2464         struct pool *pool;
2465         int quota, id;
2466         char *comma;
2467
2468         if (total_pools == 0) {
2469                 message(io_data, MSG_NOPOOL, 0, NULL, isjson);
2470                 return;
2471         }
2472
2473         if (param == NULL || *param == '\0') {
2474                 message(io_data, MSG_MISPID, 0, NULL, isjson);
2475                 return;
2476         }
2477
2478         comma = strchr(param, ',');
2479         if (!comma) {
2480                 message(io_data, MSG_CONVAL, 0, param, isjson);
2481                 return;
2482         }
2483
2484         *(comma++) = '\0';
2485
2486         id = atoi(param);
2487         if (id < 0 || id >= total_pools) {
2488                 message(io_data, MSG_INVPID, id, NULL, isjson);
2489                 return;
2490         }
2491         pool = pools[id];
2492
2493         quota = atoi(comma);
2494         if (quota < 0) {
2495                 message(io_data, MSG_INVNEG, quota, pool->rpc_url, isjson);
2496                 return;
2497         }
2498
2499         pool->quota = quota;
2500         adjust_quota_gcd();
2501         message(io_data, MSG_SETQUOTA, quota, pool->rpc_url, isjson);
2502 }
2503
2504 static void disablepool(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
2505 {
2506         struct pool *pool;
2507         int id;
2508
2509         if (total_pools == 0) {
2510                 message(io_data, MSG_NOPOOL, 0, NULL, isjson);
2511                 return;
2512         }
2513
2514         if (param == NULL || *param == '\0') {
2515                 message(io_data, MSG_MISPID, 0, NULL, isjson);
2516                 return;
2517         }
2518
2519         id = atoi(param);
2520         if (id < 0 || id >= total_pools) {
2521                 message(io_data, MSG_INVPID, id, NULL, isjson);
2522                 return;
2523         }
2524
2525         pool = pools[id];
2526         if (pool->enabled == POOL_DISABLED) {
2527                 message(io_data, MSG_ALRDISP, id, NULL, isjson);
2528                 return;
2529         }
2530
2531         if (enabled_pools <= 1) {
2532                 message(io_data, MSG_DISLASTP, id, NULL, isjson);
2533                 return;
2534         }
2535
2536         pool->enabled = POOL_DISABLED;
2537         if (pool == current_pool())
2538                 switch_pools(NULL);
2539
2540         message(io_data, MSG_DISPOOL, id, NULL, isjson);
2541 }
2542
2543 static void removepool(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
2544 {
2545         struct pool *pool;
2546         char *rpc_url;
2547         bool dofree = false;
2548         int id;
2549
2550         if (total_pools == 0) {
2551                 message(io_data, MSG_NOPOOL, 0, NULL, isjson);
2552                 return;
2553         }
2554
2555         if (param == NULL || *param == '\0') {
2556                 message(io_data, MSG_MISPID, 0, NULL, isjson);
2557                 return;
2558         }
2559
2560         id = atoi(param);
2561         if (id < 0 || id >= total_pools) {
2562                 message(io_data, MSG_INVPID, id, NULL, isjson);
2563                 return;
2564         }
2565
2566         if (total_pools <= 1) {
2567                 message(io_data, MSG_REMLASTP, id, NULL, isjson);
2568                 return;
2569         }
2570
2571         pool = pools[id];
2572         if (pool == current_pool())
2573                 switch_pools(NULL);
2574
2575         if (pool == current_pool()) {
2576                 message(io_data, MSG_ACTPOOL, id, NULL, isjson);
2577                 return;
2578         }
2579
2580         pool->enabled = POOL_DISABLED;
2581         rpc_url = escape_string(pool->rpc_url, isjson);
2582         if (rpc_url != pool->rpc_url)
2583                 dofree = true;
2584
2585         remove_pool(pool);
2586
2587         message(io_data, MSG_REMPOOL, id, rpc_url, isjson);
2588
2589         if (dofree)
2590                 free(rpc_url);
2591         rpc_url = NULL;
2592 }
2593
2594 #ifdef HAVE_OPENCL
2595 static bool splitgpuvalue(struct io_data *io_data, char *param, int *gpu, char **value, bool isjson)
2596 {
2597         int id;
2598         char *gpusep;
2599
2600         if (nDevs == 0) {
2601                 message(io_data, MSG_GPUNON, 0, NULL, isjson);
2602                 return false;
2603         }
2604
2605         if (param == NULL || *param == '\0') {
2606                 message(io_data, MSG_MISID, 0, NULL, isjson);
2607                 return false;
2608         }
2609
2610         gpusep = strchr(param, GPUSEP);
2611         if (gpusep == NULL) {
2612                 message(io_data, MSG_MISVAL, 0, NULL, isjson);
2613                 return false;
2614         }
2615
2616         *(gpusep++) = '\0';
2617
2618         id = atoi(param);
2619         if (id < 0 || id >= nDevs) {
2620                 message(io_data, MSG_INVGPU, id, NULL, isjson);
2621                 return false;
2622         }
2623
2624         *gpu = id;
2625         *value = gpusep;
2626
2627         return true;
2628 }
2629
2630 static void gpuintensity(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
2631 {
2632         int id;
2633         char *value;
2634         char intensitystr[7];
2635         char buf[TMPBUFSIZ];
2636
2637         if (!splitgpuvalue(io_data, param, &id, &value, isjson))
2638                 return;
2639
2640         struct cgpu_info * const cgpu = &gpus[id];
2641         struct opencl_device_data * const data = gpus[id].device_data;
2642         
2643         enum bfg_set_device_replytype success;
2644         proc_set_device(cgpu, "intensity", value, buf, &success);
2645         if (success == SDR_OK)
2646         {
2647                 if (data->dynamic)
2648                         strcpy(intensitystr, DYNAMIC);
2649                 else
2650                         snprintf(intensitystr, sizeof(intensitystr), "%g", oclthreads_to_intensity(data->oclthreads, !opt_scrypt));
2651         }
2652         else
2653         {
2654                 message(io_data, MSG_INVINT, 0, value, isjson);
2655                 return;
2656         }
2657
2658         message(io_data, MSG_GPUINT, id, intensitystr, isjson);
2659 }
2660
2661 static void gpumem(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
2662 {
2663 #ifdef HAVE_ADL
2664         int id;
2665         char *value;
2666         char buf[TMPBUFSIZ];
2667
2668         if (!splitgpuvalue(io_data, param, &id, &value, isjson))
2669                 return;
2670
2671         struct cgpu_info * const cgpu = &gpus[id];
2672         
2673         enum bfg_set_device_replytype success;
2674         proc_set_device(cgpu, "memclock", value, buf, &success);
2675         if (success != SDR_OK)
2676                 message(io_data, MSG_GPUMERR, id, value, isjson);
2677         else
2678                 message(io_data, MSG_GPUMEM, id, value, isjson);
2679 #else
2680         message(io_data, MSG_NOADL, 0, NULL, isjson);
2681 #endif
2682 }
2683
2684 static void gpuengine(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
2685 {
2686 #ifdef HAVE_ADL
2687         int id;
2688         char *value;
2689         char buf[TMPBUFSIZ];
2690
2691         if (!splitgpuvalue(io_data, param, &id, &value, isjson))
2692                 return;
2693
2694         struct cgpu_info * const cgpu = &gpus[id];
2695         
2696         enum bfg_set_device_replytype success;
2697         proc_set_device(cgpu, "clock", value, buf, &success);
2698         if (success != SDR_OK)
2699                 message(io_data, MSG_GPUEERR, id, value, isjson);
2700         else
2701                 message(io_data, MSG_GPUENG, id, value, isjson);
2702 #else
2703         message(io_data, MSG_NOADL, 0, NULL, isjson);
2704 #endif
2705 }
2706
2707 static void gpufan(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
2708 {
2709 #ifdef HAVE_ADL
2710         int id;
2711         char *value;
2712         char buf[TMPBUFSIZ];
2713
2714         if (!splitgpuvalue(io_data, param, &id, &value, isjson))
2715                 return;
2716
2717         struct cgpu_info * const cgpu = &gpus[id];
2718         
2719         enum bfg_set_device_replytype success;
2720         proc_set_device(cgpu, "fan", value, buf, &success);
2721         if (success != SDR_OK)
2722                 message(io_data, MSG_GPUFERR, id, value, isjson);
2723         else
2724                 message(io_data, MSG_GPUFAN, id, value, isjson);
2725 #else
2726         message(io_data, MSG_NOADL, 0, NULL, isjson);
2727 #endif
2728 }
2729
2730 static void gpuvddc(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
2731 {
2732 #ifdef HAVE_ADL
2733         int id;
2734         char *value;
2735         char buf[TMPBUFSIZ];
2736
2737         if (!splitgpuvalue(io_data, param, &id, &value, isjson))
2738                 return;
2739
2740         struct cgpu_info * const cgpu = &gpus[id];
2741         
2742         enum bfg_set_device_replytype success;
2743         proc_set_device(cgpu, "voltage", value, buf, &success);
2744         if (success != SDR_OK)
2745                 message(io_data, MSG_GPUVERR, id, value, isjson);
2746         else
2747                 message(io_data, MSG_GPUVDDC, id, value, isjson);
2748 #else
2749         message(io_data, MSG_NOADL, 0, NULL, isjson);
2750 #endif
2751 }
2752 #endif
2753
2754 void doquit(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
2755 {
2756         if (isjson)
2757                 io_put(io_data, JSON_START JSON_BYE);
2758         else
2759                 io_put(io_data, _BYE);
2760
2761         bye = true;
2762         do_a_quit = true;
2763 }
2764
2765 void dorestart(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
2766 {
2767         if (isjson)
2768                 io_put(io_data, JSON_START JSON_RESTART);
2769         else
2770                 io_put(io_data, _RESTART);
2771
2772         bye = true;
2773         do_a_restart = true;
2774 }
2775
2776 void privileged(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
2777 {
2778         message(io_data, MSG_ACCOK, 0, NULL, isjson);
2779 }
2780
2781 void notifystatus(struct io_data *io_data, int device, struct cgpu_info *cgpu, bool isjson, __maybe_unused char group)
2782 {
2783         struct cgpu_info *proc;
2784         struct api_data *root = NULL;
2785         char buf[TMPBUFSIZ];
2786         char *reason;
2787         
2788         time_t last_not_well = 0;
2789         enum dev_reason uninitialised_var(enum_reason);
2790         int thread_fail_init_count = 0, thread_zero_hash_count = 0, thread_fail_queue_count = 0;
2791         int dev_sick_idle_60_count = 0, dev_dead_idle_600_count = 0;
2792         int dev_nostart_count = 0, dev_over_heat_count = 0, dev_thermal_cutoff_count = 0, dev_comms_error_count = 0, dev_throttle_count = 0;
2793
2794         int procs = per_proc ? 1 : cgpu->procs, i;
2795         for (i = 0, proc = cgpu; i < procs; ++i, proc = proc->next_proc)
2796         {
2797                 if (proc->device_last_not_well > last_not_well)
2798                 {
2799                         last_not_well = proc->device_last_not_well;
2800                         enum_reason = proc->device_not_well_reason;
2801                         thread_fail_init_count   += proc->thread_fail_init_count;
2802                         thread_zero_hash_count   += proc->thread_zero_hash_count;
2803                         thread_fail_queue_count  += proc->thread_fail_queue_count;
2804                         dev_sick_idle_60_count   += proc->dev_sick_idle_60_count;
2805                         dev_dead_idle_600_count  += proc->dev_dead_idle_600_count;
2806                         dev_nostart_count        += proc->dev_nostart_count;
2807                         dev_over_heat_count      += proc->dev_over_heat_count;
2808                         dev_thermal_cutoff_count += proc->dev_thermal_cutoff_count;
2809                         dev_comms_error_count    += proc->dev_comms_error_count;
2810                         dev_throttle_count       += proc->dev_throttle_count;
2811                 }
2812                 if (per_proc)
2813                         break;
2814         }
2815         
2816         if (last_not_well == 0)
2817                 reason = REASON_NONE;
2818         else
2819                 switch (enum_reason)
2820                 {
2821                         case REASON_THREAD_FAIL_INIT:
2822                                 reason = REASON_THREAD_FAIL_INIT_STR;
2823                                 break;
2824                         case REASON_THREAD_ZERO_HASH:
2825                                 reason = REASON_THREAD_ZERO_HASH_STR;
2826                                 break;
2827                         case REASON_THREAD_FAIL_QUEUE:
2828                                 reason = REASON_THREAD_FAIL_QUEUE_STR;
2829                                 break;
2830                         case REASON_DEV_SICK_IDLE_60:
2831                                 reason = REASON_DEV_SICK_IDLE_60_STR;
2832                                 break;
2833                         case REASON_DEV_DEAD_IDLE_600:
2834                                 reason = REASON_DEV_DEAD_IDLE_600_STR;
2835                                 break;
2836                         case REASON_DEV_NOSTART:
2837                                 reason = REASON_DEV_NOSTART_STR;
2838                                 break;
2839                         case REASON_DEV_OVER_HEAT:
2840                                 reason = REASON_DEV_OVER_HEAT_STR;
2841                                 break;
2842                         case REASON_DEV_THERMAL_CUTOFF:
2843                                 reason = REASON_DEV_THERMAL_CUTOFF_STR;
2844                                 break;
2845                         case REASON_DEV_COMMS_ERROR:
2846                                 reason = REASON_DEV_COMMS_ERROR_STR;
2847                                 break;
2848                         default:
2849                                 reason = REASON_UNKNOWN_STR;
2850                                 break;
2851                 }
2852
2853         // ALL counters (and only counters) must start the name with a '*'
2854         // Simplifies future external support for identifying new counters
2855         root = api_add_int(root, "NOTIFY", &device, false);
2856         root = api_add_device_identifier(root, cgpu);
2857         if (per_proc)
2858                 root = api_add_time(root, "Last Well", &(cgpu->device_last_well), false);
2859         root = api_add_time(root, "Last Not Well", &last_not_well, false);
2860         root = api_add_string(root, "Reason Not Well", reason, false);
2861         root = api_add_int(root, "*Thread Fail Init", &thread_fail_init_count, false);
2862         root = api_add_int(root, "*Thread Zero Hash", &thread_zero_hash_count, false);
2863         root = api_add_int(root, "*Thread Fail Queue", &thread_fail_queue_count, false);
2864         root = api_add_int(root, "*Dev Sick Idle 60s", &dev_sick_idle_60_count, false);
2865         root = api_add_int(root, "*Dev Dead Idle 600s", &dev_dead_idle_600_count, false);
2866         root = api_add_int(root, "*Dev Nostart", &dev_nostart_count, false);
2867         root = api_add_int(root, "*Dev Over Heat", &dev_over_heat_count, false);
2868         root = api_add_int(root, "*Dev Thermal Cutoff", &dev_thermal_cutoff_count, false);
2869         root = api_add_int(root, "*Dev Comms Error", &dev_comms_error_count, false);
2870         root = api_add_int(root, "*Dev Throttle", &dev_throttle_count, false);
2871
2872         root = print_data(root, buf, isjson, isjson && (device > 0));
2873         io_add(io_data, buf);
2874 }
2875
2876 static
2877 void notify(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, char group)
2878 {
2879         struct cgpu_info *cgpu;
2880         bool io_open = false;
2881         int i, n = 0;
2882
2883         if (total_devices == 0) {
2884                 message(io_data, MSG_NODEVS, 0, NULL, isjson);
2885                 return;