api.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726
  1. /*
  2. * Copyright 2011 Kano
  3. * Copyright 2011 Con Kolivas
  4. *
  5. * This program is free software; you can redistribute it and/or modify it
  6. * under the terms of the GNU General Public License as published by the Free
  7. * Software Foundation; either version 2 of the License, or (at your option)
  8. * any later version. See COPYING for more details.
  9. */
  10. #include "config.h"
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <stdbool.h>
  15. #include <stdint.h>
  16. #include <unistd.h>
  17. #include <sys/types.h>
  18. #include "compat.h"
  19. #include "miner.h"
  20. #if defined(unix)
  21. #include <errno.h>
  22. #include <sys/socket.h>
  23. #include <netinet/in.h>
  24. #include <arpa/inet.h>
  25. #define SOCKETTYPE int
  26. #define BINDERROR < 0
  27. #define LISTENERROR BINDERROR
  28. #define ACCEPTERROR BINDERROR
  29. #define INVSOCK -1
  30. #define CLOSESOCKET close
  31. #endif
  32. #ifdef WIN32
  33. #include <winsock2.h>
  34. #include "inet_ntop.h"
  35. #include "inet_pton.h"
  36. #define SOCKETTYPE SOCKET
  37. #define BINDERROR == SOCKET_ERROR
  38. #define LISTENERROR BINDERROR
  39. #define ACCEPTERROR BINDERROR
  40. #define INVSOCK INVALID_SOCKET
  41. #define CLOSESOCKET closesocket
  42. #ifndef SHUT_RDWR
  43. #define SHUT_RDWR SD_BOTH
  44. #endif
  45. #endif
  46. // Big enough for largest API request
  47. // though a PC with 100s of CPUs may exceed the size ...
  48. // Current code assumes it can socket send this size also
  49. #define MYBUFSIZ 16384
  50. // Number of requests to queue - normally would be small
  51. #define QUEUE 10
  52. static char *io_buffer = NULL;
  53. static char *msg_buffer = NULL;
  54. static SOCKETTYPE sock = INVSOCK;
  55. static const char *UNAVAILABLE = " - API will not be available";
  56. static const char *BLANK = "";
  57. static const char SEPARATOR = '|';
  58. static const char *SEPARATORSTR = "|";
  59. #define MSG_INVGPU 1
  60. #define MSG_ALRENA 2
  61. #define MSG_ALRDIS 3
  62. #define MSG_GPUMRE 4
  63. #define MSG_GPUREN 5
  64. #define MSG_GPUNON 6
  65. #define MSG_POOL 7
  66. #define MSG_NOPOOL 8
  67. #define MSG_DEVS 9
  68. #define MSG_NODEVS 10
  69. #define MSG_SUMM 11
  70. #define MSG_GPUDIS 12
  71. #define MSG_GPUREI 13
  72. #define MSG_INVCMD 14
  73. #define MSG_MISID 15
  74. #define MSG_CPUNON 16
  75. #define MSG_GPUDEV 17
  76. #define MSG_CPUDEV 18
  77. #define MSG_INVCPU 19
  78. #define MSG_NUMGPU 20
  79. #define MSG_NUMCPU 21
  80. enum code_severity {
  81. SEVERITY_ERR,
  82. SEVERITY_WARN,
  83. SEVERITY_INFO,
  84. SEVERITY_SUCC,
  85. SEVERITY_FAIL
  86. };
  87. enum code_parameters {
  88. PARAM_GPU,
  89. PARAM_CPU,
  90. PARAM_GPUMAX,
  91. PARAM_CPUMAX,
  92. PARAM_PMAX,
  93. PARAM_GCMAX,
  94. PARAM_NONE
  95. };
  96. struct CODES {
  97. const enum code_severity severity;
  98. const int code;
  99. const enum code_parameters params;
  100. const char *description;
  101. } codes[] = {
  102. { SEVERITY_ERR, MSG_INVGPU, PARAM_GPUMAX, "Invalid GPU id %d - range is 0 - %d" },
  103. { SEVERITY_INFO, MSG_ALRENA, PARAM_GPU, "GPU %d already enabled" },
  104. { SEVERITY_INFO, MSG_ALRDIS, PARAM_GPU, "GPU %d already disabled" },
  105. { SEVERITY_WARN, MSG_GPUMRE, PARAM_GPU, "GPU %d must be restarted first" },
  106. { SEVERITY_INFO, MSG_GPUREN, PARAM_GPU, "GPU %d sent enable message" },
  107. { SEVERITY_ERR, MSG_GPUNON, PARAM_NONE, "No GPUs" },
  108. { SEVERITY_SUCC, MSG_POOL, PARAM_PMAX, "%d Pool(s)" },
  109. { SEVERITY_ERR, MSG_NOPOOL, PARAM_NONE, "No pools" },
  110. { SEVERITY_SUCC, MSG_DEVS, PARAM_GCMAX, "%d GPU(s) - %d CPU(s)" },
  111. { SEVERITY_ERR, MSG_NODEVS, PARAM_NONE, "No GPUs/CPUs" },
  112. { SEVERITY_SUCC, MSG_SUMM, PARAM_NONE, "Summary" },
  113. { SEVERITY_INFO, MSG_GPUDIS, PARAM_GPU, "GPU %d set disable flag" },
  114. { SEVERITY_INFO, MSG_GPUREI, PARAM_GPU, "GPU %d restart attempted" },
  115. { SEVERITY_ERR, MSG_INVCMD, PARAM_NONE, "Invalid command" },
  116. { SEVERITY_ERR, MSG_MISID, PARAM_NONE, "Missing device id parameter" },
  117. { SEVERITY_ERR, MSG_CPUNON, PARAM_NONE, "No CPUs" },
  118. { SEVERITY_SUCC, MSG_GPUDEV, PARAM_GPU, "GPU%d" },
  119. { SEVERITY_SUCC, MSG_CPUDEV, PARAM_CPU, "CPU%d" },
  120. { SEVERITY_ERR, MSG_INVCPU, PARAM_CPUMAX, "Invalid CPU id %d - range is 0 - %d" },
  121. { SEVERITY_SUCC, MSG_NUMGPU, PARAM_NONE, "GPU count" },
  122. { SEVERITY_SUCC, MSG_NUMCPU, PARAM_NONE, "CPU count" },
  123. { SEVERITY_FAIL }
  124. };
  125. static const char *APIVERSION = "0.3";
  126. static const char *DEAD = "DEAD";
  127. static const char *SICK = "SICK";
  128. static const char *NOSTART = "NOSTART";
  129. static const char *DISABLED = "DISABLED";
  130. static const char *ALIVE = "ALIVE";
  131. static const char *DYNAMIC = "D";
  132. static const char *YES = "Y";
  133. static const char *NO = "N";
  134. static int bye = 0;
  135. static bool ping = true;
  136. static char *message(int messageid, int gpuid)
  137. {
  138. char severity;
  139. char *ptr;
  140. int cpu;
  141. int i;
  142. for (i = 0; codes[i].severity != SEVERITY_FAIL; i++) {
  143. if (codes[i].code == messageid) {
  144. switch (codes[i].severity) {
  145. case SEVERITY_WARN:
  146. severity = 'W';
  147. break;
  148. case SEVERITY_INFO:
  149. severity = 'I';
  150. break;
  151. case SEVERITY_SUCC:
  152. severity = 'S';
  153. break;
  154. case SEVERITY_ERR:
  155. default:
  156. severity = 'E';
  157. break;
  158. }
  159. sprintf(msg_buffer, "STATUS=%c,CODE=%d,MSG=", severity, messageid);
  160. ptr = msg_buffer + strlen(msg_buffer);
  161. switch(codes[i].params) {
  162. case PARAM_GPU:
  163. sprintf(ptr, codes[i].description, gpuid);
  164. break;
  165. case PARAM_CPU:
  166. sprintf(ptr, codes[i].description, gpuid);
  167. break;
  168. case PARAM_GPUMAX:
  169. sprintf(ptr, codes[i].description, gpuid, nDevs - 1);
  170. break;
  171. case PARAM_PMAX:
  172. sprintf(ptr, codes[i].description, total_pools);
  173. break;
  174. case PARAM_GCMAX:
  175. if (opt_n_threads > 0)
  176. cpu = num_processors;
  177. else
  178. cpu = 0;
  179. sprintf(ptr, codes[i].description, nDevs, cpu);
  180. break;
  181. case PARAM_NONE:
  182. default:
  183. strcpy(ptr, codes[i].description);
  184. }
  185. strcat(msg_buffer, SEPARATORSTR);
  186. return msg_buffer;
  187. }
  188. }
  189. sprintf(msg_buffer, "STATUS=F,CODE=-1,MSG=%d%c", messageid, SEPARATOR);
  190. return msg_buffer;
  191. }
  192. void apiversion(char *params)
  193. {
  194. strcpy(io_buffer, APIVERSION);
  195. }
  196. void gpustatus(int gpu)
  197. {
  198. char intensity[20];
  199. char buf[BUFSIZ];
  200. char *enabled;
  201. char *status;
  202. float gt;
  203. int gf, gp;
  204. if (gpu >= 0 && gpu < nDevs) {
  205. struct cgpu_info *cgpu = &gpus[gpu];
  206. cgpu->utility = cgpu->accepted / ( total_secs ? total_secs : 1 ) * 60;
  207. #ifdef HAVE_ADL
  208. if (cgpu->has_adl) {
  209. gt = gpu_temp(gpu);
  210. gf = gpu_fanspeed(gpu);
  211. gp = gpu_fanpercent(gpu);
  212. }
  213. else
  214. #endif
  215. gt = gf = gp = 0;
  216. if (gpu_devices[gpu])
  217. enabled = (char *)YES;
  218. else
  219. enabled = (char *)NO;
  220. if (cgpu->status == LIFE_DEAD)
  221. status = (char *)DEAD;
  222. else if (cgpu->status == LIFE_SICK)
  223. status = (char *)SICK;
  224. else if (cgpu->status == LIFE_NOSTART)
  225. status = (char *)NOSTART;
  226. else
  227. status = (char *)ALIVE;
  228. if (cgpu->dynamic)
  229. strcpy(intensity, DYNAMIC);
  230. else
  231. sprintf(intensity, "%d", gpus->intensity);
  232. sprintf(buf, "GPU=%d,GT=%.2f,FR=%d,FP=%d,EN=%s,STA=%s,MHS=%.2f,A=%d,R=%d,HW=%d,U=%.2f,I=%s%c",
  233. gpu, gt, gf, gp, enabled, status,
  234. cgpu->total_mhashes / total_secs,
  235. cgpu->accepted, cgpu->rejected, cgpu->hw_errors,
  236. cgpu->utility, intensity, SEPARATOR);
  237. strcat(io_buffer, buf);
  238. }
  239. }
  240. void cpustatus(int cpu)
  241. {
  242. char buf[BUFSIZ];
  243. if (opt_n_threads > 0 && cpu >= 0 && cpu < num_processors) {
  244. struct cgpu_info *cgpu = &cpus[cpu];
  245. cgpu->utility = cgpu->accepted / ( total_secs ? total_secs : 1 ) * 60;
  246. sprintf(buf, "CPU=%d,STA=%.2f,MHS=%.2f,A=%d,R=%d,U=%.2f%c",
  247. cpu, cgpu->rolling,
  248. cgpu->total_mhashes / total_secs,
  249. cgpu->accepted, cgpu->rejected,
  250. cgpu->utility, SEPARATOR);
  251. strcat(io_buffer, buf);
  252. }
  253. }
  254. void devstatus(char *params)
  255. {
  256. int i;
  257. if (nDevs == 0 && opt_n_threads == 0) {
  258. strcpy(io_buffer, message(MSG_NODEVS, 0));
  259. return;
  260. }
  261. strcpy(io_buffer, message(MSG_DEVS, 0));
  262. for (i = 0; i < nDevs; i++)
  263. gpustatus(i);
  264. if (opt_n_threads > 0)
  265. for (i = 0; i < num_processors; i++)
  266. cpustatus(i);
  267. }
  268. void gpudev(char *params)
  269. {
  270. int id;
  271. if (nDevs == 0) {
  272. strcpy(io_buffer, message(MSG_GPUNON, 0));
  273. return;
  274. }
  275. if (*params == '\0') {
  276. strcpy(io_buffer, message(MSG_MISID, 0));
  277. return;
  278. }
  279. id = atoi(params);
  280. if (id < 0 || id >= nDevs) {
  281. strcpy(io_buffer, message(MSG_INVGPU, id));
  282. return;
  283. }
  284. strcpy(io_buffer, message(MSG_GPUDEV, id));
  285. gpustatus(id);
  286. }
  287. void cpudev(char *params)
  288. {
  289. int id;
  290. if (opt_n_threads == 0) {
  291. strcpy(io_buffer, message(MSG_CPUNON, 0));
  292. return;
  293. }
  294. if (*params == '\0') {
  295. strcpy(io_buffer, message(MSG_MISID, 0));
  296. return;
  297. }
  298. id = atoi(params);
  299. if (id < 0 || id >= num_processors) {
  300. strcpy(io_buffer, message(MSG_INVCPU, id));
  301. return;
  302. }
  303. strcpy(io_buffer, message(MSG_CPUDEV, id));
  304. cpustatus(id);
  305. }
  306. void poolstatus(char *params)
  307. {
  308. char buf[BUFSIZ];
  309. char *status, *lp;
  310. int i;
  311. if (total_pools == 0) {
  312. strcpy(io_buffer, message(MSG_NOPOOL, 0));
  313. return;
  314. }
  315. strcpy(io_buffer, message(MSG_POOL, 0));
  316. for (i = 0; i < total_pools; i++) {
  317. struct pool *pool = pools[i];
  318. if (!pool->enabled)
  319. status = (char *)DISABLED;
  320. else
  321. {
  322. if (pool->idle)
  323. status = (char *)DEAD;
  324. else
  325. status = (char *)ALIVE;
  326. }
  327. if (pool->hdr_path)
  328. lp = (char *)YES;
  329. else
  330. lp = (char *)NO;
  331. sprintf(buf, "POOL=%d,URL=%s,STA=%s,PRI=%d,LP=%s,Q=%d,A=%d,R=%d,DW=%d,ST=%d,GF=%d,RF=%d%c",
  332. i, pool->rpc_url, status, pool->prio, lp,
  333. pool->getwork_requested,
  334. pool->accepted, pool->rejected,
  335. pool->discarded_work,
  336. pool->stale_shares,
  337. pool->getfail_occasions,
  338. pool->remotefail_occasions, SEPARATOR);
  339. strcat(io_buffer, buf);
  340. }
  341. }
  342. void summary(char *params)
  343. {
  344. double utility, mhs;
  345. char *algo = (char *)(algo_names[opt_algo]);
  346. if (algo == NULL)
  347. algo = "(null)";
  348. utility = total_accepted / ( total_secs ? total_secs : 1 ) * 60;
  349. mhs = total_mhashes_done / total_secs;
  350. sprintf(io_buffer, "%sSUMMARY=all,EL=%.0f,ALGO=%s,MHS=%.2f,SOL=%d,Q=%d,A=%d,R=%d,HW=%d,U=%.2f,DW=%d,ST=%d,GF=%d,LW=%u,RO=%u,BC=%u%c",
  351. message(MSG_SUMM, 0),
  352. total_secs, algo, mhs, found_blocks,
  353. total_getworks, total_accepted, total_rejected,
  354. hw_errors, utility, total_discarded, total_stale,
  355. total_go, local_work, total_ro, new_blocks, SEPARATOR);
  356. }
  357. void gpuenable(char *params)
  358. {
  359. struct thr_info *thr;
  360. int gpu;
  361. int id;
  362. int i;
  363. if (gpu_threads == 0) {
  364. strcpy(io_buffer, message(MSG_GPUNON, 0));
  365. return;
  366. }
  367. if (*params == '\0') {
  368. strcpy(io_buffer, message(MSG_MISID, 0));
  369. return;
  370. }
  371. id = atoi(params);
  372. if (id < 0 || id >= nDevs) {
  373. strcpy(io_buffer, message(MSG_INVGPU, id));
  374. return;
  375. }
  376. if (gpu_devices[id]) {
  377. strcpy(io_buffer, message(MSG_ALRENA, id));
  378. return;
  379. }
  380. for (i = 0; i < gpu_threads; i++) {
  381. gpu = thr_info[i].cgpu->cpu_gpu;
  382. if (gpu == id) {
  383. thr = &thr_info[i];
  384. if (thr->cgpu->status != LIFE_WELL) {
  385. strcpy(io_buffer, message(MSG_GPUMRE, id));
  386. return;
  387. }
  388. gpu_devices[id] = true;
  389. tq_push(thr->q, &ping);
  390. }
  391. }
  392. strcpy(io_buffer, message(MSG_GPUREN, id));
  393. }
  394. void gpudisable(char *params)
  395. {
  396. int id;
  397. if (nDevs == 0) {
  398. strcpy(io_buffer, message(MSG_GPUNON, 0));
  399. return;
  400. }
  401. if (*params == '\0') {
  402. strcpy(io_buffer, message(MSG_MISID, 0));
  403. return;
  404. }
  405. id = atoi(params);
  406. if (id < 0 || id >= nDevs) {
  407. strcpy(io_buffer, message(MSG_INVGPU, id));
  408. return;
  409. }
  410. if (!gpu_devices[id]) {
  411. strcpy(io_buffer, message(MSG_ALRDIS, id));
  412. return;
  413. }
  414. gpu_devices[id] = false;
  415. strcpy(io_buffer, message(MSG_GPUDIS, id));
  416. }
  417. void gpurestart(char *params)
  418. {
  419. int id;
  420. if (nDevs == 0) {
  421. strcpy(io_buffer, message(MSG_GPUNON, 0));
  422. return;
  423. }
  424. if (*params == '\0') {
  425. strcpy(io_buffer, message(MSG_MISID, 0));
  426. return;
  427. }
  428. id = atoi(params);
  429. if (id < 0 || id >= nDevs) {
  430. strcpy(io_buffer, message(MSG_INVGPU, id));
  431. return;
  432. }
  433. reinit_device(&gpus[id]);
  434. strcpy(io_buffer, message(MSG_GPUREI, id));
  435. }
  436. void gpucount(char *params)
  437. {
  438. char buf[BUFSIZ];
  439. strcpy(io_buffer, message(MSG_NUMGPU, 0));
  440. sprintf(buf, "GPUS,COUNT=%d|", nDevs);
  441. strcat(io_buffer, buf);
  442. }
  443. void cpucount(char *params)
  444. {
  445. char buf[BUFSIZ];
  446. strcpy(io_buffer, message(MSG_NUMCPU, 0));
  447. sprintf(buf, "CPUS,COUNT=%d|", opt_n_threads > 0 ? num_processors : 0);
  448. strcat(io_buffer, buf);
  449. }
  450. void doquit(char *params)
  451. {
  452. *io_buffer = '\0';
  453. bye = 1;
  454. kill_work();
  455. }
  456. struct CMDS {
  457. char *name;
  458. void (*func)(char *);
  459. } cmds[] = {
  460. { "apiversion", apiversion },
  461. { "devs", devstatus },
  462. { "pools", poolstatus },
  463. { "summary", summary },
  464. { "gpuenable", gpuenable },
  465. { "gpudisable", gpudisable },
  466. { "gpurestart", gpurestart },
  467. { "gpu", gpudev },
  468. { "cpu", cpudev },
  469. { "gpucount", gpucount },
  470. { "cpucount", cpucount },
  471. { "quit", doquit },
  472. { NULL }
  473. };
  474. void send_result(SOCKETTYPE c)
  475. {
  476. int n;
  477. // ignore failure - it's closed immediately anyway
  478. n = send(c, io_buffer, strlen(io_buffer)+1, 0);
  479. }
  480. void tidyup()
  481. {
  482. bye = 1;
  483. if (sock != INVSOCK) {
  484. shutdown(sock, SHUT_RDWR);
  485. CLOSESOCKET(sock);
  486. sock = INVSOCK;
  487. }
  488. if (msg_buffer != NULL) {
  489. free(msg_buffer);
  490. msg_buffer = NULL;
  491. }
  492. if (io_buffer != NULL) {
  493. free(io_buffer);
  494. io_buffer = NULL;
  495. }
  496. }
  497. void api(void)
  498. {
  499. char buf[BUFSIZ];
  500. const char *localaddr = "127.0.0.1";
  501. SOCKETTYPE c;
  502. int n, bound;
  503. char connectaddr[32];
  504. char *binderror;
  505. time_t bindstart;
  506. short int port = opt_api_port;
  507. struct sockaddr_in serv;
  508. struct sockaddr_in cli;
  509. socklen_t clisiz;
  510. char *params;
  511. bool addrok;
  512. bool did;
  513. int i;
  514. sock = socket(AF_INET, SOCK_STREAM, 0);
  515. if (sock == INVSOCK) {
  516. applog(LOG_ERR, "API1 initialisation failed (%s)%s", strerror(errno), UNAVAILABLE);
  517. return;
  518. }
  519. memset(&serv, 0, sizeof(serv));
  520. serv.sin_family = AF_INET;
  521. if (!opt_api_listen) {
  522. if (inet_pton(AF_INET, localaddr, &(serv.sin_addr)) == 0) {
  523. applog(LOG_ERR, "API2 initialisation failed (%s)%s", strerror(errno), UNAVAILABLE);
  524. return;
  525. }
  526. }
  527. serv.sin_port = htons(port);
  528. // try for 1 minute ... in case the old one hasn't completely gone yet
  529. bound = 0;
  530. bindstart = time(NULL);
  531. while (bound == 0) {
  532. if (bind(sock, (struct sockaddr *)(&serv), sizeof(serv)) BINDERROR) {
  533. binderror = strerror(errno);
  534. if ((time(NULL) - bindstart) > 61)
  535. break;
  536. else {
  537. applog(LOG_WARNING, "API bind to port %d failed - trying again in 15sec", port);
  538. sleep(15);
  539. }
  540. }
  541. else
  542. bound = 1;
  543. }
  544. if (bound == 0) {
  545. applog(LOG_ERR, "API bind to port %d failed (%s)%s", port, binderror, UNAVAILABLE);
  546. return;
  547. }
  548. if (listen(sock, QUEUE) LISTENERROR) {
  549. applog(LOG_ERR, "API3 initialisation failed (%s)%s", strerror(errno), UNAVAILABLE);
  550. CLOSESOCKET(sock);
  551. return;
  552. }
  553. sleep(opt_log_interval);
  554. if (opt_api_listen)
  555. applog(LOG_WARNING, "API running in UNRESTRICTED access mode");
  556. else
  557. applog(LOG_WARNING, "API running in restricted access mode");
  558. io_buffer = malloc(MYBUFSIZ+1);
  559. msg_buffer = malloc(MYBUFSIZ+1);
  560. while (bye == 0) {
  561. clisiz = sizeof(cli);
  562. if ((c = accept(sock, (struct sockaddr *)(&cli), &clisiz)) ACCEPTERROR) {
  563. applog(LOG_ERR, "API failed (%s)%s", strerror(errno), UNAVAILABLE);
  564. goto die;
  565. }
  566. if (opt_api_listen)
  567. addrok = true;
  568. else {
  569. inet_ntop(AF_INET, &(cli.sin_addr), &(connectaddr[0]), sizeof(connectaddr)-1);
  570. addrok = (strcmp(connectaddr, localaddr) == 0);
  571. }
  572. if (addrok) {
  573. n = recv(c, &buf[0], BUFSIZ-1, 0);
  574. if (n >= 0) {
  575. did = false;
  576. buf[n] = '\0';
  577. params = strchr(buf, SEPARATOR);
  578. if (params == NULL)
  579. params = (char *)BLANK;
  580. else
  581. *(params++) = '\0';
  582. for (i = 0; cmds[i].name != NULL; i++) {
  583. if (strcmp(buf, cmds[i].name) == 0) {
  584. (cmds[i].func)(params);
  585. send_result(c);
  586. did = true;
  587. break;
  588. }
  589. }
  590. if (!did) {
  591. strcpy(io_buffer, message(MSG_INVCMD, 0));
  592. send_result(c);
  593. }
  594. }
  595. }
  596. CLOSESOCKET(c);
  597. }
  598. die:
  599. tidyup();
  600. }