You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

842 lines
20 KiB

  1. /***************************************************************************
  2. * Copyright (C) 2005 by Dominic Rath *
  3. * Dominic.Rath@gmx.de *
  4. * *
  5. * Copyright (C) 2007-2010 Øyvind Harboe *
  6. * oyvind.harboe@zylin.com *
  7. * *
  8. * Copyright (C) 2008 by Spencer Oliver *
  9. * spen@spen-soft.co.uk *
  10. * *
  11. * This program is free software; you can redistribute it and/or modify *
  12. * it under the terms of the GNU General Public License as published by *
  13. * the Free Software Foundation; either version 2 of the License, or *
  14. * (at your option) any later version. *
  15. * *
  16. * This program is distributed in the hope that it will be useful, *
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  19. * GNU General Public License for more details. *
  20. * *
  21. * You should have received a copy of the GNU General Public License *
  22. * along with this program. If not, see <http://www.gnu.org/licenses/>. *
  23. ***************************************************************************/
  24. #ifdef HAVE_CONFIG_H
  25. #include "config.h"
  26. #endif
  27. #include "server.h"
  28. #include <target/target.h>
  29. #include <target/target_request.h>
  30. #include <target/openrisc/jsp_server.h>
  31. #include "openocd.h"
  32. #include "tcl_server.h"
  33. #include "telnet_server.h"
  34. #include <signal.h>
  35. #ifdef HAVE_NETDB_H
  36. #include <netdb.h>
  37. #endif
  38. #ifndef _WIN32
  39. #include <netinet/tcp.h>
  40. #endif
  41. static struct service *services;
  42. /* shutdown_openocd == 1: exit the main event loop, and quit the
  43. * debugger; 2: quit with non-zero return code */
  44. static int shutdown_openocd;
  45. /* store received signal to exit application by killing ourselves */
  46. static int last_signal;
  47. /* set the polling period to 100ms */
  48. static int polling_period = 100;
  49. /* address by name on which to listen for incoming TCP/IP connections */
  50. static char *bindto_name;
  51. static int add_connection(struct service *service, struct command_context *cmd_ctx)
  52. {
  53. socklen_t address_size;
  54. struct connection *c, **p;
  55. int retval;
  56. int flag = 1;
  57. c = malloc(sizeof(struct connection));
  58. if (!c) {
  59. LOG_ERROR("Failed to allocate connection.");
  60. return ERROR_FAIL;
  61. }
  62. c->cmd_ctx = copy_command_context(cmd_ctx);
  63. if (!c->cmd_ctx) {
  64. LOG_ERROR("Failed to copy command context.");
  65. free(c);
  66. return ERROR_FAIL;
  67. }
  68. c->fd = -1;
  69. c->fd_out = -1;
  70. memset(&c->sin, 0, sizeof(c->sin));
  71. c->service = service;
  72. c->input_pending = 0;
  73. c->priv = NULL;
  74. c->next = NULL;
  75. if (service->type == CONNECTION_TCP) {
  76. address_size = sizeof(c->sin);
  77. c->fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size);
  78. c->fd_out = c->fd;
  79. /* This increases performance dramatically for e.g. GDB load which
  80. * does not have a sliding window protocol.
  81. *
  82. * Ignore errors from this fn as it probably just means less performance
  83. */
  84. setsockopt(c->fd, /* socket affected */
  85. IPPROTO_TCP, /* set option at TCP level */
  86. TCP_NODELAY, /* name of option */
  87. (char *)&flag, /* the cast is historical cruft */
  88. sizeof(int)); /* length of option value */
  89. LOG_INFO("accepting '%s' connection on tcp/%s", service->name, service->port);
  90. retval = service->new_connection(c);
  91. if (retval != ERROR_OK) {
  92. close_socket(c->fd);
  93. LOG_ERROR("attempted '%s' connection rejected", service->name);
  94. command_done(c->cmd_ctx);
  95. free(c);
  96. return retval;
  97. }
  98. } else if (service->type == CONNECTION_STDINOUT) {
  99. c->fd = service->fd;
  100. c->fd_out = fileno(stdout);
  101. #ifdef _WIN32
  102. /* we are using stdin/out so ignore ctrl-c under windoze */
  103. SetConsoleCtrlHandler(NULL, TRUE);
  104. #endif
  105. /* do not check for new connections again on stdin */
  106. service->fd = -1;
  107. LOG_INFO("accepting '%s' connection from pipe", service->name);
  108. retval = service->new_connection(c);
  109. if (retval != ERROR_OK) {
  110. LOG_ERROR("attempted '%s' connection rejected", service->name);
  111. command_done(c->cmd_ctx);
  112. free(c);
  113. return retval;
  114. }
  115. } else if (service->type == CONNECTION_PIPE) {
  116. c->fd = service->fd;
  117. /* do not check for new connections again on stdin */
  118. service->fd = -1;
  119. char *out_file = alloc_printf("%so", service->port);
  120. c->fd_out = open(out_file, O_WRONLY);
  121. free(out_file);
  122. if (c->fd_out == -1) {
  123. LOG_ERROR("could not open %s", service->port);
  124. command_done(c->cmd_ctx);
  125. free(c);
  126. return ERROR_FAIL;
  127. }
  128. LOG_INFO("accepting '%s' connection from pipe %s", service->name, service->port);
  129. retval = service->new_connection(c);
  130. if (retval != ERROR_OK) {
  131. LOG_ERROR("attempted '%s' connection rejected", service->name);
  132. command_done(c->cmd_ctx);
  133. free(c);
  134. return retval;
  135. }
  136. }
  137. /* add to the end of linked list */
  138. for (p = &service->connections; *p; p = &(*p)->next)
  139. ;
  140. *p = c;
  141. if (service->max_connections != CONNECTION_LIMIT_UNLIMITED)
  142. service->max_connections--;
  143. return ERROR_OK;
  144. }
  145. static int remove_connection(struct service *service, struct connection *connection)
  146. {
  147. struct connection **p = &service->connections;
  148. struct connection *c;
  149. /* find connection */
  150. while ((c = *p)) {
  151. if (c->fd == connection->fd) {
  152. service->connection_closed(c);
  153. if (service->type == CONNECTION_TCP)
  154. close_socket(c->fd);
  155. else if (service->type == CONNECTION_PIPE) {
  156. /* The service will listen to the pipe again */
  157. c->service->fd = c->fd;
  158. }
  159. command_done(c->cmd_ctx);
  160. /* delete connection */
  161. *p = c->next;
  162. free(c);
  163. if (service->max_connections != CONNECTION_LIMIT_UNLIMITED)
  164. service->max_connections++;
  165. break;
  166. }
  167. /* redirect p to next list pointer */
  168. p = &(*p)->next;
  169. }
  170. return ERROR_OK;
  171. }
  172. static void free_service(struct service *c)
  173. {
  174. free(c->name);
  175. free(c->port);
  176. free(c);
  177. }
  178. int add_service(char *name,
  179. const char *port,
  180. int max_connections,
  181. new_connection_handler_t new_connection_handler,
  182. input_handler_t input_handler,
  183. connection_closed_handler_t connection_closed_handler,
  184. void *priv)
  185. {
  186. struct service *c, **p;
  187. struct hostent *hp;
  188. int so_reuseaddr_option = 1;
  189. c = malloc(sizeof(struct service));
  190. c->name = strdup(name);
  191. c->port = strdup(port);
  192. c->max_connections = 1; /* Only TCP/IP ports can support more than one connection */
  193. c->fd = -1;
  194. c->connections = NULL;
  195. c->new_connection = new_connection_handler;
  196. c->input = input_handler;
  197. c->connection_closed = connection_closed_handler;
  198. c->priv = priv;
  199. c->next = NULL;
  200. long portnumber;
  201. if (strcmp(c->port, "pipe") == 0)
  202. c->type = CONNECTION_STDINOUT;
  203. else {
  204. char *end;
  205. portnumber = strtol(c->port, &end, 0);
  206. if (!*end && (parse_long(c->port, &portnumber) == ERROR_OK)) {
  207. c->portnumber = portnumber;
  208. c->type = CONNECTION_TCP;
  209. } else
  210. c->type = CONNECTION_PIPE;
  211. }
  212. if (c->type == CONNECTION_TCP) {
  213. c->max_connections = max_connections;
  214. c->fd = socket(AF_INET, SOCK_STREAM, 0);
  215. if (c->fd == -1) {
  216. LOG_ERROR("error creating socket: %s", strerror(errno));
  217. free_service(c);
  218. return ERROR_FAIL;
  219. }
  220. setsockopt(c->fd,
  221. SOL_SOCKET,
  222. SO_REUSEADDR,
  223. (void *)&so_reuseaddr_option,
  224. sizeof(int));
  225. socket_nonblock(c->fd);
  226. memset(&c->sin, 0, sizeof(c->sin));
  227. c->sin.sin_family = AF_INET;
  228. if (bindto_name == NULL)
  229. c->sin.sin_addr.s_addr = INADDR_ANY;
  230. else {
  231. hp = gethostbyname(bindto_name);
  232. if (hp == NULL) {
  233. LOG_ERROR("couldn't resolve bindto address: %s", bindto_name);
  234. close_socket(c->fd);
  235. free_service(c);
  236. return ERROR_FAIL;
  237. }
  238. memcpy(&c->sin.sin_addr, hp->h_addr_list[0], hp->h_length);
  239. }
  240. c->sin.sin_port = htons(c->portnumber);
  241. if (bind(c->fd, (struct sockaddr *)&c->sin, sizeof(c->sin)) == -1) {
  242. LOG_ERROR("couldn't bind %s to socket: %s", name, strerror(errno));
  243. close_socket(c->fd);
  244. free_service(c);
  245. return ERROR_FAIL;
  246. }
  247. #ifndef _WIN32
  248. int segsize = 65536;
  249. setsockopt(c->fd, IPPROTO_TCP, TCP_MAXSEG, &segsize, sizeof(int));
  250. #endif
  251. int window_size = 128 * 1024;
  252. /* These setsockopt()s must happen before the listen() */
  253. setsockopt(c->fd, SOL_SOCKET, SO_SNDBUF,
  254. (char *)&window_size, sizeof(window_size));
  255. setsockopt(c->fd, SOL_SOCKET, SO_RCVBUF,
  256. (char *)&window_size, sizeof(window_size));
  257. if (listen(c->fd, 1) == -1) {
  258. LOG_ERROR("couldn't listen on socket: %s", strerror(errno));
  259. close_socket(c->fd);
  260. free_service(c);
  261. return ERROR_FAIL;
  262. }
  263. } else if (c->type == CONNECTION_STDINOUT) {
  264. c->fd = fileno(stdin);
  265. #ifdef _WIN32
  266. /* for win32 set stdin/stdout to binary mode */
  267. if (_setmode(_fileno(stdout), _O_BINARY) < 0)
  268. LOG_WARNING("cannot change stdout mode to binary");
  269. if (_setmode(_fileno(stdin), _O_BINARY) < 0)
  270. LOG_WARNING("cannot change stdin mode to binary");
  271. if (_setmode(_fileno(stderr), _O_BINARY) < 0)
  272. LOG_WARNING("cannot change stderr mode to binary");
  273. #else
  274. socket_nonblock(c->fd);
  275. #endif
  276. } else if (c->type == CONNECTION_PIPE) {
  277. #ifdef _WIN32
  278. /* we currenty do not support named pipes under win32
  279. * so exit openocd for now */
  280. LOG_ERROR("Named pipes currently not supported under this os");
  281. free_service(c);
  282. return ERROR_FAIL;
  283. #else
  284. /* Pipe we're reading from */
  285. c->fd = open(c->port, O_RDONLY | O_NONBLOCK);
  286. if (c->fd == -1) {
  287. LOG_ERROR("could not open %s", c->port);
  288. free_service(c);
  289. return ERROR_FAIL;
  290. }
  291. #endif
  292. }
  293. /* add to the end of linked list */
  294. for (p = &services; *p; p = &(*p)->next)
  295. ;
  296. *p = c;
  297. return ERROR_OK;
  298. }
  299. static void remove_connections(struct service *service)
  300. {
  301. struct connection *connection;
  302. connection = service->connections;
  303. while (connection) {
  304. struct connection *tmp;
  305. tmp = connection->next;
  306. remove_connection(service, connection);
  307. connection = tmp;
  308. }
  309. }
  310. int remove_service(const char *name, const char *port)
  311. {
  312. struct service *tmp;
  313. struct service *prev;
  314. prev = services;
  315. for (tmp = services; tmp; prev = tmp, tmp = tmp->next) {
  316. if (!strcmp(tmp->name, name) && !strcmp(tmp->port, port)) {
  317. remove_connections(tmp);
  318. if (tmp == services)
  319. services = tmp->next;
  320. else
  321. prev->next = tmp->next;
  322. if (tmp->type != CONNECTION_STDINOUT)
  323. close_socket(tmp->fd);
  324. free(tmp->priv);
  325. free_service(tmp);
  326. return ERROR_OK;
  327. }
  328. }
  329. return ERROR_OK;
  330. }
  331. static int remove_services(void)
  332. {
  333. struct service *c = services;
  334. /* loop service */
  335. while (c) {
  336. struct service *next = c->next;
  337. remove_connections(c);
  338. if (c->name)
  339. free(c->name);
  340. if (c->type == CONNECTION_PIPE) {
  341. if (c->fd != -1)
  342. close(c->fd);
  343. }
  344. if (c->port)
  345. free(c->port);
  346. if (c->priv)
  347. free(c->priv);
  348. /* delete service */
  349. free(c);
  350. /* remember the last service for unlinking */
  351. c = next;
  352. }
  353. services = NULL;
  354. return ERROR_OK;
  355. }
  356. int server_loop(struct command_context *command_context)
  357. {
  358. struct service *service;
  359. bool poll_ok = true;
  360. /* used in select() */
  361. fd_set read_fds;
  362. int fd_max;
  363. /* used in accept() */
  364. int retval;
  365. #ifndef _WIN32
  366. if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
  367. LOG_ERROR("couldn't set SIGPIPE to SIG_IGN");
  368. #endif
  369. while (!shutdown_openocd) {
  370. /* monitor sockets for activity */
  371. fd_max = 0;
  372. FD_ZERO(&read_fds);
  373. /* add service and connection fds to read_fds */
  374. for (service = services; service; service = service->next) {
  375. if (service->fd != -1) {
  376. /* listen for new connections */
  377. FD_SET(service->fd, &read_fds);
  378. if (service->fd > fd_max)
  379. fd_max = service->fd;
  380. }
  381. if (service->connections) {
  382. struct connection *c;
  383. for (c = service->connections; c; c = c->next) {
  384. /* check for activity on the connection */
  385. FD_SET(c->fd, &read_fds);
  386. if (c->fd > fd_max)
  387. fd_max = c->fd;
  388. }
  389. }
  390. }
  391. struct timeval tv;
  392. tv.tv_sec = 0;
  393. if (poll_ok) {
  394. /* we're just polling this iteration, this is faster on embedded
  395. * hosts */
  396. tv.tv_usec = 0;
  397. retval = socket_select(fd_max + 1, &read_fds, NULL, NULL, &tv);
  398. } else {
  399. /* Every 100ms, can be changed with "poll_period" command */
  400. tv.tv_usec = polling_period * 1000;
  401. /* Only while we're sleeping we'll let others run */
  402. openocd_sleep_prelude();
  403. kept_alive();
  404. retval = socket_select(fd_max + 1, &read_fds, NULL, NULL, &tv);
  405. openocd_sleep_postlude();
  406. }
  407. if (retval == -1) {
  408. #ifdef _WIN32
  409. errno = WSAGetLastError();
  410. if (errno == WSAEINTR)
  411. FD_ZERO(&read_fds);
  412. else {
  413. LOG_ERROR("error during select: %s", strerror(errno));
  414. return ERROR_FAIL;
  415. }
  416. #else
  417. if (errno == EINTR)
  418. FD_ZERO(&read_fds);
  419. else {
  420. LOG_ERROR("error during select: %s", strerror(errno));
  421. return ERROR_FAIL;
  422. }
  423. #endif
  424. }
  425. if (retval == 0) {
  426. /* We only execute these callbacks when there was nothing to do or we timed
  427. *out */
  428. target_call_timer_callbacks();
  429. process_jim_events(command_context);
  430. FD_ZERO(&read_fds); /* eCos leaves read_fds unchanged in this case! */
  431. /* We timed out/there was nothing to do, timeout rather than poll next time
  432. **/
  433. poll_ok = false;
  434. } else {
  435. /* There was something to do, next time we'll just poll */
  436. poll_ok = true;
  437. }
  438. /* This is a simple back-off algorithm where we immediately
  439. * re-poll if we did something this time around.
  440. *
  441. * This greatly improves performance of DCC.
  442. */
  443. poll_ok = poll_ok || target_got_message();
  444. for (service = services; service; service = service->next) {
  445. /* handle new connections on listeners */
  446. if ((service->fd != -1) && (FD_ISSET(service->fd, &read_fds))) {
  447. if (service->max_connections != 0) {
  448. retval = add_connection(service, command_context);
  449. if (retval != ERROR_OK) {
  450. LOG_ERROR("%i", retval);
  451. return ERROR_FAIL;
  452. }
  453. } else {
  454. if (service->type == CONNECTION_TCP) {
  455. struct sockaddr_in sin;
  456. socklen_t address_size = sizeof(sin);
  457. int tmp_fd;
  458. tmp_fd = accept(service->fd,
  459. (struct sockaddr *)&service->sin,
  460. &address_size);
  461. close_socket(tmp_fd);
  462. }
  463. LOG_INFO(
  464. "rejected '%s' connection, no more connections allowed",
  465. service->name);
  466. }
  467. }
  468. /* handle activity on connections */
  469. if (service->connections) {
  470. struct connection *c;
  471. for (c = service->connections; c; ) {
  472. if ((FD_ISSET(c->fd, &read_fds)) || c->input_pending) {
  473. retval = service->input(c);
  474. if (retval != ERROR_OK) {
  475. struct connection *next = c->next;
  476. if (service->type == CONNECTION_PIPE ||
  477. service->type == CONNECTION_STDINOUT) {
  478. /* if connection uses a pipe then
  479. * shutdown openocd on error */
  480. shutdown_openocd = 1;
  481. }
  482. remove_connection(service, c);
  483. LOG_INFO("dropped '%s' connection",
  484. service->name);
  485. c = next;
  486. continue;
  487. }
  488. }
  489. c = c->next;
  490. }
  491. }
  492. }
  493. #ifdef _WIN32
  494. MSG msg;
  495. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
  496. if (msg.message == WM_QUIT)
  497. shutdown_openocd = 1;
  498. }
  499. #endif
  500. }
  501. return shutdown_openocd != 2 ? ERROR_OK : ERROR_FAIL;
  502. }
  503. #ifdef _WIN32
  504. BOOL WINAPI ControlHandler(DWORD dwCtrlType)
  505. {
  506. shutdown_openocd = 1;
  507. return TRUE;
  508. }
  509. #endif
  510. void sig_handler(int sig)
  511. {
  512. /* store only first signal that hits us */
  513. if (!last_signal)
  514. last_signal = sig;
  515. shutdown_openocd = 1;
  516. }
  517. int server_preinit(void)
  518. {
  519. /* this currently only calls WSAStartup on native win32 systems
  520. * before any socket operations are performed.
  521. * This is an issue if you call init in your config script */
  522. #ifdef _WIN32
  523. WORD wVersionRequested;
  524. WSADATA wsaData;
  525. wVersionRequested = MAKEWORD(2, 2);
  526. if (WSAStartup(wVersionRequested, &wsaData) != 0) {
  527. LOG_ERROR("Failed to Open Winsock");
  528. return ERROR_FAIL;
  529. }
  530. /* register ctrl-c handler */
  531. SetConsoleCtrlHandler(ControlHandler, TRUE);
  532. signal(SIGBREAK, sig_handler);
  533. #endif
  534. signal(SIGINT, sig_handler);
  535. signal(SIGTERM, sig_handler);
  536. signal(SIGABRT, sig_handler);
  537. return ERROR_OK;
  538. }
  539. int server_init(struct command_context *cmd_ctx)
  540. {
  541. int ret;
  542. ret = tcl_init();
  543. if (ret != ERROR_OK)
  544. return ret;
  545. ret = telnet_init("Open On-Chip Debugger");
  546. if (ret != ERROR_OK) {
  547. remove_services();
  548. return ret;
  549. }
  550. return ERROR_OK;
  551. }
  552. int server_quit(void)
  553. {
  554. remove_services();
  555. target_quit();
  556. #ifdef _WIN32
  557. WSACleanup();
  558. SetConsoleCtrlHandler(ControlHandler, FALSE);
  559. return ERROR_OK;
  560. #endif
  561. /* return signal number so we can kill ourselves */
  562. return last_signal;
  563. }
  564. void exit_on_signal(int sig)
  565. {
  566. #ifndef _WIN32
  567. /* bring back default system handler and kill yourself */
  568. signal(sig, SIG_DFL);
  569. kill(getpid(), sig);
  570. #endif
  571. }
  572. int connection_write(struct connection *connection, const void *data, int len)
  573. {
  574. if (len == 0) {
  575. /* successful no-op. Sockets and pipes behave differently here... */
  576. return 0;
  577. }
  578. if (connection->service->type == CONNECTION_TCP)
  579. return write_socket(connection->fd_out, data, len);
  580. else
  581. return write(connection->fd_out, data, len);
  582. }
  583. int connection_read(struct connection *connection, void *data, int len)
  584. {
  585. if (connection->service->type == CONNECTION_TCP)
  586. return read_socket(connection->fd, data, len);
  587. else
  588. return read(connection->fd, data, len);
  589. }
  590. /* tell the server we want to shut down */
  591. COMMAND_HANDLER(handle_shutdown_command)
  592. {
  593. LOG_USER("shutdown command invoked");
  594. shutdown_openocd = 1;
  595. if (CMD_ARGC == 1) {
  596. if (!strcmp(CMD_ARGV[0], "error")) {
  597. shutdown_openocd = 2;
  598. return ERROR_FAIL;
  599. }
  600. }
  601. return ERROR_COMMAND_CLOSE_CONNECTION;
  602. }
  603. COMMAND_HANDLER(handle_poll_period_command)
  604. {
  605. if (CMD_ARGC == 0)
  606. LOG_WARNING("You need to set a period value");
  607. else
  608. COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], polling_period);
  609. LOG_INFO("set servers polling period to %ums", polling_period);
  610. return ERROR_OK;
  611. }
  612. COMMAND_HANDLER(handle_bindto_command)
  613. {
  614. switch (CMD_ARGC) {
  615. case 0:
  616. command_print(CMD_CTX, "bindto name: %s", bindto_name);
  617. break;
  618. case 1:
  619. free(bindto_name);
  620. bindto_name = strdup(CMD_ARGV[0]);
  621. break;
  622. default:
  623. return ERROR_COMMAND_SYNTAX_ERROR;
  624. }
  625. return ERROR_OK;
  626. }
  627. static const struct command_registration server_command_handlers[] = {
  628. {
  629. .name = "shutdown",
  630. .handler = &handle_shutdown_command,
  631. .mode = COMMAND_ANY,
  632. .usage = "",
  633. .help = "shut the server down",
  634. },
  635. {
  636. .name = "poll_period",
  637. .handler = &handle_poll_period_command,
  638. .mode = COMMAND_ANY,
  639. .usage = "",
  640. .help = "set the servers polling period",
  641. },
  642. {
  643. .name = "bindto",
  644. .handler = &handle_bindto_command,
  645. .mode = COMMAND_ANY,
  646. .usage = "[name]",
  647. .help = "Specify address by name on which to listen for "
  648. "incoming TCP/IP connections",
  649. },
  650. COMMAND_REGISTRATION_DONE
  651. };
  652. int server_register_commands(struct command_context *cmd_ctx)
  653. {
  654. int retval = telnet_register_commands(cmd_ctx);
  655. if (ERROR_OK != retval)
  656. return retval;
  657. retval = tcl_register_commands(cmd_ctx);
  658. if (ERROR_OK != retval)
  659. return retval;
  660. retval = jsp_register_commands(cmd_ctx);
  661. if (ERROR_OK != retval)
  662. return retval;
  663. return register_commands(cmd_ctx, NULL, server_command_handlers);
  664. }
  665. COMMAND_HELPER(server_port_command, unsigned short *out)
  666. {
  667. switch (CMD_ARGC) {
  668. case 0:
  669. command_print(CMD_CTX, "%d", *out);
  670. break;
  671. case 1:
  672. {
  673. uint16_t port;
  674. COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], port);
  675. *out = port;
  676. break;
  677. }
  678. default:
  679. return ERROR_COMMAND_SYNTAX_ERROR;
  680. }
  681. return ERROR_OK;
  682. }
  683. COMMAND_HELPER(server_pipe_command, char **out)
  684. {
  685. switch (CMD_ARGC) {
  686. case 0:
  687. command_print(CMD_CTX, "%s", *out);
  688. break;
  689. case 1:
  690. {
  691. if (CMD_CTX->mode == COMMAND_EXEC) {
  692. LOG_WARNING("unable to change server port after init");
  693. return ERROR_COMMAND_ARGUMENT_INVALID;
  694. }
  695. free(*out);
  696. *out = strdup(CMD_ARGV[0]);
  697. break;
  698. }
  699. default:
  700. return ERROR_COMMAND_SYNTAX_ERROR;
  701. }
  702. return ERROR_OK;
  703. }