]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/common/dv-sockser.c
gdb: remove unused includes in symfile.c
[thirdparty/binutils-gdb.git] / sim / common / dv-sockser.c
CommitLineData
c906108c 1/* Serial port emulation using sockets.
1d506c26 2 Copyright (C) 1998-2024 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 32#include <unistd.h>
c906108c 33#include <arpa/inet.h>
20a8e078 34#include <netinet/in.h>
2726bbc3 35#include <sys/select.h>
c906108c 36#include <sys/socket.h>
20a8e078
MF
37#include <sys/time.h>
38#include <sys/types.h>
c906108c 39
287fbf95 40#include "sim-main.h"
c906108c
SS
41#include "sim-assert.h"
42#include "sim-options.h"
43
44#include "dv-sockser.h"
45\f
75005b3a
MF
46#ifndef HAVE_SOCKLEN_T
47typedef int socklen_t;
48#endif
c906108c 49\f
c906108c
SS
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. */
58const 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. */
61static unsigned int sockser_timeout = DEFAULT_TIMEOUT;
62static int sockser_listen_fd = -1;
63static int sockser_fd = -1;
64\f
65/* FIXME: use tree properties when they're ready. */
66
67typedef enum {
68 OPTION_ADDR = OPTION_START
69} SOCKSER_OPTIONS;
70
71static DECLARE_OPTION_HANDLER (sockser_option_handler);
72
73static const OPTION sockser_options[] =
74{
75 { { "sockser-addr", required_argument, NULL, OPTION_ADDR },
76 '\0', "SOCKET ADDRESS", "Set serial emulation socket address",
21cf617c
MF
77 sockser_option_handler, NULL },
78 { { NULL, no_argument, NULL, 0 }, '\0', NULL, NULL, NULL, NULL }
c906108c
SS
79};
80
81static SIM_RC
82sockser_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
95static SIM_RC
96dv_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 }
548a3e15
AC
123 tmp = port_str - sockser_addr;
124 if (tmp >= sizeof hostname)
125 tmp = sizeof (hostname) - 1;
c906108c
SS
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);
363a6e9f 139 if (sockser_listen_fd == -1)
c906108c
SS
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;
34b47c38 147 sockaddr.sin_port = htons (port);
c906108c
SS
148 memcpy (&sockaddr.sin_addr.s_addr, hostent->h_addr,
149 sizeof (struct in_addr));
150
151 tmp = 1;
34b47c38 152 if (setsockopt (sockser_listen_fd, SOL_SOCKET, SO_REUSEADDR, (void*)& tmp, sizeof (tmp)) < 0)
c906108c
SS
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. */
03de8f26 176#ifdef SIGPIPE
c906108c
SS
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 }
03de8f26 184#endif
c906108c
SS
185
186 return SIM_RC_OK;
187}
188
189static void
190dv_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
328e805b
MF
204/* Provide a prototype to silence -Wmissing-prototypes. */
205extern MODULE_INIT_FN sim_install_dv_sockser;
206
c906108c 207SIM_RC
328e805b 208sim_install_dv_sockser (SIM_DESC sd)
c906108c
SS
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
218static int
219connected_p (SIM_DESC sd)
220{
221 int numfds,flags;
222 struct timeval tv;
223 fd_set readfds;
224 struct sockaddr sockaddr;
75005b3a 225 socklen_t addrlen;
c906108c
SS
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
9846de1b 250 addrlen = sizeof (sockaddr);
c906108c 251 sockser_fd = accept (sockser_listen_fd, &sockaddr, &addrlen);
363a6e9f 252 if (sockser_fd == -1)
c906108c
SS
253 return 0;
254
255 /* Set non-blocking i/o. */
ee73abf2 256#if defined(F_GETFL) && defined(O_NONBLOCK)
c906108c 257 flags = fcntl (sockser_fd, F_GETFL);
ee73abf2 258 flags |= O_NONBLOCK;
c906108c
SS
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 }
03de8f26 266#endif
c906108c
SS
267 return 1;
268}
269
270int
271dv_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 */
e8a76151
MF
278 status = DV_SOCKSER_INPUT_EMPTY | DV_SOCKSER_OUTPUT_EMPTY |
279 DV_SOCKSER_DISCONNECTED;
c906108c
SS
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
325int
6ab5626b
MF
326dv_sockser_write_buffer (SIM_DESC sd, const unsigned char *buffer,
327 unsigned nr_bytes)
c906108c
SS
328{
329 int n;
330
331 if (! connected_p (sd))
332 return -1;
6ab5626b 333 n = write (sockser_fd, buffer, nr_bytes);
c906108c
SS
334 if (n == -1)
335 {
336 if (errno == EPIPE)
337 {
338 close (sockser_fd);
339 sockser_fd = -1;
340 }
341 return -1;
342 }
6ab5626b 343 if (n != nr_bytes)
c906108c 344 return -1;
6ab5626b
MF
345 return nr_bytes;
346}
347
348int
349dv_sockser_write (SIM_DESC sd, unsigned char c)
350{
351 return dv_sockser_write_buffer (sd, &c, 1);
c906108c
SS
352}
353
354int
355dv_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}