- added support for AT91SAM7A3 flash (patch from andre renaud, thanks)
[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 #include "server.h"
21
22 #include "log.h"
23 #include "telnet_server.h"
24 #include "target.h"
25
26 #include <command.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <fcntl.h>
34 #include <signal.h>
35
36 service_t *services = NULL;
37
38 /* shutdown_openocd == 1: exit the main event loop, and quit the debugger */
39 static int shutdown_openocd = 0;
40 int handle_shutdown_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
41
42 int add_connection(service_t *service, command_context_t *cmd_ctx)
43 {
44 unsigned int address_size;
45 connection_t *c, *p;
46 int retval;
47
48 c = malloc(sizeof(connection_t));
49 c->fd = -1;
50 memset(&c->sin, 0, sizeof(c->sin));
51 c->cmd_ctx = copy_command_context(cmd_ctx);
52 c->service = service;
53 c->input_pending = 0;
54 c->priv = NULL;
55 c->next = NULL;
56
57 address_size = sizeof(c->sin);
58 c->fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size);
59
60 if ((retval = service->new_connection(c)) == ERROR_OK)
61 {
62 INFO("accepted '%s' connection from %i", service->name, c->sin.sin_port);
63 }
64 else
65 {
66 close(c->fd);
67 INFO("attempted '%s' connection rejected", service->name);
68 free(c);
69 }
70
71 if (service->connections)
72 {
73 for (p = service->connections; p && p->next; p = p->next);
74 if (p)
75 p->next = c;
76 }
77 else
78 {
79 service->connections = c;
80 }
81
82 service->max_connections--;
83
84 return ERROR_OK;
85 }
86
87 int remove_connection(service_t *service, connection_t *connection)
88 {
89 connection_t *c, *p = NULL;
90
91 /* find connection */
92 for (c = service->connections; c; c = c->next)
93 {
94 if (c->fd == connection->fd)
95 {
96 /* unlink connection */
97 if (p)
98 p->next = c->next;
99 else
100 service->connections = c->next;
101
102 service->connection_closed(c);
103 close(c->fd);
104
105 command_done(c->cmd_ctx);
106
107 /* delete connection */
108 free(c);
109
110 service->max_connections++;
111 break;
112 }
113
114 /* remember the last connection for unlinking */
115 p = c;
116 }
117
118 return ERROR_OK;
119 }
120
121 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)
122 {
123 service_t *c, *p;
124 int so_reuseaddr_option = 1;
125 int oldopts;
126
127 c = malloc(sizeof(service_t));
128
129 c->name = strdup(name);
130 c->type = type;
131 c->port = port;
132 c->max_connections = max_connections;
133 c->fd = -1;
134 c->connections = NULL;
135 c->new_connection = new_connection_handler;
136 c->input = input_handler;
137 c->connection_closed = connection_closed_handler;
138 c->priv = priv;
139 c->next = NULL;
140
141 if ((c->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
142 {
143 ERROR("error creating socket: %s", strerror(errno));
144 exit(-1);
145 }
146
147 setsockopt(c->fd, SOL_SOCKET, SO_REUSEADDR, &so_reuseaddr_option, sizeof(int));
148
149 oldopts = fcntl(c->fd, F_GETFL, 0);
150 fcntl(c->fd, F_SETFL, oldopts | O_NONBLOCK);
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, *p = NULL;
186
187 /* find service */
188 for (c = services; c; c = c->next)
189 {
190 if (c->port == port)
191 {
192 /* unlink service */
193 if (p)
194 p->next = c->next;
195 else
196 services = c->next;
197
198 if (c->name)
199 free(c->name);
200
201 /* delete service */
202 free(c);
203 }
204
205 /* remember the last service for unlinking */
206 p = c;
207 }
208
209 return ERROR_OK;
210 }
211
212 int server_loop(command_context_t *command_context)
213 {
214 service_t *service;
215
216 /* used in select() */
217 fd_set read_fds;
218 struct timeval tv;
219 int fd_max;
220
221 /* used in accept() */
222 int retval;
223
224 if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
225 ERROR("couldn't set SIGPIPE to SIG_IGN");
226
227 /* do regular tasks after at most 10ms */
228 tv.tv_sec = 0;
229 tv.tv_usec = 10000;
230
231 while(!shutdown_openocd)
232 {
233 /* monitor sockets for acitvity */
234 fd_max = 0;
235 FD_ZERO(&read_fds);
236
237 /* add service and connection fds to read_fds */
238 for (service = services; service; service = service->next)
239 {
240 if (service->fd != -1)
241 {
242 /* listen for new connections */
243 FD_SET(service->fd, &read_fds);
244
245 if (service->fd > fd_max)
246 fd_max = service->fd;
247 }
248
249 if (service->connections)
250 {
251 connection_t *c;
252
253 for (c = service->connections; c; c = c->next)
254 {
255 /* check for activity on the connection */
256 FD_SET(c->fd, &read_fds);
257 if (c->fd > fd_max)
258 fd_max = c->fd;
259 }
260 }
261 }
262
263 /* add STDIN to read_fds */
264 FD_SET(fileno(stdin), &read_fds);
265
266 if ((retval = select(fd_max + 1, &read_fds, NULL, NULL, &tv)) == -1)
267 {
268 if (errno == EINTR)
269 FD_ZERO(&read_fds);
270 else
271 {
272 ERROR("error during select: %s", strerror(errno));
273 exit(-1);
274 }
275 }
276
277 target_call_timer_callbacks();
278
279 if (retval == 0)
280 {
281 /* do regular tasks after at most 100ms */
282 tv.tv_sec = 0;
283 tv.tv_usec = 10000;
284
285 #if 0
286 if (shutdown_openocd)
287 return ERROR_COMMAND_CLOSE_CONNECTION;
288
289 handle_target();
290 #endif
291 }
292
293 for (service = services; service; service = service->next)
294 {
295 /* handle new connections on listeners */
296 if ((service->fd != -1)
297 && (FD_ISSET(service->fd, &read_fds)))
298 {
299 if (service->max_connections > 0)
300 add_connection(service, command_context);
301 else
302 {
303 struct sockaddr_in sin;
304 unsigned int address_size = sizeof(sin);
305 int tmp_fd;
306 tmp_fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size);
307 close(tmp_fd);
308 INFO("rejected '%s' connection, no more connections allowed", service->name);
309 }
310 }
311
312 /* handle activity on connections */
313 if (service->connections)
314 {
315 connection_t *c;
316
317 for (c = service->connections; c;)
318 {
319 if ((FD_ISSET(c->fd, &read_fds)) || c->input_pending)
320 {
321 if (service->input(c) != ERROR_OK)
322 {
323 connection_t *next = c->next;
324 remove_connection(service, c);
325 INFO("dropped '%s' connection", service->name);
326 c = next;
327 continue;
328 }
329 }
330 c = c->next;
331 }
332 }
333 }
334
335 if (FD_ISSET(fileno(stdin), &read_fds))
336 {
337 if (getc(stdin) == 'x')
338 {
339 shutdown_openocd = 1;
340 }
341 }
342 }
343
344 return ERROR_OK;
345 }
346
347 int server_init()
348 {
349
350 return ERROR_OK;
351 }
352
353 int server_register_commands(command_context_t *context)
354 {
355 register_command(context, NULL, "shutdown", handle_shutdown_command,
356 COMMAND_ANY, "shut the server down");
357
358 return ERROR_OK;
359 }
360
361 /* tell the server we want to shut down */
362 int handle_shutdown_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
363 {
364 shutdown_openocd = 1;
365
366 return ERROR_COMMAND_CLOSE_CONNECTION;
367 }
368

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)