]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/common/dv-sockser.c
32ba57c885caf02304a999fecefe489499e48aa3
[thirdparty/binutils-gdb.git] / sim / common / dv-sockser.c
1 /* Serial port emulation using sockets.
2 Copyright (C) 1998, 2007-2012 Free Software Foundation, Inc.
3 Contributed by Cygnus Solutions.
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 3 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, see <http://www.gnu.org/licenses/>. */
17
18 /* FIXME: will obviously need to evolve.
19 - connectionless sockets might be more appropriate. */
20
21 #include "sim-main.h"
22
23 #ifdef HAVE_STRING_H
24 #include <string.h>
25 #else
26 #ifdef HAVE_STRINGS_H
27 #include <strings.h>
28 #endif
29 #endif
30 #include <signal.h>
31 #ifdef HAVE_STDLIB_H
32 #include <stdlib.h>
33 #endif
34 #ifdef HAVE_FCNTL_H
35 #include <fcntl.h>
36 #endif
37 #ifdef HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif
40
41 #include <errno.h>
42 #include <sys/types.h>
43 #include <sys/time.h>
44 #include <netinet/in.h>
45 #include <arpa/inet.h>
46 #include <netdb.h>
47 #include <sys/socket.h>
48
49 #ifndef __CYGWIN32__
50 #include <netinet/tcp.h>
51 #endif
52
53 #include "sim-assert.h"
54 #include "sim-options.h"
55
56 #include "dv-sockser.h"
57 \f
58 #ifndef HAVE_SOCKLEN_T
59 typedef int socklen_t;
60 #endif
61
62 /* Get definitions for both O_NONBLOCK and O_NDELAY. */
63
64 #ifndef O_NDELAY
65 #ifdef FNDELAY
66 #define O_NDELAY FNDELAY
67 #else /* ! defined (FNDELAY) */
68 #define O_NDELAY 0
69 #endif /* ! defined (FNDELAY) */
70 #endif /* ! defined (O_NDELAY) */
71
72 #ifndef O_NONBLOCK
73 #ifdef FNBLOCK
74 #define O_NONBLOCK FNBLOCK
75 #else /* ! defined (FNBLOCK) */
76 #define O_NONBLOCK 0
77 #endif /* ! defined (FNBLOCK) */
78 #endif /* ! defined (O_NONBLOCK) */
79 \f
80
81 /* Compromise between eating cpu and properly busy-waiting.
82 One could have an option to set this but for now that seems
83 like featuritis. */
84 #define DEFAULT_TIMEOUT 1000 /* microseconds */
85
86 /* FIXME: These should allocated at run time and kept with other simulator
87 state (duh...). Later. */
88 const char * sockser_addr = NULL;
89 /* Timeout in microseconds during status flag computation.
90 Setting this to zero achieves proper busy wait semantics but eats cpu. */
91 static unsigned int sockser_timeout = DEFAULT_TIMEOUT;
92 static int sockser_listen_fd = -1;
93 static int sockser_fd = -1;
94 \f
95 /* FIXME: use tree properties when they're ready. */
96
97 typedef enum {
98 OPTION_ADDR = OPTION_START
99 } SOCKSER_OPTIONS;
100
101 static DECLARE_OPTION_HANDLER (sockser_option_handler);
102
103 static const OPTION sockser_options[] =
104 {
105 { { "sockser-addr", required_argument, NULL, OPTION_ADDR },
106 '\0', "SOCKET ADDRESS", "Set serial emulation socket address",
107 sockser_option_handler, NULL },
108 { { NULL, no_argument, NULL, 0 }, '\0', NULL, NULL, NULL, NULL }
109 };
110
111 static SIM_RC
112 sockser_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt,
113 char *arg, int is_command)
114 {
115 switch (opt)
116 {
117 case OPTION_ADDR :
118 sockser_addr = arg;
119 break;
120 }
121
122 return SIM_RC_OK;
123 }
124
125 static SIM_RC
126 dv_sockser_init (SIM_DESC sd)
127 {
128 struct hostent *hostent;
129 struct sockaddr_in sockaddr;
130 char hostname[100];
131 const char *port_str;
132 int tmp,port;
133
134 if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT
135 || sockser_addr == NULL)
136 return SIM_RC_OK;
137
138 if (*sockser_addr == '/')
139 {
140 /* support for these can come later */
141 sim_io_eprintf (sd, "sockser init: unix domain sockets not supported: `%s'\n",
142 sockser_addr);
143 return SIM_RC_FAIL;
144 }
145
146 port_str = strchr (sockser_addr, ':');
147 if (!port_str)
148 {
149 sim_io_eprintf (sd, "sockser init: missing port number: `%s'\n",
150 sockser_addr);
151 return SIM_RC_FAIL;
152 }
153 tmp = port_str - sockser_addr;
154 if (tmp >= sizeof hostname)
155 tmp = sizeof (hostname) - 1;
156 strncpy (hostname, sockser_addr, tmp);
157 hostname[tmp] = '\000';
158 port = atoi (port_str + 1);
159
160 hostent = gethostbyname (hostname);
161 if (! hostent)
162 {
163 sim_io_eprintf (sd, "sockser init: unknown host: %s\n",
164 hostname);
165 return SIM_RC_FAIL;
166 }
167
168 sockser_listen_fd = socket (PF_INET, SOCK_STREAM, 0);
169 if (sockser_listen_fd == -1)
170 {
171 sim_io_eprintf (sd, "sockser init: unable to get socket: %s\n",
172 strerror (errno));
173 return SIM_RC_FAIL;
174 }
175
176 sockaddr.sin_family = PF_INET;
177 sockaddr.sin_port = htons (port);
178 memcpy (&sockaddr.sin_addr.s_addr, hostent->h_addr,
179 sizeof (struct in_addr));
180
181 tmp = 1;
182 if (setsockopt (sockser_listen_fd, SOL_SOCKET, SO_REUSEADDR, (void*)& tmp, sizeof (tmp)) < 0)
183 {
184 sim_io_eprintf (sd, "sockser init: unable to set SO_REUSEADDR: %s\n",
185 strerror (errno));
186 }
187 if (bind (sockser_listen_fd, (struct sockaddr *) &sockaddr, sizeof (sockaddr)) < 0)
188 {
189 sim_io_eprintf (sd, "sockser init: unable to bind socket address: %s\n",
190 strerror (errno));
191 close (sockser_listen_fd);
192 sockser_listen_fd = -1;
193 return SIM_RC_FAIL;
194 }
195 if (listen (sockser_listen_fd, 1) < 0)
196 {
197 sim_io_eprintf (sd, "sockser init: unable to set up listener: %s\n",
198 strerror (errno));
199 close (sockser_listen_fd);
200 sockser_listen_fd = -1;
201 return SIM_RC_OK;
202 }
203
204 /* Handle writes to missing client -> SIGPIPE.
205 ??? Need a central signal management module. */
206 {
207 RETSIGTYPE (*orig) ();
208 orig = signal (SIGPIPE, SIG_IGN);
209 /* If a handler is already set up, don't mess with it. */
210 if (orig != SIG_DFL && orig != SIG_IGN)
211 signal (SIGPIPE, orig);
212 }
213
214 return SIM_RC_OK;
215 }
216
217 static void
218 dv_sockser_uninstall (SIM_DESC sd)
219 {
220 if (sockser_listen_fd != -1)
221 {
222 close (sockser_listen_fd);
223 sockser_listen_fd = -1;
224 }
225 if (sockser_fd != -1)
226 {
227 close (sockser_fd);
228 sockser_fd = -1;
229 }
230 }
231
232 SIM_RC
233 dv_sockser_install (SIM_DESC sd)
234 {
235 SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
236 if (sim_add_option_table (sd, NULL, sockser_options) != SIM_RC_OK)
237 return SIM_RC_FAIL;
238 sim_module_add_init_fn (sd, dv_sockser_init);
239 sim_module_add_uninstall_fn (sd, dv_sockser_uninstall);
240 return SIM_RC_OK;
241 }
242
243 static int
244 connected_p (SIM_DESC sd)
245 {
246 int numfds,flags;
247 struct timeval tv;
248 fd_set readfds;
249 struct sockaddr sockaddr;
250 socklen_t addrlen;
251
252 if (sockser_listen_fd == -1)
253 return 0;
254
255 if (sockser_fd >= 0)
256 {
257 /* FIXME: has client gone away? */
258 return 1;
259 }
260
261 /* Not connected. Connect with a client if there is one. */
262
263 FD_ZERO (&readfds);
264 FD_SET (sockser_listen_fd, &readfds);
265
266 /* ??? One can certainly argue this should be done differently,
267 but for now this is sufficient. */
268 tv.tv_sec = 0;
269 tv.tv_usec = sockser_timeout;
270
271 numfds = select (sockser_listen_fd + 1, &readfds, 0, 0, &tv);
272 if (numfds <= 0)
273 return 0;
274
275 addrlen = sizeof (sockaddr);
276 sockser_fd = accept (sockser_listen_fd, &sockaddr, &addrlen);
277 if (sockser_fd == -1)
278 return 0;
279
280 /* Set non-blocking i/o. */
281 flags = fcntl (sockser_fd, F_GETFL);
282 flags |= O_NONBLOCK | O_NDELAY;
283 if (fcntl (sockser_fd, F_SETFL, flags) == -1)
284 {
285 sim_io_eprintf (sd, "unable to set nonblocking i/o");
286 close (sockser_fd);
287 sockser_fd = -1;
288 return 0;
289 }
290 return 1;
291 }
292
293 int
294 dv_sockser_status (SIM_DESC sd)
295 {
296 int numrfds,numwfds,status;
297 struct timeval tv;
298 fd_set readfds,writefds;
299
300 /* status to return if the socket isn't set up, or select fails */
301 status = DV_SOCKSER_INPUT_EMPTY | DV_SOCKSER_OUTPUT_EMPTY |
302 DV_SOCKSER_DISCONNECTED;
303
304 if (! connected_p (sd))
305 return status;
306
307 FD_ZERO (&readfds);
308 FD_ZERO (&writefds);
309 FD_SET (sockser_fd, &readfds);
310 FD_SET (sockser_fd, &writefds);
311
312 /* ??? One can certainly argue this should be done differently,
313 but for now this is sufficient. The read is done separately
314 from the write to enforce the delay which we heuristically set to
315 once every SOCKSER_TIMEOUT_FREQ tries.
316 No, this isn't great for SMP situations, blah blah blah. */
317
318 {
319 static int n;
320 #define SOCKSER_TIMEOUT_FREQ 42
321 if (++n == SOCKSER_TIMEOUT_FREQ)
322 n = 0;
323 if (n == 0)
324 {
325 tv.tv_sec = 0;
326 tv.tv_usec = sockser_timeout;
327 numrfds = select (sockser_fd + 1, &readfds, 0, 0, &tv);
328 tv.tv_sec = 0;
329 tv.tv_usec = 0;
330 numwfds = select (sockser_fd + 1, 0, &writefds, 0, &tv);
331 }
332 else /* do both selects at once */
333 {
334 tv.tv_sec = 0;
335 tv.tv_usec = 0;
336 numrfds = numwfds = select (sockser_fd + 1, &readfds, &writefds, 0, &tv);
337 }
338 }
339
340 status = 0;
341 if (numrfds <= 0 || ! FD_ISSET (sockser_fd, &readfds))
342 status |= DV_SOCKSER_INPUT_EMPTY;
343 if (numwfds <= 0 || FD_ISSET (sockser_fd, &writefds))
344 status |= DV_SOCKSER_OUTPUT_EMPTY;
345 return status;
346 }
347
348 int
349 dv_sockser_write_buffer (SIM_DESC sd, const unsigned char *buffer,
350 unsigned nr_bytes)
351 {
352 int n;
353
354 if (! connected_p (sd))
355 return -1;
356 n = write (sockser_fd, buffer, nr_bytes);
357 if (n == -1)
358 {
359 if (errno == EPIPE)
360 {
361 close (sockser_fd);
362 sockser_fd = -1;
363 }
364 return -1;
365 }
366 if (n != nr_bytes)
367 return -1;
368 return nr_bytes;
369 }
370
371 int
372 dv_sockser_write (SIM_DESC sd, unsigned char c)
373 {
374 return dv_sockser_write_buffer (sd, &c, 1);
375 }
376
377 int
378 dv_sockser_read (SIM_DESC sd)
379 {
380 unsigned char c;
381 int n;
382
383 if (! connected_p (sd))
384 return -1;
385 n = read (sockser_fd, &c, 1);
386 /* ??? We're assuming semantics that may not be correct for all hosts.
387 In particular (from cvssrc/src/server.c), this assumes that we are using
388 BSD or POSIX nonblocking I/O. System V nonblocking I/O returns zero if
389 there is nothing to read. */
390 if (n == 0)
391 {
392 close (sockser_fd);
393 sockser_fd = -1;
394 return -1;
395 }
396 if (n != 1)
397 return -1;
398 return c;
399 }