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

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)