- added myself to copyright on files i remember adding large contributions for over...
[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 int add_connection(service_t *service, command_context_t *cmd_ctx)
57 {
58 unsigned int address_size;
59 connection_t *c, **p;
60 int retval;
61 int flag=1;
62
63 c = malloc(sizeof(connection_t));
64 c->fd = -1;
65 memset(&c->sin, 0, sizeof(c->sin));
66 c->cmd_ctx = copy_command_context(cmd_ctx);
67 c->service = service;
68 c->input_pending = 0;
69 c->priv = NULL;
70 c->next = NULL;
71
72 address_size = sizeof(c->sin);
73
74 c->fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size);
75
76 /* This increases performance dramatically for e.g. GDB load which
77 * does not have a sliding window protocol. */
78 retval=setsockopt(c->fd, /* socket affected */
79 IPPROTO_TCP, /* set option at TCP level */
80 TCP_NODELAY, /* name of option */
81 (char *)&flag, /* the cast is historical cruft */
82 sizeof(int)); /* length of option value */
83
84 LOG_INFO("accepting '%s' connection from %i", service->name, c->sin.sin_port);
85 if ((retval = service->new_connection(c)) == ERROR_OK)
86 {
87 }
88 else
89 {
90 close_socket(c->fd);
91 LOG_ERROR("attempted '%s' connection rejected", service->name);
92 free(c);
93 return retval;
94 }
95
96 /* add to the end of linked list */
97 for (p = &service->connections; *p; p = &(*p)->next);
98 *p = c;
99
100 service->max_connections--;
101
102 return ERROR_OK;
103 }
104
105 int remove_connection(service_t *service, connection_t *connection)
106 {
107 connection_t **p = &service->connections;
108 connection_t *c;
109
110 /* find connection */
111 while((c = *p))
112 {
113 if (c->fd == connection->fd)
114 {
115 service->connection_closed(c);
116 close_socket(c->fd);
117 command_done(c->cmd_ctx);
118
119 /* delete connection */
120 *p = c->next;
121 free(c);
122
123 service->max_connections++;
124 break;
125 }
126
127 /* redirect p to next list pointer */
128 p = &(*p)->next;
129 }
130
131 return ERROR_OK;
132 }
133
134 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)
135 {
136 service_t *c, **p;
137 int so_reuseaddr_option = 1;
138
139 c = malloc(sizeof(service_t));
140
141 c->name = strdup(name);
142 c->type = type;
143 c->port = port;
144 c->max_connections = max_connections;
145 c->fd = -1;
146 c->connections = NULL;
147 c->new_connection = new_connection_handler;
148 c->input = input_handler;
149 c->connection_closed = connection_closed_handler;
150 c->priv = priv;
151 c->next = NULL;
152
153 if ((c->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
154 {
155 LOG_ERROR("error creating socket: %s", strerror(errno));
156 exit(-1);
157 }
158
159 setsockopt(c->fd, SOL_SOCKET, SO_REUSEADDR, (void*)&so_reuseaddr_option, sizeof(int));
160
161 socket_nonblock(c->fd);
162
163 memset(&c->sin, 0, sizeof(c->sin));
164 c->sin.sin_family = AF_INET;
165 c->sin.sin_addr.s_addr = INADDR_ANY;
166 c->sin.sin_port = htons(port);
167
168 if (bind(c->fd, (struct sockaddr *)&c->sin, sizeof(c->sin)) == -1)
169 {
170 LOG_ERROR("couldn't bind to socket: %s", strerror(errno));
171 exit(-1);
172 }
173
174 #ifndef _WIN32
175 int segsize=65536;
176 setsockopt(c->fd, IPPROTO_TCP, TCP_MAXSEG, &segsize, sizeof(int));
177 #endif
178 int window_size = 128 * 1024;
179
180 /* These setsockopt()s must happen before the listen() */
181
182 setsockopt(c->fd, SOL_SOCKET, SO_SNDBUF,
183 (char *)&window_size, sizeof(window_size));
184 setsockopt(c->fd, SOL_SOCKET, SO_RCVBUF,
185 (char *)&window_size, sizeof(window_size));
186
187 if (listen(c->fd, 1) == -1)
188 {
189 LOG_ERROR("couldn't listen on socket: %s", strerror(errno));
190 exit(-1);
191 }
192
193 /* add to the end of linked list */
194 for (p = &services; *p; p = &(*p)->next);
195 *p = c;
196
197 return ERROR_OK;
198 }
199
200 int remove_service(unsigned short port)
201 {
202 service_t **p = &services;
203 service_t *c;
204
205 /* find service */
206 while((c = *p))
207 {
208 if (c->port == port)
209 {
210 if (c->name)
211 free(c->name);
212
213 if (c->priv)
214 free(c->priv);
215
216 /* delete service */
217 *p = c->next;
218 free(c);
219 }
220
221 /* redirect p to next list pointer */
222 p = &(*p)->next;
223 }
224
225 return ERROR_OK;
226 }
227
228 int remove_services(void)
229 {
230 service_t *c = services;
231
232 /* loop service */
233 while(c)
234 {
235 service_t *next = c->next;
236
237 if (c->name)
238 free(c->name);
239
240 if (c->priv)
241 free(c->priv);
242
243 /* delete service */
244 free(c);
245
246 /* remember the last service for unlinking */
247 c = next;
248 }
249
250 services = NULL;
251
252 return ERROR_OK;
253 }
254
255 extern void openocd_sleep_prelude(void);
256 extern void openocd_sleep_postlude(void);
257
258 int server_loop(command_context_t *command_context)
259 {
260 service_t *service;
261
262 /* used in select() */
263 fd_set read_fds;
264 struct timeval tv;
265 int fd_max;
266
267 /* used in accept() */
268 int retval;
269
270 #ifndef _WIN32
271 if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
272 LOG_ERROR("couldn't set SIGPIPE to SIG_IGN");
273 #endif
274
275 /* do regular tasks after at most 10ms */
276 tv.tv_sec = 0;
277 tv.tv_usec = 10000;
278
279 while(!shutdown_openocd)
280 {
281 /* monitor sockets for acitvity */
282 fd_max = 0;
283 FD_ZERO(&read_fds);
284
285 /* add service and connection fds to read_fds */
286 for (service = services; service; service = service->next)
287 {
288 if (service->fd != -1)
289 {
290 /* listen for new connections */
291 FD_SET(service->fd, &read_fds);
292
293 if (service->fd > fd_max)
294 fd_max = service->fd;
295 }
296
297 if (service->connections)
298 {
299 connection_t *c;
300
301 for (c = service->connections; c; c = c->next)
302 {
303 /* check for activity on the connection */
304 FD_SET(c->fd, &read_fds);
305 if (c->fd > fd_max)
306 fd_max = c->fd;
307 }
308 }
309 }
310
311 #ifndef _WIN32
312 #if BUILD_ECOSBOARD == 0
313 /* add STDIN to read_fds */
314 FD_SET(fileno(stdin), &read_fds);
315 #endif
316 #endif
317
318 openocd_sleep_prelude();
319 kept_alive();
320 // Only while we're sleeping we'll let others run
321 retval = select(fd_max + 1, &read_fds, NULL, NULL, &tv);
322 openocd_sleep_postlude();
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 process_jim_events ();
353
354 if (retval == 0)
355 {
356 /* do regular tasks after at most 100ms */
357 tv.tv_sec = 0;
358 tv.tv_usec = 10000;
359 FD_ZERO(&read_fds); /* eCos leaves read_fds unchanged in this case! */
360 }
361
362 for (service = services; service; service = service->next)
363 {
364 /* handle new connections on listeners */
365 if ((service->fd != -1)
366 && (FD_ISSET(service->fd, &read_fds)))
367 {
368 if (service->max_connections > 0)
369 {
370 add_connection(service, command_context);
371 }
372 else
373 {
374 struct sockaddr_in sin;
375 unsigned int address_size = sizeof(sin);
376 int tmp_fd;
377 tmp_fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size);
378 close_socket(tmp_fd);
379 LOG_INFO("rejected '%s' connection, no more connections allowed", service->name);
380 }
381 }
382
383 /* handle activity on connections */
384 if (service->connections)
385 {
386 connection_t *c;
387
388 for (c = service->connections; c;)
389 {
390 if ((FD_ISSET(c->fd, &read_fds)) || c->input_pending)
391 {
392 if (service->input(c) != ERROR_OK)
393 {
394 connection_t *next = c->next;
395 remove_connection(service, c);
396 LOG_INFO("dropped '%s' connection", service->name);
397 c = next;
398 continue;
399 }
400 }
401 c = c->next;
402 }
403 }
404 }
405
406 #ifndef _WIN32
407 #if BUILD_ECOSBOARD == 0
408 if (FD_ISSET(fileno(stdin), &read_fds))
409 {
410 if (getc(stdin) == 'x')
411 {
412 shutdown_openocd = 1;
413 }
414 }
415 #endif
416 #else
417 MSG msg;
418 while (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
419 {
420 if (msg.message == WM_QUIT)
421 shutdown_openocd = 1;
422 }
423 #endif
424 }
425
426 return ERROR_OK;
427 }
428
429 #ifdef _WIN32
430 BOOL WINAPI ControlHandler(DWORD dwCtrlType)
431 {
432 shutdown_openocd = 1;
433 return TRUE;
434 }
435
436 void sig_handler(int sig) {
437 shutdown_openocd = 1;
438 }
439 #endif
440
441 int server_init(void)
442 {
443 #ifdef _WIN32
444 WORD wVersionRequested;
445 WSADATA wsaData;
446
447 wVersionRequested = MAKEWORD( 2, 2 );
448
449 if (WSAStartup(wVersionRequested, &wsaData) != 0)
450 {
451 LOG_ERROR("Failed to Open Winsock");
452 exit(-1);
453 }
454
455 SetConsoleCtrlHandler( ControlHandler, TRUE );
456
457 signal(SIGINT, sig_handler);
458 signal(SIGTERM, sig_handler);
459 signal(SIGBREAK, sig_handler);
460 signal(SIGABRT, sig_handler);
461 #endif
462
463
464 return ERROR_OK;
465 }
466
467 int server_quit(void)
468 {
469 remove_services();
470
471 #ifdef _WIN32
472 WSACleanup();
473 SetConsoleCtrlHandler( ControlHandler, FALSE );
474 #endif
475
476 return ERROR_OK;
477 }
478
479 int server_register_commands(command_context_t *context)
480 {
481 register_command(context, NULL, "shutdown", handle_shutdown_command,
482 COMMAND_ANY, "shut the server down");
483
484 return ERROR_OK;
485 }
486
487 /* tell the server we want to shut down */
488 int handle_shutdown_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
489 {
490 shutdown_openocd = 1;
491
492 return ERROR_COMMAND_CLOSE_CONNECTION;
493 }
494
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)