98b1fb1d4a95c0a4fbb4a06224146f611825ab85
[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
41 service_t *services = NULL;
42
43 /* shutdown_openocd == 1: exit the main event loop, and quit the debugger */
44 static int shutdown_openocd = 0;
45 int handle_shutdown_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
46
47 int add_connection(service_t *service, command_context_t *cmd_ctx)
48 {
49 unsigned int address_size;
50 connection_t *c, *p;
51 int retval;
52
53 c = malloc(sizeof(connection_t));
54 c->fd = -1;
55 memset(&c->sin, 0, sizeof(c->sin));
56 c->cmd_ctx = copy_command_context(cmd_ctx);
57 c->service = service;
58 c->input_pending = 0;
59 c->priv = NULL;
60 c->next = NULL;
61
62 address_size = sizeof(c->sin);
63 c->fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size);
64
65 if ((retval = service->new_connection(c)) == ERROR_OK)
66 {
67 INFO("accepted '%s' connection from %i", service->name, c->sin.sin_port);
68 }
69 else
70 {
71 close_socket(c->fd);
72 INFO("attempted '%s' connection rejected", service->name);
73 free(c);
74 }
75
76 if (service->connections)
77 {
78 for (p = service->connections; p && p->next; p = p->next);
79 if (p)
80 p->next = c;
81 }
82 else
83 {
84 service->connections = c;
85 }
86
87 service->max_connections--;
88
89 return ERROR_OK;
90 }
91
92 int remove_connection(service_t *service, connection_t *connection)
93 {
94 connection_t *c = service->connections;
95
96 /* find connection */
97 while(c)
98 {
99 connection_t *next = c->next;
100
101 if (c->fd == connection->fd)
102 {
103 service->connections = next;
104 service->connection_closed(c);
105 close_socket(c->fd);
106
107 command_done(c->cmd_ctx);
108
109 /* delete connection */
110 free(c);
111
112 service->max_connections++;
113 break;
114 }
115
116 /* remember the last connection for unlinking */
117 c = next;
118 }
119
120 return ERROR_OK;
121 }
122
123 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)
124 {
125 service_t *c, *p;
126 int so_reuseaddr_option = 1;
127
128 c = malloc(sizeof(service_t));
129
130 c->name = strdup(name);
131 c->type = type;
132 c->port = port;
133 c->max_connections = max_connections;
134 c->fd = -1;
135 c->connections = NULL;
136 c->new_connection = new_connection_handler;
137 c->input = input_handler;
138 c->connection_closed = connection_closed_handler;
139 c->priv = priv;
140 c->next = NULL;
141
142 if ((c->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
143 {
144 ERROR("error creating socket: %s", strerror(errno));
145 exit(-1);
146 }
147
148 setsockopt(c->fd, SOL_SOCKET, SO_REUSEADDR, (void*)&so_reuseaddr_option, sizeof(int));
149
150 socket_nonblock(c->fd);
151
152 memset(&c->sin, 0, sizeof(c->sin));
153 c->sin.sin_family = AF_INET;
154 c->sin.sin_addr.s_addr = INADDR_ANY;
155 c->sin.sin_port = htons(port);
156
157 if (bind(c->fd, (struct sockaddr *)&c->sin, sizeof(c->sin)) == -1)
158 {
159 ERROR("couldn't bind to socket: %s", strerror(errno));
160 exit(-1);
161 }
162
163 if (listen(c->fd, 1) == -1)
164 {
165 ERROR("couldn't listen on socket: %s", strerror(errno));
166 exit(-1);
167 }
168
169 if (services)
170 {
171 for (p = services; p && p->next; p = p->next);
172 if (p)
173 p->next = c;
174 }
175 else
176 {
177 services = c;
178 }
179
180 return ERROR_OK;
181 }
182
183 int remove_service(unsigned short port)
184 {
185 service_t *c = services;
186
187 /* find service */
188 while(c)
189 {
190 service_t *next = c->next;
191
192 if (c->port == port)
193 {
194 if (c->name)
195 free(c->name);
196
197 if (c->priv)
198 free(c->priv);
199
200 /* delete service */
201 free(c);
202 }
203
204 /* remember the last service for unlinking */
205 c = next;
206 }
207
208 return ERROR_OK;
209 }
210
211 int remove_services()
212 {
213 service_t *c = services;
214
215 /* loop service */
216 while(c)
217 {
218 service_t *next = c->next;
219
220 if (c->name)
221 free(c->name);
222
223 if (c->priv)
224 free(c->priv);
225
226 /* delete service */
227 free(c);
228
229 /* remember the last service for unlinking */
230 c = next;
231 }
232
233 return ERROR_OK;
234 }
235
236 int server_loop(command_context_t *command_context)
237 {
238 service_t *service;
239
240 /* used in select() */
241 fd_set read_fds;
242 struct timeval tv;
243 int fd_max;
244
245 /* used in accept() */
246 int retval;
247
248 #ifndef _WIN32
249 if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
250 ERROR("couldn't set SIGPIPE to SIG_IGN");
251 #endif
252
253 /* do regular tasks after at most 10ms */
254 tv.tv_sec = 0;
255 tv.tv_usec = 10000;
256
257 while(!shutdown_openocd)
258 {
259 /* monitor sockets for acitvity */
260 fd_max = 0;
261 FD_ZERO(&read_fds);
262
263 /* add service and connection fds to read_fds */
264 for (service = services; service; service = service->next)
265 {
266 if (service->fd != -1)
267 {
268 /* listen for new connections */
269 FD_SET(service->fd, &read_fds);
270
271 if (service->fd > fd_max)
272 fd_max = service->fd;
273 }
274
275 if (service->connections)
276 {
277 connection_t *c;
278
279 for (c = service->connections; c; c = c->next)
280 {
281 /* check for activity on the connection */
282 FD_SET(c->fd, &read_fds);
283 if (c->fd > fd_max)
284 fd_max = c->fd;
285 }
286 }
287 }
288
289 #ifndef _WIN32
290 /* add STDIN to read_fds */
291 FD_SET(fileno(stdin), &read_fds);
292 #endif
293
294 if ((retval = select(fd_max + 1, &read_fds, NULL, NULL, &tv)) == -1)
295 {
296 #ifdef _WIN32
297
298 errno = WSAGetLastError();
299
300 if (errno == WSAEINTR)
301 FD_ZERO(&read_fds);
302 else
303 {
304 ERROR("error during select: %s", strerror(errno));
305 exit(-1);
306 }
307 #else
308
309 if (errno == EINTR)
310 FD_ZERO(&read_fds);
311 else
312 {
313 ERROR("error during select: %s", strerror(errno));
314 exit(-1);
315 }
316 #endif
317 }
318
319 target_call_timer_callbacks();
320
321 if (retval == 0)
322 {
323 /* do regular tasks after at most 100ms */
324 tv.tv_sec = 0;
325 tv.tv_usec = 10000;
326 }
327
328 for (service = services; service; service = service->next)
329 {
330 /* handle new connections on listeners */
331 if ((service->fd != -1)
332 && (FD_ISSET(service->fd, &read_fds)))
333 {
334 if (service->max_connections > 0)
335 add_connection(service, command_context);
336 else
337 {
338 struct sockaddr_in sin;
339 unsigned int address_size = sizeof(sin);
340 int tmp_fd;
341 tmp_fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size);
342 close_socket(tmp_fd);
343 INFO("rejected '%s' connection, no more connections allowed", service->name);
344 }
345 }
346
347 /* handle activity on connections */
348 if (service->connections)
349 {
350 connection_t *c;
351
352 for (c = service->connections; c;)
353 {
354 if ((FD_ISSET(c->fd, &read_fds)) || c->input_pending)
355 {
356 if (service->input(c) != ERROR_OK)
357 {
358 connection_t *next = c->next;
359 remove_connection(service, c);
360 INFO("dropped '%s' connection", service->name);
361 c = next;
362 continue;
363 }
364 }
365 c = c->next;
366 }
367 }
368 }
369
370 #ifndef _WIN32
371 if (FD_ISSET(fileno(stdin), &read_fds))
372 {
373 if (getc(stdin) == 'x')
374 {
375 shutdown_openocd = 1;
376 }
377 }
378 #else
379 MSG msg;
380 while (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
381 {
382 if (msg.message == WM_QUIT)
383 shutdown_openocd = 1;
384 }
385 #endif
386 }
387
388 return ERROR_OK;
389 }
390
391 #ifdef _WIN32
392 BOOL WINAPI ControlHandler(DWORD dwCtrlType)
393 {
394 shutdown_openocd = 1;
395 return TRUE;
396 }
397
398 void sig_handler(int sig) {
399 shutdown_openocd = 1;
400 }
401 #endif
402
403 int server_init()
404 {
405 #ifdef _WIN32
406 WORD wVersionRequested;
407 WSADATA wsaData;
408
409 wVersionRequested = MAKEWORD( 2, 2 );
410
411 if (WSAStartup(wVersionRequested, &wsaData) != 0)
412 {
413 ERROR("Failed to Open Winsock");
414 exit(-1);
415 }
416
417 SetConsoleCtrlHandler( ControlHandler, TRUE );
418
419 signal(SIGINT, sig_handler);
420 signal(SIGTERM, sig_handler);
421 signal(SIGBREAK, sig_handler);
422 signal(SIGABRT, sig_handler);
423 #endif
424
425
426 return ERROR_OK;
427 }
428
429 int server_quit()
430 {
431 remove_services();
432
433 #ifdef _WIN32
434 WSACleanup();
435 SetConsoleCtrlHandler( ControlHandler, FALSE );
436 #endif
437
438 return ERROR_OK;
439 }
440
441 int server_register_commands(command_context_t *context)
442 {
443 register_command(context, NULL, "shutdown", handle_shutdown_command,
444 COMMAND_ANY, "shut the server down");
445
446 return ERROR_OK;
447 }
448
449 /* tell the server we want to shut down */
450 int handle_shutdown_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
451 {
452 shutdown_openocd = 1;
453
454 return ERROR_COMMAND_CLOSE_CONNECTION;
455 }
456

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)