1 /* Serial port emulation using sockets.
2 Copyright (C) 1998-2022 Free Software Foundation, Inc.
3 Contributed by Cygnus Solutions.
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.
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.
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/>. */
18 /* FIXME: will obviously need to evolve.
19 - connectionless sockets might be more appropriate. */
21 /* This must come before any other includes. */
35 #include <arpa/inet.h>
36 #include <netinet/in.h>
37 #include <sys/select.h>
38 #include <sys/socket.h>
40 #include <sys/types.h>
43 #include "sim-assert.h"
44 #include "sim-options.h"
46 #include "dv-sockser.h"
48 #ifndef HAVE_SOCKLEN_T
49 typedef int socklen_t
;
53 /* Compromise between eating cpu and properly busy-waiting.
54 One could have an option to set this but for now that seems
56 #define DEFAULT_TIMEOUT 1000 /* microseconds */
58 /* FIXME: These should allocated at run time and kept with other simulator
59 state (duh...). Later. */
60 const 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. */
63 static unsigned int sockser_timeout
= DEFAULT_TIMEOUT
;
64 static int sockser_listen_fd
= -1;
65 static int sockser_fd
= -1;
67 /* FIXME: use tree properties when they're ready. */
70 OPTION_ADDR
= OPTION_START
73 static DECLARE_OPTION_HANDLER (sockser_option_handler
);
75 static const OPTION sockser_options
[] =
77 { { "sockser-addr", required_argument
, NULL
, OPTION_ADDR
},
78 '\0', "SOCKET ADDRESS", "Set serial emulation socket address",
79 sockser_option_handler
, NULL
},
80 { { NULL
, no_argument
, NULL
, 0 }, '\0', NULL
, NULL
, NULL
, NULL
}
84 sockser_option_handler (SIM_DESC sd
, sim_cpu
*cpu
, int opt
,
85 char *arg
, int is_command
)
98 dv_sockser_init (SIM_DESC sd
)
100 struct hostent
*hostent
;
101 struct sockaddr_in sockaddr
;
103 const char *port_str
;
106 if (STATE_ENVIRONMENT (sd
) != OPERATING_ENVIRONMENT
107 || sockser_addr
== NULL
)
110 if (*sockser_addr
== '/')
112 /* support for these can come later */
113 sim_io_eprintf (sd
, "sockser init: unix domain sockets not supported: `%s'\n",
118 port_str
= strchr (sockser_addr
, ':');
121 sim_io_eprintf (sd
, "sockser init: missing port number: `%s'\n",
125 tmp
= port_str
- sockser_addr
;
126 if (tmp
>= sizeof hostname
)
127 tmp
= sizeof (hostname
) - 1;
128 strncpy (hostname
, sockser_addr
, tmp
);
129 hostname
[tmp
] = '\000';
130 port
= atoi (port_str
+ 1);
132 hostent
= gethostbyname (hostname
);
135 sim_io_eprintf (sd
, "sockser init: unknown host: %s\n",
140 sockser_listen_fd
= socket (PF_INET
, SOCK_STREAM
, 0);
141 if (sockser_listen_fd
== -1)
143 sim_io_eprintf (sd
, "sockser init: unable to get socket: %s\n",
148 sockaddr
.sin_family
= PF_INET
;
149 sockaddr
.sin_port
= htons (port
);
150 memcpy (&sockaddr
.sin_addr
.s_addr
, hostent
->h_addr
,
151 sizeof (struct in_addr
));
154 if (setsockopt (sockser_listen_fd
, SOL_SOCKET
, SO_REUSEADDR
, (void*)& tmp
, sizeof (tmp
)) < 0)
156 sim_io_eprintf (sd
, "sockser init: unable to set SO_REUSEADDR: %s\n",
159 if (bind (sockser_listen_fd
, (struct sockaddr
*) &sockaddr
, sizeof (sockaddr
)) < 0)
161 sim_io_eprintf (sd
, "sockser init: unable to bind socket address: %s\n",
163 close (sockser_listen_fd
);
164 sockser_listen_fd
= -1;
167 if (listen (sockser_listen_fd
, 1) < 0)
169 sim_io_eprintf (sd
, "sockser init: unable to set up listener: %s\n",
171 close (sockser_listen_fd
);
172 sockser_listen_fd
= -1;
176 /* Handle writes to missing client -> SIGPIPE.
177 ??? Need a central signal management module. */
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
);
192 dv_sockser_uninstall (SIM_DESC sd
)
194 if (sockser_listen_fd
!= -1)
196 close (sockser_listen_fd
);
197 sockser_listen_fd
= -1;
199 if (sockser_fd
!= -1)
206 /* Provide a prototype to silence -Wmissing-prototypes. */
207 extern MODULE_INIT_FN sim_install_dv_sockser
;
210 sim_install_dv_sockser (SIM_DESC sd
)
212 SIM_ASSERT (STATE_MAGIC (sd
) == SIM_MAGIC_NUMBER
);
213 if (sim_add_option_table (sd
, NULL
, sockser_options
) != SIM_RC_OK
)
215 sim_module_add_init_fn (sd
, dv_sockser_init
);
216 sim_module_add_uninstall_fn (sd
, dv_sockser_uninstall
);
221 connected_p (SIM_DESC sd
)
226 struct sockaddr sockaddr
;
229 if (sockser_listen_fd
== -1)
234 /* FIXME: has client gone away? */
238 /* Not connected. Connect with a client if there is one. */
241 FD_SET (sockser_listen_fd
, &readfds
);
243 /* ??? One can certainly argue this should be done differently,
244 but for now this is sufficient. */
246 tv
.tv_usec
= sockser_timeout
;
248 numfds
= select (sockser_listen_fd
+ 1, &readfds
, 0, 0, &tv
);
252 addrlen
= sizeof (sockaddr
);
253 sockser_fd
= accept (sockser_listen_fd
, &sockaddr
, &addrlen
);
254 if (sockser_fd
== -1)
257 /* Set non-blocking i/o. */
258 #if defined(F_GETFL) && defined(O_NONBLOCK)
259 flags
= fcntl (sockser_fd
, F_GETFL
);
261 if (fcntl (sockser_fd
, F_SETFL
, flags
) == -1)
263 sim_io_eprintf (sd
, "unable to set nonblocking i/o");
273 dv_sockser_status (SIM_DESC sd
)
275 int numrfds
,numwfds
,status
;
277 fd_set readfds
,writefds
;
279 /* status to return if the socket isn't set up, or select fails */
280 status
= DV_SOCKSER_INPUT_EMPTY
| DV_SOCKSER_OUTPUT_EMPTY
|
281 DV_SOCKSER_DISCONNECTED
;
283 if (! connected_p (sd
))
288 FD_SET (sockser_fd
, &readfds
);
289 FD_SET (sockser_fd
, &writefds
);
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. */
299 #define SOCKSER_TIMEOUT_FREQ 42
300 if (++n
== SOCKSER_TIMEOUT_FREQ
)
305 tv
.tv_usec
= sockser_timeout
;
306 numrfds
= select (sockser_fd
+ 1, &readfds
, 0, 0, &tv
);
309 numwfds
= select (sockser_fd
+ 1, 0, &writefds
, 0, &tv
);
311 else /* do both selects at once */
315 numrfds
= numwfds
= select (sockser_fd
+ 1, &readfds
, &writefds
, 0, &tv
);
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
;
328 dv_sockser_write_buffer (SIM_DESC sd
, const unsigned char *buffer
,
333 if (! connected_p (sd
))
335 n
= write (sockser_fd
, buffer
, nr_bytes
);
351 dv_sockser_write (SIM_DESC sd
, unsigned char c
)
353 return dv_sockser_write_buffer (sd
, &c
, 1);
357 dv_sockser_read (SIM_DESC sd
)
362 if (! connected_p (sd
))
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. */