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