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

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)