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