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