hooks for multithreading. Disable nagle
[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 #ifndef _WIN32
56 int flag=1;
57 #endif
58
59 c = malloc(sizeof(connection_t));
60 c->fd = -1;
61 memset(&c->sin, 0, sizeof(c->sin));
62 c->cmd_ctx = copy_command_context(cmd_ctx);
63 c->service = service;
64 c->input_pending = 0;
65 c->priv = NULL;
66 c->next = NULL;
67
68 address_size = sizeof(c->sin);
69 #ifndef _WIN32
70 int segsize=65536;
71 setsockopt(service->fd, IPPROTO_TCP, TCP_MAXSEG, &segsize, sizeof(int));
72 int window_size = 128 * 1024;
73
74 /* These setsockopt()s must happen before the accept() */
75
76 setsockopt(service->fd, SOL_SOCKET, SO_SNDBUF,
77 (char *) &window_size, sizeof(window_size));
78
79 setsockopt(service->fd, SOL_SOCKET, SO_RCVBUF,
80 (char *) &window_size, sizeof(window_size));
81
82 #endif
83 c->fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size);
84 #ifndef _WIN32
85 // This increases performance dramatically for e.g. GDB load which
86 // does not have a sliding window protocol.
87 retval=setsockopt(c->fd, /* socket affected */
88 IPPROTO_TCP, /* set option at TCP level */
89 TCP_NODELAY, /* name of option */
90 (char *) &flag, /* the cast is historical
91 cruft */
92 sizeof(int)); /* length of option value */
93 setsockopt(c->fd, IPPROTO_TCP, TCP_MAXSEG, &segsize, sizeof(int));
94 #endif
95
96
97 LOG_INFO("accepting '%s' connection from %i", service->name, c->sin.sin_port);
98 if ((retval = service->new_connection(c)) == ERROR_OK)
99 {
100 }
101 else
102 {
103 close_socket(c->fd);
104 LOG_ERROR("attempted '%s' connection rejected", service->name);
105 free(c);
106 return retval;
107 }
108
109 /* add to the end of linked list */
110 for (p = &service->connections; *p; p = &(*p)->next);
111 *p = c;
112
113 service->max_connections--;
114
115 return ERROR_OK;
116 }
117
118 int remove_connection(service_t *service, connection_t *connection)
119 {
120 connection_t **p = &service->connections;
121 connection_t *c;
122
123 /* find connection */
124 while((c = *p))
125 {
126 if (c->fd == connection->fd)
127 {
128 service->connection_closed(c);
129 close_socket(c->fd);
130 command_done(c->cmd_ctx);
131
132 /* delete connection */
133 *p = c->next;
134 free(c);
135
136 service->max_connections++;
137 break;
138 }
139
140 /* redirect p to next list pointer */
141 p = &(*p)->next;
142 }
143
144 return ERROR_OK;
145 }
146
147 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)
148 {
149 service_t *c, **p;
150 int so_reuseaddr_option = 1;
151
152 c = malloc(sizeof(service_t));
153
154 c->name = strdup(name);
155 c->type = type;
156 c->port = port;
157 c->max_connections = max_connections;
158 c->fd = -1;
159 c->connections = NULL;
160 c->new_connection = new_connection_handler;
161 c->input = input_handler;
162 c->connection_closed = connection_closed_handler;
163 c->priv = priv;
164 c->next = NULL;
165
166 if ((c->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
167 {
168 LOG_ERROR("error creating socket: %s", strerror(errno));
169 exit(-1);
170 }
171
172 setsockopt(c->fd, SOL_SOCKET, SO_REUSEADDR, (void*)&so_reuseaddr_option, sizeof(int));
173
174 socket_nonblock(c->fd);
175
176 memset(&c->sin, 0, sizeof(c->sin));
177 c->sin.sin_family = AF_INET;
178 c->sin.sin_addr.s_addr = INADDR_ANY;
179 c->sin.sin_port = htons(port);
180
181 if (bind(c->fd, (struct sockaddr *)&c->sin, sizeof(c->sin)) == -1)
182 {
183 LOG_ERROR("couldn't bind to socket: %s", strerror(errno));
184 exit(-1);
185 }
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()
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 lockBigLock();
256 extern void unlockBigLock();
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 // This function is reentrant(workaround for configuration problems)
276 static int lockCount=0;
277 if (lockCount++==0)
278 {
279 lockBigLock();
280 }
281
282 /* do regular tasks after at most 10ms */
283 tv.tv_sec = 0;
284 tv.tv_usec = 10000;
285
286 while(!shutdown_openocd)
287 {
288 /* monitor sockets for acitvity */
289 fd_max = 0;
290 FD_ZERO(&read_fds);
291
292 /* add service and connection fds to read_fds */
293 for (service = services; service; service = service->next)
294 {
295 if (service->fd != -1)
296 {
297 /* listen for new connections */
298 FD_SET(service->fd, &read_fds);
299
300 if (service->fd > fd_max)
301 fd_max = service->fd;
302 }
303
304 if (service->connections)
305 {
306 connection_t *c;
307
308 for (c = service->connections; c; c = c->next)
309 {
310 /* check for activity on the connection */
311 FD_SET(c->fd, &read_fds);
312 if (c->fd > fd_max)
313 fd_max = c->fd;
314 }
315 }
316 }
317
318 #ifndef _WIN32
319 #ifndef BUILD_ECOSBOARD
320 /* add STDIN to read_fds */
321 FD_SET(fileno(stdin), &read_fds);
322 #endif
323 #endif
324
325 // Only while we're sleeping we'll let others run
326 unlockBigLock();
327 retval = select(fd_max + 1, &read_fds, NULL, NULL, &tv);
328 lockBigLock();
329
330 if (retval == -1)
331 {
332 #ifdef _WIN32
333
334 errno = WSAGetLastError();
335
336 if (errno == WSAEINTR)
337 FD_ZERO(&read_fds);
338 else
339 {
340 LOG_ERROR("error during select: %s", strerror(errno));
341 exit(-1);
342 }
343 #else
344
345 if (errno == EINTR)
346 {
347 FD_ZERO(&read_fds);
348 }
349 else
350 {
351 LOG_ERROR("error during select: %s", strerror(errno));
352 exit(-1);
353 }
354 #endif
355 }
356
357 target_call_timer_callbacks();
358
359 if (retval == 0)
360 {
361 /* do regular tasks after at most 100ms */
362 tv.tv_sec = 0;
363 tv.tv_usec = 10000;
364 FD_ZERO(&read_fds); /* eCos leaves read_fds unchanged in this case! */
365 }
366
367 for (service = services; service; service = service->next)
368 {
369 /* handle new connections on listeners */
370 if ((service->fd != -1)
371 && (FD_ISSET(service->fd, &read_fds)))
372 {
373 if (service->max_connections > 0)
374 {
375 add_connection(service, command_context);
376 }
377 else
378 {
379 struct sockaddr_in sin;
380 unsigned int address_size = sizeof(sin);
381 int tmp_fd;
382 tmp_fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size);
383 close_socket(tmp_fd);
384 LOG_INFO("rejected '%s' connection, no more connections allowed", service->name);
385 }
386 }
387
388 /* handle activity on connections */
389 if (service->connections)
390 {
391 connection_t *c;
392
393 for (c = service->connections; c;)
394 {
395 if ((FD_ISSET(c->fd, &read_fds)) || c->input_pending)
396 {
397 if (service->input(c) != ERROR_OK)
398 {
399 connection_t *next = c->next;
400 remove_connection(service, c);
401 LOG_INFO("dropped '%s' connection", service->name);
402 c = next;
403 continue;
404 }
405 }
406 c = c->next;
407 }
408 }
409 }
410
411 #ifndef _WIN32
412 #ifndef BUILD_ECOSBOARD
413 if (FD_ISSET(fileno(stdin), &read_fds))
414 {
415 if (getc(stdin) == 'x')
416 {
417 shutdown_openocd = 1;
418 }
419 }
420 #endif
421 #else
422 MSG msg;
423 while (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
424 {
425 if (msg.message == WM_QUIT)
426 shutdown_openocd = 1;
427 }
428 #endif
429 }
430 if (--lockCount==0)
431 {
432 unlockBigLock();
433 }
434
435 return ERROR_OK;
436 }
437
438 #ifdef _WIN32
439 BOOL WINAPI ControlHandler(DWORD dwCtrlType)
440 {
441 shutdown_openocd = 1;
442 return TRUE;
443 }
444
445 void sig_handler(int sig) {
446 shutdown_openocd = 1;
447 }
448 #endif
449
450 int server_init()
451 {
452 #ifdef _WIN32
453 WORD wVersionRequested;
454 WSADATA wsaData;
455
456 wVersionRequested = MAKEWORD( 2, 2 );
457
458 if (WSAStartup(wVersionRequested, &wsaData) != 0)
459 {
460 LOG_ERROR("Failed to Open Winsock");
461 exit(-1);
462 }
463
464 SetConsoleCtrlHandler( ControlHandler, TRUE );
465
466 signal(SIGINT, sig_handler);
467 signal(SIGTERM, sig_handler);
468 signal(SIGBREAK, sig_handler);
469 signal(SIGABRT, sig_handler);
470 #endif
471
472
473 return ERROR_OK;
474 }
475
476 int server_quit()
477 {
478 remove_services();
479
480 #ifdef _WIN32
481 WSACleanup();
482 SetConsoleCtrlHandler( ControlHandler, FALSE );
483 #endif
484
485 return ERROR_OK;
486 }
487
488 int server_register_commands(command_context_t *context)
489 {
490 register_command(context, NULL, "shutdown", handle_shutdown_command,
491 COMMAND_ANY, "shut the server down");
492
493 return ERROR_OK;
494 }
495
496 /* tell the server we want to shut down */
497 int handle_shutdown_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
498 {
499 shutdown_openocd = 1;
500
501 return ERROR_COMMAND_CLOSE_CONNECTION;
502 }
503
504

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)