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