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