1 /* Serial port emulation using sockets.
2 Copyright (C) 1998-2021 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 <sys/types.h>
37 #include <netinet/in.h>
38 #include <arpa/inet.h>
40 #include <sys/select.h>
41 #include <sys/socket.h>
44 #include "sim-assert.h"
45 #include "sim-options.h"
47 #include "dv-sockser.h"
49 #ifndef HAVE_SOCKLEN_T
50 typedef int socklen_t
;
54 /* Compromise between eating cpu and properly busy-waiting.
55 One could have an option to set this but for now that seems
57 #define DEFAULT_TIMEOUT 1000 /* microseconds */
59 /* FIXME: These should allocated at run time and kept with other simulator
60 state (duh...). Later. */
61 const char * sockser_addr
= NULL
;
62 /* Timeout in microseconds during status flag computation.
63 Setting this to zero achieves proper busy wait semantics but eats cpu. */
64 static unsigned int sockser_timeout
= DEFAULT_TIMEOUT
;
65 static int sockser_listen_fd
= -1;
66 static int sockser_fd
= -1;
68 /* FIXME: use tree properties when they're ready. */
71 OPTION_ADDR
= OPTION_START
74 static DECLARE_OPTION_HANDLER (sockser_option_handler
);
76 static const OPTION sockser_options
[] =
78 { { "sockser-addr", required_argument
, NULL
, OPTION_ADDR
},
79 '\0', "SOCKET ADDRESS", "Set serial emulation socket address",
80 sockser_option_handler
, NULL
},
81 { { NULL
, no_argument
, NULL
, 0 }, '\0', NULL
, NULL
, NULL
, NULL
}
85 sockser_option_handler (SIM_DESC sd
, sim_cpu
*cpu
, int opt
,
86 char *arg
, int is_command
)
99 dv_sockser_init (SIM_DESC sd
)
101 struct hostent
*hostent
;
102 struct sockaddr_in sockaddr
;
104 const char *port_str
;
107 if (STATE_ENVIRONMENT (sd
) != OPERATING_ENVIRONMENT
108 || sockser_addr
== NULL
)
111 if (*sockser_addr
== '/')
113 /* support for these can come later */
114 sim_io_eprintf (sd
, "sockser init: unix domain sockets not supported: `%s'\n",
119 port_str
= strchr (sockser_addr
, ':');
122 sim_io_eprintf (sd
, "sockser init: missing port number: `%s'\n",
126 tmp
= port_str
- sockser_addr
;
127 if (tmp
>= sizeof hostname
)
128 tmp
= sizeof (hostname
) - 1;
129 strncpy (hostname
, sockser_addr
, tmp
);
130 hostname
[tmp
] = '\000';
131 port
= atoi (port_str
+ 1);
133 hostent
= gethostbyname (hostname
);
136 sim_io_eprintf (sd
, "sockser init: unknown host: %s\n",
141 sockser_listen_fd
= socket (PF_INET
, SOCK_STREAM
, 0);
142 if (sockser_listen_fd
== -1)
144 sim_io_eprintf (sd
, "sockser init: unable to get socket: %s\n",
149 sockaddr
.sin_family
= PF_INET
;
150 sockaddr
.sin_port
= htons (port
);
151 memcpy (&sockaddr
.sin_addr
.s_addr
, hostent
->h_addr
,
152 sizeof (struct in_addr
));
155 if (setsockopt (sockser_listen_fd
, SOL_SOCKET
, SO_REUSEADDR
, (void*)& tmp
, sizeof (tmp
)) < 0)
157 sim_io_eprintf (sd
, "sockser init: unable to set SO_REUSEADDR: %s\n",
160 if (bind (sockser_listen_fd
, (struct sockaddr
*) &sockaddr
, sizeof (sockaddr
)) < 0)
162 sim_io_eprintf (sd
, "sockser init: unable to bind socket address: %s\n",
164 close (sockser_listen_fd
);
165 sockser_listen_fd
= -1;
168 if (listen (sockser_listen_fd
, 1) < 0)
170 sim_io_eprintf (sd
, "sockser init: unable to set up listener: %s\n",
172 close (sockser_listen_fd
);
173 sockser_listen_fd
= -1;
177 /* Handle writes to missing client -> SIGPIPE.
178 ??? Need a central signal management module. */
181 RETSIGTYPE (*orig
) ();
182 orig
= signal (SIGPIPE
, SIG_IGN
);
183 /* If a handler is already set up, don't mess with it. */
184 if (orig
!= SIG_DFL
&& orig
!= SIG_IGN
)
185 signal (SIGPIPE
, orig
);
193 dv_sockser_uninstall (SIM_DESC sd
)
195 if (sockser_listen_fd
!= -1)
197 close (sockser_listen_fd
);
198 sockser_listen_fd
= -1;
200 if (sockser_fd
!= -1)
207 /* Provide a prototype to silence -Wmissing-prototypes. */
208 extern MODULE_INIT_FN sim_install_dv_sockser
;
211 sim_install_dv_sockser (SIM_DESC sd
)
213 SIM_ASSERT (STATE_MAGIC (sd
) == SIM_MAGIC_NUMBER
);
214 if (sim_add_option_table (sd
, NULL
, sockser_options
) != SIM_RC_OK
)
216 sim_module_add_init_fn (sd
, dv_sockser_init
);
217 sim_module_add_uninstall_fn (sd
, dv_sockser_uninstall
);
222 connected_p (SIM_DESC sd
)
227 struct sockaddr sockaddr
;
230 if (sockser_listen_fd
== -1)
235 /* FIXME: has client gone away? */
239 /* Not connected. Connect with a client if there is one. */
242 FD_SET (sockser_listen_fd
, &readfds
);
244 /* ??? One can certainly argue this should be done differently,
245 but for now this is sufficient. */
247 tv
.tv_usec
= sockser_timeout
;
249 numfds
= select (sockser_listen_fd
+ 1, &readfds
, 0, 0, &tv
);
253 addrlen
= sizeof (sockaddr
);
254 sockser_fd
= accept (sockser_listen_fd
, &sockaddr
, &addrlen
);
255 if (sockser_fd
== -1)
258 /* Set non-blocking i/o. */
259 #if defined(F_GETFL) && defined(O_NONBLOCK)
260 flags
= fcntl (sockser_fd
, F_GETFL
);
262 if (fcntl (sockser_fd
, F_SETFL
, flags
) == -1)
264 sim_io_eprintf (sd
, "unable to set nonblocking i/o");
274 dv_sockser_status (SIM_DESC sd
)
276 int numrfds
,numwfds
,status
;
278 fd_set readfds
,writefds
;
280 /* status to return if the socket isn't set up, or select fails */
281 status
= DV_SOCKSER_INPUT_EMPTY
| DV_SOCKSER_OUTPUT_EMPTY
|
282 DV_SOCKSER_DISCONNECTED
;
284 if (! connected_p (sd
))
289 FD_SET (sockser_fd
, &readfds
);
290 FD_SET (sockser_fd
, &writefds
);
292 /* ??? One can certainly argue this should be done differently,
293 but for now this is sufficient. The read is done separately
294 from the write to enforce the delay which we heuristically set to
295 once every SOCKSER_TIMEOUT_FREQ tries.
296 No, this isn't great for SMP situations, blah blah blah. */
300 #define SOCKSER_TIMEOUT_FREQ 42
301 if (++n
== SOCKSER_TIMEOUT_FREQ
)
306 tv
.tv_usec
= sockser_timeout
;
307 numrfds
= select (sockser_fd
+ 1, &readfds
, 0, 0, &tv
);
310 numwfds
= select (sockser_fd
+ 1, 0, &writefds
, 0, &tv
);
312 else /* do both selects at once */
316 numrfds
= numwfds
= select (sockser_fd
+ 1, &readfds
, &writefds
, 0, &tv
);
321 if (numrfds
<= 0 || ! FD_ISSET (sockser_fd
, &readfds
))
322 status
|= DV_SOCKSER_INPUT_EMPTY
;
323 if (numwfds
<= 0 || FD_ISSET (sockser_fd
, &writefds
))
324 status
|= DV_SOCKSER_OUTPUT_EMPTY
;
329 dv_sockser_write_buffer (SIM_DESC sd
, const unsigned char *buffer
,
334 if (! connected_p (sd
))
336 n
= write (sockser_fd
, buffer
, nr_bytes
);
352 dv_sockser_write (SIM_DESC sd
, unsigned char c
)
354 return dv_sockser_write_buffer (sd
, &c
, 1);
358 dv_sockser_read (SIM_DESC sd
)
363 if (! connected_p (sd
))
365 n
= read (sockser_fd
, &c
, 1);
366 /* ??? We're assuming semantics that may not be correct for all hosts.
367 In particular (from cvssrc/src/server.c), this assumes that we are using
368 BSD or POSIX nonblocking I/O. System V nonblocking I/O returns zero if
369 there is nothing to read. */