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