]> git.sur5r.net Git - openocd/blob - src/server/server.c
3ad6f377a5e71022f1eed24116462758cdb8c35f
[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 #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 #if 0
328                         if (shutdown_openocd)
329                                 return ERROR_COMMAND_CLOSE_CONNECTION;
330                         
331                         handle_target();
332 #endif
333                 }
334                 
335                 for (service = services; service; service = service->next)
336                 {
337                         /* handle new connections on listeners */
338                         if ((service->fd != -1) 
339                                 && (FD_ISSET(service->fd, &read_fds))) 
340                         {
341                                 if (service->max_connections > 0)
342                                         add_connection(service, command_context);
343                                 else
344                                 {
345                                         struct sockaddr_in sin;
346                                         unsigned int address_size = sizeof(sin);
347                                         int tmp_fd;
348                                         tmp_fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size);
349                                         close_socket(tmp_fd);
350                                         INFO("rejected '%s' connection, no more connections allowed", service->name);
351                                 }
352                         }
353                         
354                         /* handle activity on connections */
355                         if (service->connections)
356                         {
357                                 connection_t *c;
358                                 
359                                 for (c = service->connections; c;)
360                                 {
361                                         if ((FD_ISSET(c->fd, &read_fds)) || c->input_pending)
362                                         {
363                                                 if (service->input(c) != ERROR_OK)
364                                                 {
365                                                         connection_t *next = c->next;
366                                                         remove_connection(service, c);
367                                                         INFO("dropped '%s' connection", service->name);
368                                                         c = next;
369                                                         continue;
370                                                 }
371                                         }
372                                         c = c->next;
373                                 }
374                         }
375                 }
376                 
377 #ifndef _WIN32
378                 if (FD_ISSET(fileno(stdin), &read_fds))
379                 {
380                         if (getc(stdin) == 'x')
381                         {
382                                 shutdown_openocd = 1;
383                         }
384                 }
385 #else
386                 MSG msg;
387                 while (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
388                 {
389                         if (msg.message == WM_QUIT)
390                                 shutdown_openocd = 1;
391                 }
392 #endif
393         }
394         
395         return ERROR_OK;
396 }
397
398 #ifdef _WIN32
399 BOOL WINAPI ControlHandler(DWORD dwCtrlType)
400 {
401     shutdown_openocd = 1;
402     return TRUE;
403 }
404
405 void sig_handler(int sig) {
406     shutdown_openocd = 1;
407 }
408 #endif
409
410 int server_init()
411 {
412 #ifdef _WIN32
413         WORD wVersionRequested;
414         WSADATA wsaData;
415
416         wVersionRequested = MAKEWORD( 2, 2 );
417
418         if (WSAStartup(wVersionRequested, &wsaData) != 0)
419         {
420                 ERROR("Failed to Open Winsock");
421                 exit(-1);
422         }
423
424         SetConsoleCtrlHandler( ControlHandler, TRUE );
425
426         signal(SIGINT, sig_handler);
427         signal(SIGTERM, sig_handler);
428         signal(SIGBREAK, sig_handler);
429         signal(SIGABRT, sig_handler);
430 #endif
431
432         
433         return ERROR_OK;
434 }
435
436 int server_quit()
437 {
438         remove_services();
439
440 #ifdef _WIN32
441         WSACleanup();
442         SetConsoleCtrlHandler( ControlHandler, FALSE );
443 #endif
444
445         return ERROR_OK;
446 }
447
448 int server_register_commands(command_context_t *context)
449 {
450         register_command(context, NULL, "shutdown", handle_shutdown_command,
451                                          COMMAND_ANY, "shut the server down");
452         
453         return ERROR_OK;
454 }
455
456 /* tell the server we want to shut down */
457 int handle_shutdown_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
458 {
459         shutdown_openocd = 1;
460
461         return ERROR_COMMAND_CLOSE_CONNECTION;
462 }
463