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.
 
 
 
 
 
 

813 lines
19 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. static int remove_services(void)
  311. {
  312. struct service *c = services;
  313. /* loop service */
  314. while (c) {
  315. struct service *next = c->next;
  316. remove_connections(c);
  317. if (c->name)
  318. free(c->name);
  319. if (c->type == CONNECTION_PIPE) {
  320. if (c->fd != -1)
  321. close(c->fd);
  322. }
  323. if (c->port)
  324. free(c->port);
  325. if (c->priv)
  326. free(c->priv);
  327. /* delete service */
  328. free(c);
  329. /* remember the last service for unlinking */
  330. c = next;
  331. }
  332. services = NULL;
  333. return ERROR_OK;
  334. }
  335. int server_loop(struct command_context *command_context)
  336. {
  337. struct service *service;
  338. bool poll_ok = true;
  339. /* used in select() */
  340. fd_set read_fds;
  341. int fd_max;
  342. /* used in accept() */
  343. int retval;
  344. #ifndef _WIN32
  345. if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
  346. LOG_ERROR("couldn't set SIGPIPE to SIG_IGN");
  347. #endif
  348. while (!shutdown_openocd) {
  349. /* monitor sockets for activity */
  350. fd_max = 0;
  351. FD_ZERO(&read_fds);
  352. /* add service and connection fds to read_fds */
  353. for (service = services; service; service = service->next) {
  354. if (service->fd != -1) {
  355. /* listen for new connections */
  356. FD_SET(service->fd, &read_fds);
  357. if (service->fd > fd_max)
  358. fd_max = service->fd;
  359. }
  360. if (service->connections) {
  361. struct connection *c;
  362. for (c = service->connections; c; c = c->next) {
  363. /* check for activity on the connection */
  364. FD_SET(c->fd, &read_fds);
  365. if (c->fd > fd_max)
  366. fd_max = c->fd;
  367. }
  368. }
  369. }
  370. struct timeval tv;
  371. tv.tv_sec = 0;
  372. if (poll_ok) {
  373. /* we're just polling this iteration, this is faster on embedded
  374. * hosts */
  375. tv.tv_usec = 0;
  376. retval = socket_select(fd_max + 1, &read_fds, NULL, NULL, &tv);
  377. } else {
  378. /* Every 100ms, can be changed with "poll_period" command */
  379. tv.tv_usec = polling_period * 1000;
  380. /* Only while we're sleeping we'll let others run */
  381. openocd_sleep_prelude();
  382. kept_alive();
  383. retval = socket_select(fd_max + 1, &read_fds, NULL, NULL, &tv);
  384. openocd_sleep_postlude();
  385. }
  386. if (retval == -1) {
  387. #ifdef _WIN32
  388. errno = WSAGetLastError();
  389. if (errno == WSAEINTR)
  390. FD_ZERO(&read_fds);
  391. else {
  392. LOG_ERROR("error during select: %s", strerror(errno));
  393. return ERROR_FAIL;
  394. }
  395. #else
  396. if (errno == EINTR)
  397. FD_ZERO(&read_fds);
  398. else {
  399. LOG_ERROR("error during select: %s", strerror(errno));
  400. return ERROR_FAIL;
  401. }
  402. #endif
  403. }
  404. if (retval == 0) {
  405. /* We only execute these callbacks when there was nothing to do or we timed
  406. *out */
  407. target_call_timer_callbacks();
  408. process_jim_events(command_context);
  409. FD_ZERO(&read_fds); /* eCos leaves read_fds unchanged in this case! */
  410. /* We timed out/there was nothing to do, timeout rather than poll next time
  411. **/
  412. poll_ok = false;
  413. } else {
  414. /* There was something to do, next time we'll just poll */
  415. poll_ok = true;
  416. }
  417. /* This is a simple back-off algorithm where we immediately
  418. * re-poll if we did something this time around.
  419. *
  420. * This greatly improves performance of DCC.
  421. */
  422. poll_ok = poll_ok || target_got_message();
  423. for (service = services; service; service = service->next) {
  424. /* handle new connections on listeners */
  425. if ((service->fd != -1) && (FD_ISSET(service->fd, &read_fds))) {
  426. if (service->max_connections != 0) {
  427. retval = add_connection(service, command_context);
  428. if (retval != ERROR_OK) {
  429. LOG_ERROR("%i", retval);
  430. return ERROR_FAIL;
  431. }
  432. } else {
  433. if (service->type == CONNECTION_TCP) {
  434. struct sockaddr_in sin;
  435. socklen_t address_size = sizeof(sin);
  436. int tmp_fd;
  437. tmp_fd = accept(service->fd,
  438. (struct sockaddr *)&service->sin,
  439. &address_size);
  440. close_socket(tmp_fd);
  441. }
  442. LOG_INFO(
  443. "rejected '%s' connection, no more connections allowed",
  444. service->name);
  445. }
  446. }
  447. /* handle activity on connections */
  448. if (service->connections) {
  449. struct connection *c;
  450. for (c = service->connections; c; ) {
  451. if ((FD_ISSET(c->fd, &read_fds)) || c->input_pending) {
  452. retval = service->input(c);
  453. if (retval != ERROR_OK) {
  454. struct connection *next = c->next;
  455. if (service->type == CONNECTION_PIPE ||
  456. service->type == CONNECTION_STDINOUT) {
  457. /* if connection uses a pipe then
  458. * shutdown openocd on error */
  459. shutdown_openocd = 1;
  460. }
  461. remove_connection(service, c);
  462. LOG_INFO("dropped '%s' connection",
  463. service->name);
  464. c = next;
  465. continue;
  466. }
  467. }
  468. c = c->next;
  469. }
  470. }
  471. }
  472. #ifdef _WIN32
  473. MSG msg;
  474. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
  475. if (msg.message == WM_QUIT)
  476. shutdown_openocd = 1;
  477. }
  478. #endif
  479. }
  480. return shutdown_openocd != 2 ? ERROR_OK : ERROR_FAIL;
  481. }
  482. #ifdef _WIN32
  483. BOOL WINAPI ControlHandler(DWORD dwCtrlType)
  484. {
  485. shutdown_openocd = 1;
  486. return TRUE;
  487. }
  488. #endif
  489. void sig_handler(int sig)
  490. {
  491. /* store only first signal that hits us */
  492. if (!last_signal)
  493. last_signal = sig;
  494. shutdown_openocd = 1;
  495. }
  496. int server_preinit(void)
  497. {
  498. /* this currently only calls WSAStartup on native win32 systems
  499. * before any socket operations are performed.
  500. * This is an issue if you call init in your config script */
  501. #ifdef _WIN32
  502. WORD wVersionRequested;
  503. WSADATA wsaData;
  504. wVersionRequested = MAKEWORD(2, 2);
  505. if (WSAStartup(wVersionRequested, &wsaData) != 0) {
  506. LOG_ERROR("Failed to Open Winsock");
  507. return ERROR_FAIL;
  508. }
  509. /* register ctrl-c handler */
  510. SetConsoleCtrlHandler(ControlHandler, TRUE);
  511. signal(SIGBREAK, sig_handler);
  512. #endif
  513. signal(SIGINT, sig_handler);
  514. signal(SIGTERM, sig_handler);
  515. signal(SIGABRT, sig_handler);
  516. return ERROR_OK;
  517. }
  518. int server_init(struct command_context *cmd_ctx)
  519. {
  520. int ret;
  521. ret = tcl_init();
  522. if (ret != ERROR_OK)
  523. return ret;
  524. ret = telnet_init("Open On-Chip Debugger");
  525. if (ret != ERROR_OK) {
  526. remove_services();
  527. return ret;
  528. }
  529. return ERROR_OK;
  530. }
  531. int server_quit(void)
  532. {
  533. remove_services();
  534. target_quit();
  535. #ifdef _WIN32
  536. WSACleanup();
  537. SetConsoleCtrlHandler(ControlHandler, FALSE);
  538. return ERROR_OK;
  539. #endif
  540. /* return signal number so we can kill ourselves */
  541. return last_signal;
  542. }
  543. void exit_on_signal(int sig)
  544. {
  545. #ifndef _WIN32
  546. /* bring back default system handler and kill yourself */
  547. signal(sig, SIG_DFL);
  548. kill(getpid(), sig);
  549. #endif
  550. }
  551. int connection_write(struct connection *connection, const void *data, int len)
  552. {
  553. if (len == 0) {
  554. /* successful no-op. Sockets and pipes behave differently here... */
  555. return 0;
  556. }
  557. if (connection->service->type == CONNECTION_TCP)
  558. return write_socket(connection->fd_out, data, len);
  559. else
  560. return write(connection->fd_out, data, len);
  561. }
  562. int connection_read(struct connection *connection, void *data, int len)
  563. {
  564. if (connection->service->type == CONNECTION_TCP)
  565. return read_socket(connection->fd, data, len);
  566. else
  567. return read(connection->fd, data, len);
  568. }
  569. /* tell the server we want to shut down */
  570. COMMAND_HANDLER(handle_shutdown_command)
  571. {
  572. LOG_USER("shutdown command invoked");
  573. shutdown_openocd = 1;
  574. if (CMD_ARGC == 1) {
  575. if (!strcmp(CMD_ARGV[0], "error")) {
  576. shutdown_openocd = 2;
  577. return ERROR_FAIL;
  578. }
  579. }
  580. return ERROR_COMMAND_CLOSE_CONNECTION;
  581. }
  582. COMMAND_HANDLER(handle_poll_period_command)
  583. {
  584. if (CMD_ARGC == 0)
  585. LOG_WARNING("You need to set a period value");
  586. else
  587. COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], polling_period);
  588. LOG_INFO("set servers polling period to %ums", polling_period);
  589. return ERROR_OK;
  590. }
  591. COMMAND_HANDLER(handle_bindto_command)
  592. {
  593. switch (CMD_ARGC) {
  594. case 0:
  595. command_print(CMD_CTX, "bindto name: %s", bindto_name);
  596. break;
  597. case 1:
  598. free(bindto_name);
  599. bindto_name = strdup(CMD_ARGV[0]);
  600. break;
  601. default:
  602. return ERROR_COMMAND_SYNTAX_ERROR;
  603. }
  604. return ERROR_OK;
  605. }
  606. static const struct command_registration server_command_handlers[] = {
  607. {
  608. .name = "shutdown",
  609. .handler = &handle_shutdown_command,
  610. .mode = COMMAND_ANY,
  611. .usage = "",
  612. .help = "shut the server down",
  613. },
  614. {
  615. .name = "poll_period",
  616. .handler = &handle_poll_period_command,
  617. .mode = COMMAND_ANY,
  618. .usage = "",
  619. .help = "set the servers polling period",
  620. },
  621. {
  622. .name = "bindto",
  623. .handler = &handle_bindto_command,
  624. .mode = COMMAND_ANY,
  625. .usage = "[name]",
  626. .help = "Specify address by name on which to listen for "
  627. "incoming TCP/IP connections",
  628. },
  629. COMMAND_REGISTRATION_DONE
  630. };
  631. int server_register_commands(struct command_context *cmd_ctx)
  632. {
  633. int retval = telnet_register_commands(cmd_ctx);
  634. if (ERROR_OK != retval)
  635. return retval;
  636. retval = tcl_register_commands(cmd_ctx);
  637. if (ERROR_OK != retval)
  638. return retval;
  639. retval = jsp_register_commands(cmd_ctx);
  640. if (ERROR_OK != retval)
  641. return retval;
  642. return register_commands(cmd_ctx, NULL, server_command_handlers);
  643. }
  644. COMMAND_HELPER(server_port_command, unsigned short *out)
  645. {
  646. switch (CMD_ARGC) {
  647. case 0:
  648. command_print(CMD_CTX, "%d", *out);
  649. break;
  650. case 1:
  651. {
  652. uint16_t port;
  653. COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], port);
  654. *out = port;
  655. break;
  656. }
  657. default:
  658. return ERROR_COMMAND_SYNTAX_ERROR;
  659. }
  660. return ERROR_OK;
  661. }
  662. COMMAND_HELPER(server_pipe_command, char **out)
  663. {
  664. switch (CMD_ARGC) {
  665. case 0:
  666. command_print(CMD_CTX, "%s", *out);
  667. break;
  668. case 1:
  669. {
  670. if (CMD_CTX->mode == COMMAND_EXEC) {
  671. LOG_WARNING("unable to change server port after init");
  672. return ERROR_COMMAND_ARGUMENT_INVALID;
  673. }
  674. free(*out);
  675. *out = strdup(CMD_ARGV[0]);
  676. break;
  677. }
  678. default:
  679. return ERROR_COMMAND_SYNTAX_ERROR;
  680. }
  681. return ERROR_OK;
  682. }