Remove redundant sys/types.h #include directives (now in types.h).
[openocd.git] / src / server / server.c
1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
4 * *
5 * Copyright (C) 2007,2008 Ø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 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
25 ***************************************************************************/
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include "replacements.h"
31
32 #include "server.h"
33
34 #include "log.h"
35 #include "telnet_server.h"
36 #include "target.h"
37
38 #include <command.h>
39 #include <string.h>
40 #include <stdlib.h>
41 #include <errno.h>
42 #include <unistd.h>
43 #include <fcntl.h>
44 #include <signal.h>
45 #ifndef _WIN32
46 #include <netinet/tcp.h>
47 #endif
48
49 service_t *services = NULL;
50
51 /* shutdown_openocd == 1: exit the main event loop, and quit the debugger */
52 static int shutdown_openocd = 0;
53 int handle_shutdown_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
54
55 /* set when using pipes rather than tcp */
56 int server_use_pipes = 0;
57
58 int add_connection(service_t *service, command_context_t *cmd_ctx)
59 {
60 socklen_t address_size;
61 connection_t *c, **p;
62 int retval;
63 int flag=1;
64
65 c = malloc(sizeof(connection_t));
66 c->fd = -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 {
76 address_size = sizeof(c->sin);
77
78 c->fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size);
79
80 /* This increases performance dramatically for e.g. GDB load which
81 * does not have a sliding window protocol. */
82 retval=setsockopt(c->fd, /* socket affected */
83 IPPROTO_TCP, /* set option at TCP level */
84 TCP_NODELAY, /* name of option */
85 (char *)&flag, /* the cast is historical cruft */
86 sizeof(int)); /* length of option value */
87
88 LOG_INFO("accepting '%s' connection from %i", service->name, c->sin.sin_port);
89 if ((retval = service->new_connection(c)) != ERROR_OK)
90 {
91 close_socket(c->fd);
92 LOG_ERROR("attempted '%s' connection rejected", service->name);
93 free(c);
94 return retval;
95 }
96 }
97 else if (service->type == CONNECTION_PIPE)
98 {
99 c->fd = service->fd;
100
101 /* do not check for new connections again on stdin */
102 service->fd = -1;
103
104 LOG_INFO("accepting '%s' connection from pipe", service->name);
105 if ((retval = service->new_connection(c)) != ERROR_OK)
106 {
107 LOG_ERROR("attempted '%s' connection rejected", service->name);
108 free(c);
109 return retval;
110 }
111 }
112
113 /* add to the end of linked list */
114 for (p = &service->connections; *p; p = &(*p)->next);
115 *p = c;
116
117 service->max_connections--;
118
119 return ERROR_OK;
120 }
121
122 int remove_connection(service_t *service, connection_t *connection)
123 {
124 connection_t **p = &service->connections;
125 connection_t *c;
126
127 /* find connection */
128 while((c = *p))
129 {
130 if (c->fd == connection->fd)
131 {
132 service->connection_closed(c);
133 if (service->type == CONNECTION_TCP)
134 close_socket(c->fd);
135 command_done(c->cmd_ctx);
136
137 /* delete connection */
138 *p = c->next;
139 free(c);
140
141 service->max_connections++;
142 break;
143 }
144
145 /* redirect p to next list pointer */
146 p = &(*p)->next;
147 }
148
149 return ERROR_OK;
150 }
151
152 int add_service(char *name, enum connection_type type, unsigned short port, int max_connections, new_connection_handler_t new_connection_handler, input_handler_t input_handler, connection_closed_handler_t connection_closed_handler, void *priv)
153 {
154 service_t *c, **p;
155 int so_reuseaddr_option = 1;
156
157 c = malloc(sizeof(service_t));
158
159 c->name = strdup(name);
160 c->type = type;
161 c->port = port;
162 c->max_connections = max_connections;
163 c->fd = -1;
164 c->connections = NULL;
165 c->new_connection = new_connection_handler;
166 c->input = input_handler;
167 c->connection_closed = connection_closed_handler;
168 c->priv = priv;
169 c->next = NULL;
170
171 if (type == CONNECTION_TCP)
172 {
173 if ((c->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
174 {
175 LOG_ERROR("error creating socket: %s", strerror(errno));
176 exit(-1);
177 }
178
179 setsockopt(c->fd, SOL_SOCKET, SO_REUSEADDR, (void*)&so_reuseaddr_option, sizeof(int));
180
181 socket_nonblock(c->fd);
182
183 memset(&c->sin, 0, sizeof(c->sin));
184 c->sin.sin_family = AF_INET;
185 c->sin.sin_addr.s_addr = INADDR_ANY;
186 c->sin.sin_port = htons(port);
187
188 if (bind(c->fd, (struct sockaddr *)&c->sin, sizeof(c->sin)) == -1)
189 {
190 LOG_ERROR("couldn't bind to socket: %s", strerror(errno));
191 exit(-1);
192 }
193
194 #ifndef _WIN32
195 int segsize=65536;
196 setsockopt(c->fd, IPPROTO_TCP, TCP_MAXSEG, &segsize, sizeof(int));
197 #endif
198 int window_size = 128 * 1024;
199
200 /* These setsockopt()s must happen before the listen() */
201
202 setsockopt(c->fd, SOL_SOCKET, SO_SNDBUF,
203 (char *)&window_size, sizeof(window_size));
204 setsockopt(c->fd, SOL_SOCKET, SO_RCVBUF,
205 (char *)&window_size, sizeof(window_size));
206
207 if (listen(c->fd, 1) == -1)
208 {
209 LOG_ERROR("couldn't listen on socket: %s", strerror(errno));
210 exit(-1);
211 }
212 }
213 else if (type == CONNECTION_PIPE)
214 {
215 /* use stdin */
216 c->fd = STDIN_FILENO;
217
218 #ifdef _WIN32
219 /* for win32 set stdin/stdout to binary mode */
220 if (_setmode(_fileno(stdout), _O_BINARY) < 0)
221 LOG_WARNING("cannot change stdout mode to binary");
222 if (_setmode(_fileno(stdin), _O_BINARY) < 0)
223 LOG_WARNING("cannot change stdin mode to binary");
224 if (_setmode(_fileno(stderr), _O_BINARY) < 0)
225 LOG_WARNING("cannot change stderr mode to binary");
226 #else
227 socket_nonblock(c->fd);
228 #endif
229 }
230 else
231 {
232 LOG_ERROR("unknown connection type: %d", type);
233 exit(1);
234 }
235
236 /* add to the end of linked list */
237 for (p = &services; *p; p = &(*p)->next);
238 *p = c;
239
240 return ERROR_OK;
241 }
242
243 int remove_service(unsigned short port)
244 {
245 service_t **p = &services;
246 service_t *c;
247
248 /* find service */
249 while((c = *p))
250 {
251 if (c->port == port)
252 {
253 if (c->name)
254 free(c->name);
255
256 if (c->priv)
257 free(c->priv);
258
259 /* delete service */
260 *p = c->next;
261 free(c);
262 }
263
264 /* redirect p to next list pointer */
265 p = &(*p)->next;
266 }
267
268 return ERROR_OK;
269 }
270
271 int remove_services(void)
272 {
273 service_t *c = services;
274
275 /* loop service */
276 while(c)
277 {
278 service_t *next = c->next;
279
280 if (c->name)
281 free(c->name);
282
283 if (c->priv)
284 free(c->priv);
285
286 /* delete service */
287 free(c);
288
289 /* remember the last service for unlinking */
290 c = next;
291 }
292
293 services = NULL;
294
295 return ERROR_OK;
296 }
297
298 extern void openocd_sleep_prelude(void);
299 extern void openocd_sleep_postlude(void);
300
301 int server_loop(command_context_t *command_context)
302 {
303 service_t *service;
304
305 /* used in select() */
306 fd_set read_fds;
307 struct timeval tv;
308 int fd_max;
309
310 /* used in accept() */
311 int retval;
312
313 #ifndef _WIN32
314 if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
315 LOG_ERROR("couldn't set SIGPIPE to SIG_IGN");
316 #endif
317
318 /* do regular tasks after at most 10ms */
319 tv.tv_sec = 0;
320 tv.tv_usec = 10000;
321
322 while(!shutdown_openocd)
323 {
324 /* monitor sockets for acitvity */
325 fd_max = 0;
326 FD_ZERO(&read_fds);
327
328 /* add service and connection fds to read_fds */
329 for (service = services; service; service = service->next)
330 {
331 if (service->fd != -1)
332 {
333 /* listen for new connections */
334 FD_SET(service->fd, &read_fds);
335
336 if (service->fd > fd_max)
337 fd_max = service->fd;
338 }
339
340 if (service->connections)
341 {
342 connection_t *c;
343
344 for (c = service->connections; c; c = c->next)
345 {
346 /* check for activity on the connection */
347 FD_SET(c->fd, &read_fds);
348 if (c->fd > fd_max)
349 fd_max = c->fd;
350 }
351 }
352 }
353
354 #ifndef _WIN32
355 #if BUILD_ECOSBOARD == 0
356 if (server_use_pipes == 0)
357 {
358 /* add STDIN to read_fds */
359 FD_SET(fileno(stdin), &read_fds);
360 }
361 #endif
362 #endif
363
364 openocd_sleep_prelude();
365 kept_alive();
366
367 /* Only while we're sleeping we'll let others run */
368 retval = socket_select(fd_max + 1, &read_fds, NULL, NULL, &tv);
369 openocd_sleep_postlude();
370
371 if (retval == -1)
372 {
373 #ifdef _WIN32
374
375 errno = WSAGetLastError();
376
377 if (errno == WSAEINTR)
378 FD_ZERO(&read_fds);
379 else
380 {
381 LOG_ERROR("error during select: %s", strerror(errno));
382 exit(-1);
383 }
384 #else
385
386 if (errno == EINTR)
387 {
388 FD_ZERO(&read_fds);
389 }
390 else
391 {
392 LOG_ERROR("error during select: %s", strerror(errno));
393 exit(-1);
394 }
395 #endif
396 }
397
398 target_call_timer_callbacks();
399 process_jim_events ();
400
401 if (retval == 0)
402 {
403 /* do regular tasks after at most 100ms */
404 tv.tv_sec = 0;
405 tv.tv_usec = 10000;
406 FD_ZERO(&read_fds); /* eCos leaves read_fds unchanged in this case! */
407 }
408
409 for (service = services; service; service = service->next)
410 {
411 /* handle new connections on listeners */
412 if ((service->fd != -1)
413 && (FD_ISSET(service->fd, &read_fds)))
414 {
415 if (service->max_connections > 0)
416 {
417 add_connection(service, command_context);
418 }
419 else
420 {
421 if (service->type != CONNECTION_PIPE)
422 {
423 struct sockaddr_in sin;
424 socklen_t address_size = sizeof(sin);
425 int tmp_fd;
426 tmp_fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size);
427 close_socket(tmp_fd);
428 }
429 LOG_INFO("rejected '%s' connection, no more connections allowed", service->name);
430 }
431 }
432
433 /* handle activity on connections */
434 if (service->connections)
435 {
436 connection_t *c;
437
438 for (c = service->connections; c;)
439 {
440 if ((FD_ISSET(c->fd, &read_fds)) || c->input_pending)
441 {
442 if ((retval = service->input(c)) != ERROR_OK)
443 {
444 connection_t *next = c->next;
445 if (service->type == CONNECTION_PIPE)
446 {
447 /* if connection uses a pipe then shutdown openocd on error */
448 shutdown_openocd = 1;
449 }
450 remove_connection(service, c);
451 LOG_INFO("dropped '%s' connection - error %d", service->name, retval);
452 c = next;
453 continue;
454 }
455 }
456 c = c->next;
457 }
458 }
459 }
460
461 #ifndef _WIN32
462 #if BUILD_ECOSBOARD == 0
463 /* check for data on stdin if not using pipes */
464 if (server_use_pipes == 0)
465 {
466 if (FD_ISSET(fileno(stdin), &read_fds))
467 {
468 if (getc(stdin) == 'x')
469 {
470 shutdown_openocd = 1;
471 }
472 }
473 }
474 #endif
475 #else
476 MSG msg;
477 while (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
478 {
479 if (msg.message == WM_QUIT)
480 shutdown_openocd = 1;
481 }
482 #endif
483 }
484
485 return ERROR_OK;
486 }
487
488 #ifdef _WIN32
489 BOOL WINAPI ControlHandler(DWORD dwCtrlType)
490 {
491 shutdown_openocd = 1;
492 return TRUE;
493 }
494
495 void sig_handler(int sig) {
496 shutdown_openocd = 1;
497 }
498 #endif
499
500 int server_init(void)
501 {
502 #ifdef _WIN32
503 WORD wVersionRequested;
504 WSADATA wsaData;
505
506 wVersionRequested = MAKEWORD(2, 2);
507
508 if (WSAStartup(wVersionRequested, &wsaData) != 0)
509 {
510 LOG_ERROR("Failed to Open Winsock");
511 exit(-1);
512 }
513
514 if (server_use_pipes == 0)
515 {
516 /* register ctrl-c handler */
517 SetConsoleCtrlHandler(ControlHandler, TRUE);
518 }
519 else
520 {
521 /* we are using pipes so ignore ctrl-c */
522 SetConsoleCtrlHandler(NULL, TRUE);
523 }
524
525 signal(SIGINT, sig_handler);
526 signal(SIGTERM, sig_handler);
527 signal(SIGBREAK, sig_handler);
528 signal(SIGABRT, sig_handler);
529 #endif
530
531 return ERROR_OK;
532 }
533
534 int server_quit(void)
535 {
536 remove_services();
537
538 #ifdef _WIN32
539 WSACleanup();
540 SetConsoleCtrlHandler( ControlHandler, FALSE );
541 #endif
542
543 return ERROR_OK;
544 }
545
546 int server_register_commands(command_context_t *context)
547 {
548 register_command(context, NULL, "shutdown", handle_shutdown_command,
549 COMMAND_ANY, "shut the server down");
550
551 return ERROR_OK;
552 }
553
554 /* tell the server we want to shut down */
555 int handle_shutdown_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
556 {
557 shutdown_openocd = 1;
558
559 return ERROR_COMMAND_CLOSE_CONNECTION;
560 }

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)