@ -29,12 +29,6 @@
@@ -29,12 +29,6 @@
# include "miner.h"
# include "util.h"
// Big enough for largest API request
// data is truncated at the end of the last record that fits
// but still closed correctly for JSON
// Current code assumes it can socket send this size + JSON_CLOSE + JSON_END
# define SOCKBUFSIZ 65432
// BUFSIZ varies on Windows and Linux
# define TMPBUFSIZ 8192
@ -126,7 +120,11 @@ static const char SEPARATOR = '|';
@@ -126,7 +120,11 @@ static const char SEPARATOR = '|';
# define SEPSTR "|"
static const char GPUSEP = ' , ' ;
static const char * APIVERSION = " 3.0 " ;
# define CMDJOIN '+'
# define JOIN_CMD "CMD="
# define BETWEEN_JOIN SEPSTR
static const char * APIVERSION = " 3.1 " ;
static const char * DEAD = " Dead " ;
static const char * SICK = " Sick " ;
static const char * NOSTART = " NoStart " ;
@ -215,9 +213,10 @@ static const char ISJSON = '{';
@@ -215,9 +213,10 @@ static const char ISJSON = '{';
# define JSON_MINECOIN JSON1 _MINECOIN JSON2
# define JSON_DEBUGSET JSON1 _DEBUGSET JSON2
# define JSON_SETCONFIG JSON1 _SETCONFIG JSON2
# define JSON_USBSTATS JSON1 _USBSTATS JSON2
# define JSON_END JSON4 JSON5
# define JSON_END_TRUNCATED JSON4_TRUNCATED JSON5
# define JSON_BETWEEN_JOIN ","
static const char * JSON_COMMAND = " command " ;
static const char * JSON_PARAMETER = " parameter " ;
@ -296,7 +295,7 @@ static const char *JSON_PARAMETER = "parameter";
@@ -296,7 +295,7 @@ static const char *JSON_PARAMETER = "parameter";
# define MSG_INVNUM 84
# define MSG_CONPAR 85
# define MSG_CONVAL 86
# define MSG_USBSTA 87
# define MSG_NOUSTA 88
# define MSG_ZERMIS 94
@ -418,7 +417,6 @@ struct CODES {
@@ -418,7 +417,6 @@ struct CODES {
{ SEVERITY_SUCC , MSG_SETQUOTA , PARAM_SET , " Set pool '%s' to quota %d' " } ,
{ SEVERITY_ERR , MSG_CONPAR , PARAM_NONE , " Missing config parameters 'name,N' " } ,
{ SEVERITY_ERR , MSG_CONVAL , PARAM_STR , " Missing config value N for '%s,N' " } ,
{ SEVERITY_SUCC , MSG_USBSTA , PARAM_NONE , " USB Statistics " } ,
{ SEVERITY_INFO , MSG_NOUSTA , PARAM_NONE , " No USB Statistics " } ,
{ SEVERITY_ERR , MSG_ZERMIS , PARAM_NONE , " Missing zero parameters " } ,
{ SEVERITY_ERR , MSG_ZERINV , PARAM_STR , " Invalid zero parameter '%s' " } ,
@ -729,6 +727,10 @@ static struct api_data *api_add_data_full(struct api_data *root, char *name, enu
@@ -729,6 +727,10 @@ static struct api_data *api_add_data_full(struct api_data *root, char *name, enu
api_data - > data = ( void * ) malloc ( sizeof ( uint32_t ) ) ;
* ( ( uint32_t * ) ( api_data - > data ) ) = * ( ( uint32_t * ) data ) ;
break ;
case API_HEX32 :
api_data - > data = ( void * ) malloc ( sizeof ( uint32_t ) ) ;
* ( ( uint32_t * ) ( api_data - > data ) ) = * ( ( uint32_t * ) data ) ;
break ;
case API_UINT64 :
api_data - > data = ( void * ) malloc ( sizeof ( uint64_t ) ) ;
* ( ( uint64_t * ) ( api_data - > data ) ) = * ( ( uint64_t * ) data ) ;
@ -815,6 +817,11 @@ struct api_data *api_add_uint32(struct api_data *root, char *name, uint32_t *dat
@@ -815,6 +817,11 @@ struct api_data *api_add_uint32(struct api_data *root, char *name, uint32_t *dat
return api_add_data_full ( root , name , API_UINT32 , ( void * ) data , copy_data ) ;
}
struct api_data * api_add_hex32 ( struct api_data * root , char * name , uint32_t * data , bool copy_data )
{
return api_add_data_full ( root , name , API_HEX32 , ( void * ) data , copy_data ) ;
}
struct api_data * api_add_uint64 ( struct api_data * root , char * name , uint64_t * data , bool copy_data )
{
return api_add_data_full ( root , name , API_UINT64 , ( void * ) data , copy_data ) ;
@ -958,6 +965,9 @@ static struct api_data *print_data(struct api_data *root, char *buf, bool isjson
@@ -958,6 +965,9 @@ static struct api_data *print_data(struct api_data *root, char *buf, bool isjson
case API_UINT32 :
sprintf ( buf , " % " PRIu32 , * ( ( uint32_t * ) ( root - > data ) ) ) ;
break ;
case API_HEX32 :
snprintf ( buf , sizeof ( buf ) , " 0x%08x " , * ( ( uint32_t * ) ( root - > data ) ) ) ;
break ;
case API_UINT64 :
sprintf ( buf , " % " PRIu64 , * ( ( uint64_t * ) ( root - > data ) ) ) ;
break ;
@ -995,9 +1005,9 @@ static struct api_data *print_data(struct api_data *root, char *buf, bool isjson
@@ -995,9 +1005,9 @@ static struct api_data *print_data(struct api_data *root, char *buf, bool isjson
sprintf ( buf , " %s " , * ( ( bool * ) ( root - > data ) ) ? TRUESTR : FALSESTR ) ;
break ;
case API_TIMEVAL :
sprintf ( buf , " %ld.%06ld " ,
( ( struct timeval * ) ( root - > data ) ) - > tv_sec ,
( ( struct timeval * ) ( root - > data ) ) - > tv_usec ) ;
sn printf ( buf , sizeof ( buf ) , " %ld.%06ld " ,
( long ) ( ( struct timeval * ) ( root - > data ) ) - > tv_sec ,
( long ) ( ( struct timeval * ) ( root - > data ) ) - > tv_usec ) ;
break ;
case API_TEMP :
sprintf ( buf , " %.2f " , * ( ( float * ) ( root - > data ) ) ) ;
@ -1049,10 +1059,8 @@ static void message(struct io_data *io_data, int messageid, int paramid, char *p
@@ -1049,10 +1059,8 @@ static void message(struct io_data *io_data, int messageid, int paramid, char *p
int i ;
io_reinit ( io_data ) ;
if ( isjson )
io_put ( io_data , JSON_START JSON_STATUS ) ;
io_add ( io_data , JSON_START JSON_STATUS ) ;
for ( i = 0 ; codes [ i ] . severity ! = SEVERITY_FAIL ; i + + ) {
if ( codes [ i ] . code = = messageid ) {
@ -3033,44 +3041,45 @@ struct CMDS {
@@ -3033,44 +3041,45 @@ struct CMDS {
char * name ;
void ( * func ) ( struct io_data * , SOCKETTYPE , char * , bool , char ) ;
bool iswritemode ;
bool joinable ;
} cmds [ ] = {
{ " version " , apiversion , false } ,
{ " config " , minerconfig , false } ,
{ " devs " , devstatus , false } ,
{ " pools " , poolstatus , false } ,
{ " summary " , summary , false } ,
{ " gpuenable " , gpuenable , tru e } ,
{ " gpudisable " , gpudisable , tru e } ,
{ " gpurestart " , gpurestart , tru e } ,
{ " gpu " , gpudev , false } ,
{ " gpucount " , gpucount , fals e } ,
{ " switchpool " , switchpool , true } ,
{ " addpool " , addpool , true } ,
{ " poolpriority " , poolpriority , true } ,
{ " poolquota " , poolquota , true } ,
{ " enablepool " , enablepool , true } ,
{ " disablepool " , disablepool , true } ,
{ " removepool " , removepool , true } ,
{ " gpuintensity " , gpuintensity , tru e } ,
{ " gpumem " , gpumem , tru e } ,
{ " gpuengine " , gpuengine , tru e } ,
{ " gpufan " , gpufan , tru e } ,
{ " gpuvddc " , gpuvddc , tru e } ,
{ " save " , dosave , true } ,
{ " quit " , doquit , true } ,
{ " privileged " , privileged , true } ,
{ " notify " , notify , false } ,
{ " devdetails " , devdetails , false } ,
{ " restart " , dorestart , true } ,
{ " stats " , minerstats , false } ,
{ " check " , checkcommand , false } ,
{ " failover-only " , failoveronly , true } ,
{ " coin " , minecoin , false } ,
{ " debug " , debugstate , true } ,
{ " setconfig " , setconfig , true } ,
{ " zero " , dozero , true } ,
{ " lockstats " , lockstats , true } ,
{ NULL , NULL , false }
{ " version " , apiversion , false , true } ,
{ " config " , minerconfig , false , true } ,
{ " devs " , devstatus , false , true } ,
{ " pools " , poolstatus , false , true } ,
{ " summary " , summary , false , true } ,
{ " gpuenable " , gpuenable , true , fals e } ,
{ " gpudisable " , gpudisable , true , fals e } ,
{ " gpurestart " , gpurestart , true , fals e } ,
{ " gpu " , gpudev , false , false } ,
{ " gpucount " , gpucount , false , tru e } ,
{ " switchpool " , switchpool , true , false } ,
{ " addpool " , addpool , true , false } ,
{ " poolpriority " , poolpriority , true , false } ,
{ " poolquota " , poolquota , true , false } ,
{ " enablepool " , enablepool , true , false } ,
{ " disablepool " , disablepool , true , false } ,
{ " removepool " , removepool , true , false } ,
{ " gpuintensity " , gpuintensity , true , fals e } ,
{ " gpumem " , gpumem , true , fals e } ,
{ " gpuengine " , gpuengine , true , fals e } ,
{ " gpufan " , gpufan , true , fals e } ,
{ " gpuvddc " , gpuvddc , true , fals e } ,
{ " save " , dosave , true , false } ,
{ " quit " , doquit , true , false } ,
{ " privileged " , privileged , true , false } ,
{ " notify " , notify , false , true } ,
{ " devdetails " , devdetails , false , true } ,
{ " restart " , dorestart , true , false } ,
{ " stats " , minerstats , false , true } ,
{ " check " , checkcommand , false , false } ,
{ " failover-only " , failoveronly , true , false } ,
{ " coin " , minecoin , false , true } ,
{ " debug " , debugstate , true , false } ,
{ " setconfig " , setconfig , true , false } ,
{ " zero " , dozero , true , false } ,
{ " lockstats " , lockstats , true , true } ,
{ NULL , NULL , false , false }
} ;
static void checkcommand ( struct io_data * io_data , __maybe_unused SOCKETTYPE c , char * param , bool isjson , char group )
@ -3113,6 +3122,49 @@ static void checkcommand(struct io_data *io_data, __maybe_unused SOCKETTYPE c, c
@@ -3113,6 +3122,49 @@ static void checkcommand(struct io_data *io_data, __maybe_unused SOCKETTYPE c, c
io_close ( io_data ) ;
}
static void head_join ( struct io_data * io_data , char * cmdptr , bool isjson , bool * firstjoin )
{
char * ptr ;
if ( * firstjoin ) {
if ( isjson )
io_add ( io_data , JSON0 ) ;
* firstjoin = false ;
} else {
if ( isjson )
io_add ( io_data , JSON_BETWEEN_JOIN ) ;
}
// External supplied string
ptr = escape_string ( cmdptr , isjson ) ;
if ( isjson ) {
io_add ( io_data , JSON1 ) ;
io_add ( io_data , ptr ) ;
io_add ( io_data , JSON2 ) ;
} else {
io_add ( io_data , JOIN_CMD ) ;
io_add ( io_data , ptr ) ;
io_add ( io_data , BETWEEN_JOIN ) ;
}
if ( ptr ! = cmdptr )
free ( ptr ) ;
}
static void tail_join ( struct io_data * io_data , bool isjson )
{
if ( io_data - > close ) {
io_add ( io_data , JSON_CLOSE ) ;
io_data - > close = false ;
}
if ( isjson ) {
io_add ( io_data , JSON_END ) ;
io_add ( io_data , JSON3 ) ;
}
}
static void send_result ( struct io_data * io_data , SOCKETTYPE c , bool isjson )
{
int count , sendc , res , tosend , len , n ;
@ -3677,7 +3729,7 @@ void api(int api_thr_id)
@@ -3677,7 +3729,7 @@ void api(int api_thr_id)
struct sockaddr_in cli ;
socklen_t clisiz ;
char cmdbuf [ 100 ] ;
char * cmd = NULL ;
char * cmd = NULL , * cmdptr , * cmdsbuf ;
char * param ;
bool addrok ;
char group ;
@ -3685,7 +3737,7 @@ void api(int api_thr_id)
@@ -3685,7 +3737,7 @@ void api(int api_thr_id)
json_t * json_config = NULL ;
json_t * json_val ;
bool isjson ;
bool did ;
bool did , isjoin , firstjoin ;
int i ;
SOCKETTYPE * apisock ;
@ -3886,27 +3938,80 @@ void api(int api_thr_id)
@@ -3886,27 +3938,80 @@ void api(int api_thr_id)
}
if ( ! did ) {
for ( i = 0 ; cmds [ i ] . name ! = NULL ; i + + ) {
if ( strcmp ( cmd , cmds [ i ] . name ) = = 0 ) {
sprintf ( cmdbuf , " |%s| " , cmd ) ;
if ( ISPRIVGROUP ( group ) | | strstr ( COMMANDS ( group ) , cmdbuf ) )
( cmds [ i ] . func ) ( io_data , c , param , isjson , group ) ;
else {
message ( io_data , MSG_ACCDENY , 0 , cmds [ i ] . name , isjson ) ;
applog ( LOG_DEBUG , " API: access denied to '%s' for '%s' command " , connectaddr , cmds [ i ] . name ) ;
if ( strchr ( cmd , CMDJOIN ) ) {
firstjoin = isjoin = true ;
// cmd + leading '|' + '\0'
cmdsbuf = malloc ( strlen ( cmd ) + 2 ) ;
if ( ! cmdsbuf )
quithere ( 1 , " OOM cmdsbuf " ) ;
strcpy ( cmdsbuf , " | " ) ;
param = NULL ;
} else
firstjoin = isjoin = false ;
cmdptr = cmd ;
do {
did = false ;
if ( isjoin ) {
cmd = strchr ( cmdptr , CMDJOIN ) ;
if ( cmd )
* ( cmd + + ) = ' \0 ' ;
if ( ! * cmdptr )
goto inochi ;
}
for ( i = 0 ; cmds [ i ] . name ! = NULL ; i + + ) {
if ( strcmp ( cmdptr , cmds [ i ] . name ) = = 0 ) {
sprintf ( cmdbuf , " |%s| " , cmdptr ) ;
if ( isjoin ) {
if ( strstr ( cmdsbuf , cmdbuf ) ) {
did = true ;
break ;
}
strcat ( cmdsbuf , cmdptr ) ;
strcat ( cmdsbuf , " | " ) ;
head_join ( io_data , cmdptr , isjson , & firstjoin ) ;
if ( ! cmds [ i ] . joinable ) {
message ( io_data , MSG_ACCDENY , 0 , cmds [ i ] . name , isjson ) ;
did = true ;
tail_join ( io_data , isjson ) ;
break ;
}
}
if ( ISPRIVGROUP ( group ) | | strstr ( COMMANDS ( group ) , cmdbuf ) )
( cmds [ i ] . func ) ( io_data , c , param , isjson , group ) ;
else {
message ( io_data , MSG_ACCDENY , 0 , cmds [ i ] . name , isjson ) ;
applog ( LOG_DEBUG , " API: access denied to '%s' for '%s' command " , connectaddr , cmds [ i ] . name ) ;
}
did = true ;
if ( ! isjoin )
send_result ( io_data , c , isjson ) ;
else
tail_join ( io_data , isjson ) ;
break ;
}
}
send_result ( io_data , c , isjson ) ;
did = true ;
break ;
if ( ! did ) {
if ( isjoin )
head_join ( io_data , cmdptr , isjson , & firstjoin ) ;
message ( io_data , MSG_INVCMD , 0 , NULL , isjson ) ;
if ( isjoin )
tail_join ( io_data , isjson ) ;
else
send_result ( io_data , c , isjson ) ;
}
}
inochi :
if ( isjoin )
cmdptr = cmd ;
} while ( isjoin & & cmdptr ) ;
}
if ( ! did ) {
message ( io_data , MSG_INVCMD , 0 , NULL , isjson ) ;
if ( isjoin )
send_result ( io_data , c , isjson ) ;
}
if ( isjson & & json_is_object ( json_config ) )
json_decref ( json_config ) ;
}