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