26610cfd90265c895f58dff50aca7cf97f98588d
[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 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the *
20 * Free Software Foundation, Inc., *
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
22 ***************************************************************************/
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include "replacements.h"
28
29 #include "server.h"
30
31 #include "log.h"
32 #include "telnet_server.h"
33 #include "target.h"
34
35 #include <command.h>
36 #include <string.h>
37 #include <stdlib.h>
38 #include <errno.h>
39 #include <unistd.h>
40 #include <sys/types.h>
41 #include <fcntl.h>
42 #include <signal.h>
43 #ifndef _WIN32
44 #include <netinet/tcp.h>
45 #endif
46
47 service_t *services = NULL;
48
49 /* shutdown_openocd == 1: exit the main event loop, and quit the debugger */
50 static int shutdown_openocd = 0;
51 int handle_shutdown_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
52
53 int add_connection(service_t *service, command_context_t *cmd_ctx)
54 {
55 unsigned int address_size;
56 connection_t *c, **p;
57 int retval;
58 int flag=1;
59
60 c = malloc(sizeof(connection_t));
61 c->fd = -1;
62 memset(&c->sin, 0, sizeof(c->sin));
63 c->cmd_ctx = copy_command_context(cmd_ctx);
64 c->service = service;
65 c->input_pending = 0;
66 c->priv = NULL;
67 c->next = NULL;
68
69 address_size = sizeof(c->sin);
70
71 c->fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size);
72
73 /* This increases performance dramatically for e.g. GDB load which
74 * does not have a sliding window protocol. */
75 retval=setsockopt(c->fd, /* socket affected */
76 IPPROTO_TCP, /* set option at TCP level */
77 TCP_NODELAY, /* name of option */
78 (char *)&flag, /* the cast is historical cruft */
79 sizeof(int)); /* length of option value */
80
81 LOG_INFO("accepting '%s' connection from %i", service->name, c->sin.sin_port);
82 if ((retval = service->new_connection(c)) == ERROR_OK)
83 {
84 }
85 else
86 {
87 close_socket(c->fd);
88 LOG_ERROR("attempted '%s' connection rejected", service->name);
89 free(c);
90 return retval;
91 }
92
93 /* add to the end of linked list */
94 for (p = &service->connections; *p; p = &(*p)->next);
95 *p = c;
96
97 service->max_connections--;
98
99 return ERROR_OK;
100 }
101
102 int remove_connection(service_t *service, connection_t *connection)
103 {
104 connection_t **p = &service->connections;
105 connection_t *c;
106
107 /* find connection */
108 while((c = *p))
109 {
110 if (c->fd == connection->fd)
111 {
112 service->connection_closed(c);
113 close_socket(c->fd);
114 command_done(c->cmd_ctx);
115
116 /* delete connection */
117 *p = c->next;
118 free(c);
119
120 service->max_connections++;
121 break;
122 }
123
124 /* redirect p to next list pointer */
125 p = &(*p)->next;
126 }
127
128 return ERROR_OK;
129 }
130
131 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)
132 {
133 service_t *c, **p;
134 int so_reuseaddr_option = 1;
135
136 c = malloc(sizeof(service_t));
137
138 c->name = strdup(name);
139 c->type = type;
140 c->port = port;
141 c->max_connections = max_connections;
142 c->fd = -1;
143 c->connections = NULL;
144 c->new_connection = new_connection_handler;
145 c->input = input_handler;
146 c->connection_closed = connection_closed_handler;
147 c->priv = priv;
148 c->next = NULL;
149
150 if ((c->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
151 {
152 LOG_ERROR("error creating socket: %s", strerror(errno));
153 exit(-1);
154 }
155
156 setsockopt(c->fd, SOL_SOCKET, SO_REUSEADDR, (void*)&so_reuseaddr_option, sizeof(int));
157
158 socket_nonblock(c->fd);
159
160 memset(&c->sin, 0, sizeof(c->sin));
161 c->sin.sin_family = AF_INET;
162 c->sin.sin_addr.s_addr = INADDR_ANY;
163 c->sin.sin_port = htons(port);
164
165 if (bind(c->fd, (struct sockaddr *)&c->sin, sizeof(c->sin)) == -1)
166 {
167 LOG_ERROR("couldn't bind to socket: %s", strerror(errno));
168 exit(-1);
169 }
170
171 #ifndef _WIN32
172 int segsize=65536;
173 setsockopt(c->fd, IPPROTO_TCP, TCP_MAXSEG, &segsize, sizeof(int));
174 #endif
175 int window_size = 128 * 1024;
176
177 /* These setsockopt()s must happen before the listen() */
178
179 setsockopt(c->fd, SOL_SOCKET, SO_SNDBUF,
180 (char *)&window_size, sizeof(window_size));
181 setsockopt(c->fd, SOL_SOCKET, SO_RCVBUF,
182 (char *)&window_size, sizeof(window_size));
183
184 if (listen(c->fd, 1) == -1)
185 {
186 LOG_ERROR("couldn't listen on socket: %s", strerror(errno));
187 exit(-1);
188 }
189
190 /* add to the end of linked list */
191 for (p = &services; *p; p = &(*p)->next);
192 *p = c;
193
194 return ERROR_OK;
195 }
196
197 int remove_service(unsigned short port)
198 {
199 service_t **p = &services;
200 service_t *c;
201
202 /* find service */
203 while((c = *p))
204 {
205 if (c->port == port)
206 {
207 if (c->name)
208 free(c->name);
209
210 if (c->priv)
211 free(c->priv);
212
213 /* delete service */
214 *p = c->next;
215 free(c);
216 }
217
218 /* redirect p to next list pointer */
219 p = &(*p)->next;
220 }
221
222 return ERROR_OK;
223 }
224
225 int remove_services(void)
226 {
227 service_t *c = services;
228
229 /* loop service */
230 while(c)
231 {
232 service_t *next = c->next;
233
234 if (c->name)
235 free(c->name);
236
237 if (c->priv)
238 free(c->priv);
239
240 /* delete service */
241 free(c);
242
243 /* remember the last service for unlinking */
244 c = next;
245 }
246
247 services = NULL;
248
249 return ERROR_OK;
250 }
251
252 extern void openocd_sleep_prelude(void);
253 extern void openocd_sleep_postlude(void);
254
255 int server_loop(command_context_t *command_context)
256 {
257 service_t *service;
258
259 /* used in select() */
260 fd_set read_fds;
261 struct timeval tv;
262 int fd_max;
263
264 /* used in accept() */
265 int retval;
266
267 #ifndef _WIN32
268 if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
269 LOG_ERROR("couldn't set SIGPIPE to SIG_IGN");
270 #endif
271
272 /* do regular tasks after at most 10ms */
273 tv.tv_sec = 0;
274 tv.tv_usec = 10000;
275
276 while(!shutdown_openocd)
277 {
278 /* monitor sockets for acitvity */
279 fd_max = 0;
280 FD_ZERO(&read_fds);
281
282 /* add service and connection fds to read_fds */
283 for (service = services; service; service = service->next)
284 {
285 if (service->fd != -1)
286 {
287 /* listen for new connections */
288 FD_SET(service->fd, &read_fds);
289
290 if (service->fd > fd_max)
291 fd_max = service->fd;
292 }
293
294 if (service->connections)
295 {
296 connection_t *c;
297
298 for (c = service->connections; c; c = c->next)
299 {
300 /* check for activity on the connection */
301 FD_SET(c->fd, &read_fds);
302 if (c->fd > fd_max)
303 fd_max = c->fd;
304 }
305 }
306 }
307
308 #ifndef _WIN32
309 #if BUILD_ECOSBOARD == 0
310 /* add STDIN to read_fds */
311 FD_SET(fileno(stdin), &read_fds);
312 #endif
313 #endif
314
315 openocd_sleep_prelude();
316 kept_alive();
317 // Only while we're sleeping we'll let others run
318 retval = select(fd_max + 1, &read_fds, NULL, NULL, &tv);
319 openocd_sleep_postlude();
320
321 if (retval == -1)
322 {
323 #ifdef _WIN32
324
325 errno = WSAGetLastError();
326
327 if (errno == WSAEINTR)
328 FD_ZERO(&read_fds);
329 else
330 {
331 LOG_ERROR("error during select: %s", strerror(errno));
332 exit(-1);
333 }
334 #else
335
336 if (errno == EINTR)
337 {
338 FD_ZERO(&read_fds);
339 }
340 else
341 {
342 LOG_ERROR("error during select: %s", strerror(errno));
343 exit(-1);
344 }
345 #endif
346 }
347
348 target_call_timer_callbacks();
349 process_jim_events ();
350
351 if (retval == 0)
352 {
353 /* do regular tasks after at most 100ms */
354 tv.tv_sec = 0;
355 tv.tv_usec = 10000;
356 FD_ZERO(&read_fds); /* eCos leaves read_fds unchanged in this case! */
357 }
358
359 for (service = services; service; service = service->next)
360 {
361 /* handle new connections on listeners */
362 if ((service->fd != -1)
363 && (FD_ISSET(service->fd, &read_fds)))
364 {
365 if (service->max_connections > 0)
366 {
367 add_connection(service, command_context);
368 }
369 else
370 {
371 struct sockaddr_in sin;
372 unsigned int address_size = sizeof(sin);
373 int tmp_fd;
374 tmp_fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size);
375 close_socket(tmp_fd);
376 LOG_INFO("rejected '%s' connection, no more connections allowed", service->name);
377 }
378 }
379
380 /* handle activity on connections */
381 if (service->connections)
382 {
383 connection_t *c;
384
385 for (c = service->connections; c;)
386 {
387 if ((FD_ISSET(c->fd, &read_fds)) || c->input_pending)
388 {
389 if (service->input(c) != ERROR_OK)
390 {
391 connection_t *next = c->next;
392 remove_connection(service, c);
393 LOG_INFO("dropped '%s' connection", service->name);
394 c = next;
395 continue;
396 }
397 }
398 c = c->next;
399 }
400 }
401 }
402
403 #ifndef _WIN32
404 #if BUILD_ECOSBOARD == 0
405 if (FD_ISSET(fileno(stdin), &read_fds))
406 {
407 if (getc(stdin) == 'x')
408 {
409 shutdown_openocd = 1;
410 }
411 }
412 #endif
413 #else
414 MSG msg;
415 while (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
416 {
417 if (msg.message == WM_QUIT)
418 shutdown_openocd = 1;
419 }
420 #endif
421 }
422
423 return ERROR_OK;
424 }
425
426 #ifdef _WIN32
427 BOOL WINAPI ControlHandler(DWORD dwCtrlType)
428 {
429 shutdown_openocd = 1;
430 return TRUE;
431 }
432
433 void sig_handler(int sig) {
434 shutdown_openocd = 1;
435 }
436 #endif
437
438 int server_init(void)
439 {
440 #ifdef _WIN32
441 WORD wVersionRequested;
442 WSADATA wsaData;
443
444 wVersionRequested = MAKEWORD( 2, 2 );
445
446 if (WSAStartup(wVersionRequested, &wsaData) != 0)
447 {
448 LOG_ERROR("Failed to Open Winsock");
449 exit(-1);
450 }
451
452 SetConsoleCtrlHandler( ControlHandler, TRUE );
453
454 signal(SIGINT, sig_handler);
455 signal(SIGTERM, sig_handler);
456 signal(SIGBREAK, sig_handler);
457 signal(SIGABRT, sig_handler);
458 #endif
459
460
461 return ERROR_OK;
462 }
463
464 int server_quit(void)
465 {
466 remove_services();
467
468 #ifdef _WIN32
469 WSACleanup();
470 SetConsoleCtrlHandler( ControlHandler, FALSE );
471 #endif
472
473 return ERROR_OK;
474 }
475
476 int server_register_commands(command_context_t *context)
477 {
478 register_command(context, NULL, "shutdown", handle_shutdown_command,
479 COMMAND_ANY, "shut the server down");
480
481 return ERROR_OK;
482 }
483
484 /* tell the server we want to shut down */
485 int handle_shutdown_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
486 {
487 shutdown_openocd = 1;
488
489 return ERROR_COMMAND_CLOSE_CONNECTION;
490 }
491
492

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)