- prepare OpenOCD for branching, created ./trunk/
[fw/openocd] / 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