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