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

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)