1 /* Serial port emulation using sockets.
2 Copyright (C) 1998-2024 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. */
33 #include <arpa/inet.h>
34 #include <netinet/in.h>
35 #include <sys/select.h>
36 #include <sys/socket.h>
38 #include <sys/types.h>
41 #include "sim-assert.h"
42 #include "sim-options.h"
44 #include "dv-sockser.h"
46 #ifndef HAVE_SOCKLEN_T
47 typedef int socklen_t
;
51 /* Compromise between eating cpu and properly busy-waiting.
52 One could have an option to set this but for now that seems
54 #define DEFAULT_TIMEOUT 1000 /* microseconds */
56 /* FIXME: These should allocated at run time and kept with other simulator
57 state (duh...). Later. */
58 const 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. */
61 static unsigned int sockser_timeout
= DEFAULT_TIMEOUT
;
62 static int sockser_listen_fd
= -1;
63 static int sockser_fd
= -1;
65 /* FIXME: use tree properties when they're ready. */
68 OPTION_ADDR
= OPTION_START
71 static DECLARE_OPTION_HANDLER (sockser_option_handler
);
73 static const OPTION sockser_options
[] =
75 { { "sockser-addr", required_argument
, NULL
, OPTION_ADDR
},
76 '\0', "SOCKET ADDRESS", "Set serial emulation socket address",
77 sockser_option_handler
, NULL
},
78 { { NULL
, no_argument
, NULL
, 0 }, '\0', NULL
, NULL
, NULL
, NULL
}
82 sockser_option_handler (SIM_DESC sd
, sim_cpu
*cpu
, int opt
,
83 char *arg
, int is_command
)
96 dv_sockser_init (SIM_DESC sd
)
98 struct hostent
*hostent
;
99 struct sockaddr_in sockaddr
;
101 const char *port_str
;
104 if (STATE_ENVIRONMENT (sd
) != OPERATING_ENVIRONMENT
105 || sockser_addr
== NULL
)
108 if (*sockser_addr
== '/')
110 /* support for these can come later */
111 sim_io_eprintf (sd
, "sockser init: unix domain sockets not supported: `%s'\n",
116 port_str
= strchr (sockser_addr
, ':');
119 sim_io_eprintf (sd
, "sockser init: missing port number: `%s'\n",
123 tmp
= port_str
- sockser_addr
;
124 if (tmp
>= sizeof hostname
)
125 tmp
= sizeof (hostname
) - 1;
126 strncpy (hostname
, sockser_addr
, tmp
);
127 hostname
[tmp
] = '\000';
128 port
= atoi (port_str
+ 1);
130 hostent
= gethostbyname (hostname
);
133 sim_io_eprintf (sd
, "sockser init: unknown host: %s\n",
138 sockser_listen_fd
= socket (PF_INET
, SOCK_STREAM
, 0);
139 if (sockser_listen_fd
== -1)
141 sim_io_eprintf (sd
, "sockser init: unable to get socket: %s\n",
146 sockaddr
.sin_family
= PF_INET
;
147 sockaddr
.sin_port
= htons (port
);
148 memcpy (&sockaddr
.sin_addr
.s_addr
, hostent
->h_addr
,
149 sizeof (struct in_addr
));
152 if (setsockopt (sockser_listen_fd
, SOL_SOCKET
, SO_REUSEADDR
, (void*)& tmp
, sizeof (tmp
)) < 0)
154 sim_io_eprintf (sd
, "sockser init: unable to set SO_REUSEADDR: %s\n",
157 if (bind (sockser_listen_fd
, (struct sockaddr
*) &sockaddr
, sizeof (sockaddr
)) < 0)
159 sim_io_eprintf (sd
, "sockser init: unable to bind socket address: %s\n",
161 close (sockser_listen_fd
);
162 sockser_listen_fd
= -1;
165 if (listen (sockser_listen_fd
, 1) < 0)
167 sim_io_eprintf (sd
, "sockser init: unable to set up listener: %s\n",
169 close (sockser_listen_fd
);
170 sockser_listen_fd
= -1;
174 /* Handle writes to missing client -> SIGPIPE.
175 ??? Need a central signal management module. */
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
);
190 dv_sockser_uninstall (SIM_DESC sd
)
192 if (sockser_listen_fd
!= -1)
194 close (sockser_listen_fd
);
195 sockser_listen_fd
= -1;
197 if (sockser_fd
!= -1)
204 /* Provide a prototype to silence -Wmissing-prototypes. */
205 extern MODULE_INIT_FN sim_install_dv_sockser
;
208 sim_install_dv_sockser (SIM_DESC sd
)
210 SIM_ASSERT (STATE_MAGIC (sd
) == SIM_MAGIC_NUMBER
);
211 if (sim_add_option_table (sd
, NULL
, sockser_options
) != SIM_RC_OK
)
213 sim_module_add_init_fn (sd
, dv_sockser_init
);
214 sim_module_add_uninstall_fn (sd
, dv_sockser_uninstall
);
219 connected_p (SIM_DESC sd
)
224 struct sockaddr sockaddr
;
227 if (sockser_listen_fd
== -1)
232 /* FIXME: has client gone away? */
236 /* Not connected. Connect with a client if there is one. */
239 FD_SET (sockser_listen_fd
, &readfds
);
241 /* ??? One can certainly argue this should be done differently,
242 but for now this is sufficient. */
244 tv
.tv_usec
= sockser_timeout
;
246 numfds
= select (sockser_listen_fd
+ 1, &readfds
, 0, 0, &tv
);
250 addrlen
= sizeof (sockaddr
);
251 sockser_fd
= accept (sockser_listen_fd
, &sockaddr
, &addrlen
);
252 if (sockser_fd
== -1)
255 /* Set non-blocking i/o. */
256 #if defined(F_GETFL) && defined(O_NONBLOCK)
257 flags
= fcntl (sockser_fd
, F_GETFL
);
259 if (fcntl (sockser_fd
, F_SETFL
, flags
) == -1)
261 sim_io_eprintf (sd
, "unable to set nonblocking i/o");
271 dv_sockser_status (SIM_DESC sd
)
273 int numrfds
,numwfds
,status
;
275 fd_set readfds
,writefds
;
277 /* status to return if the socket isn't set up, or select fails */
278 status
= DV_SOCKSER_INPUT_EMPTY
| DV_SOCKSER_OUTPUT_EMPTY
|
279 DV_SOCKSER_DISCONNECTED
;
281 if (! connected_p (sd
))
286 FD_SET (sockser_fd
, &readfds
);
287 FD_SET (sockser_fd
, &writefds
);
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. */
297 #define SOCKSER_TIMEOUT_FREQ 42
298 if (++n
== SOCKSER_TIMEOUT_FREQ
)
303 tv
.tv_usec
= sockser_timeout
;
304 numrfds
= select (sockser_fd
+ 1, &readfds
, 0, 0, &tv
);
307 numwfds
= select (sockser_fd
+ 1, 0, &writefds
, 0, &tv
);
309 else /* do both selects at once */
313 numrfds
= numwfds
= select (sockser_fd
+ 1, &readfds
, &writefds
, 0, &tv
);
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
;
326 dv_sockser_write_buffer (SIM_DESC sd
, const unsigned char *buffer
,
331 if (! connected_p (sd
))
333 n
= write (sockser_fd
, buffer
, nr_bytes
);
349 dv_sockser_write (SIM_DESC sd
, unsigned char c
)
351 return dv_sockser_write_buffer (sd
, &c
, 1);
355 dv_sockser_read (SIM_DESC sd
)
360 if (! connected_p (sd
))
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. */