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. */
37 #include <sys/types.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
42 #include <sys/socket.h>
45 #include <netinet/tcp.h>
48 #include "sim-assert.h"
49 #include "sim-options.h"
51 #include "dv-sockser.h"
53 #ifndef HAVE_SOCKLEN_T
54 typedef int socklen_t
;
57 /* Get definitions for both O_NONBLOCK and O_NDELAY. */
61 #define O_NDELAY FNDELAY
62 #else /* ! defined (FNDELAY) */
64 #endif /* ! defined (FNDELAY) */
65 #endif /* ! defined (O_NDELAY) */
69 #define O_NONBLOCK FNBLOCK
70 #else /* ! defined (FNBLOCK) */
72 #endif /* ! defined (FNBLOCK) */
73 #endif /* ! defined (O_NONBLOCK) */
76 /* Compromise between eating cpu and properly busy-waiting.
77 One could have an option to set this but for now that seems
79 #define DEFAULT_TIMEOUT 1000 /* microseconds */
81 /* FIXME: These should allocated at run time and kept with other simulator
82 state (duh...). Later. */
83 const char * sockser_addr
= NULL
;
84 /* Timeout in microseconds during status flag computation.
85 Setting this to zero achieves proper busy wait semantics but eats cpu. */
86 static unsigned int sockser_timeout
= DEFAULT_TIMEOUT
;
87 static int sockser_listen_fd
= -1;
88 static int sockser_fd
= -1;
90 /* FIXME: use tree properties when they're ready. */
93 OPTION_ADDR
= OPTION_START
96 static DECLARE_OPTION_HANDLER (sockser_option_handler
);
98 static const OPTION sockser_options
[] =
100 { { "sockser-addr", required_argument
, NULL
, OPTION_ADDR
},
101 '\0', "SOCKET ADDRESS", "Set serial emulation socket address",
102 sockser_option_handler
, NULL
},
103 { { NULL
, no_argument
, NULL
, 0 }, '\0', NULL
, NULL
, NULL
, NULL
}
107 sockser_option_handler (SIM_DESC sd
, sim_cpu
*cpu
, int opt
,
108 char *arg
, int is_command
)
121 dv_sockser_init (SIM_DESC sd
)
123 struct hostent
*hostent
;
124 struct sockaddr_in sockaddr
;
126 const char *port_str
;
129 if (STATE_ENVIRONMENT (sd
) != OPERATING_ENVIRONMENT
130 || sockser_addr
== NULL
)
133 if (*sockser_addr
== '/')
135 /* support for these can come later */
136 sim_io_eprintf (sd
, "sockser init: unix domain sockets not supported: `%s'\n",
141 port_str
= strchr (sockser_addr
, ':');
144 sim_io_eprintf (sd
, "sockser init: missing port number: `%s'\n",
148 tmp
= port_str
- sockser_addr
;
149 if (tmp
>= sizeof hostname
)
150 tmp
= sizeof (hostname
) - 1;
151 strncpy (hostname
, sockser_addr
, tmp
);
152 hostname
[tmp
] = '\000';
153 port
= atoi (port_str
+ 1);
155 hostent
= gethostbyname (hostname
);
158 sim_io_eprintf (sd
, "sockser init: unknown host: %s\n",
163 sockser_listen_fd
= socket (PF_INET
, SOCK_STREAM
, 0);
164 if (sockser_listen_fd
== -1)
166 sim_io_eprintf (sd
, "sockser init: unable to get socket: %s\n",
171 sockaddr
.sin_family
= PF_INET
;
172 sockaddr
.sin_port
= htons (port
);
173 memcpy (&sockaddr
.sin_addr
.s_addr
, hostent
->h_addr
,
174 sizeof (struct in_addr
));
177 if (setsockopt (sockser_listen_fd
, SOL_SOCKET
, SO_REUSEADDR
, (void*)& tmp
, sizeof (tmp
)) < 0)
179 sim_io_eprintf (sd
, "sockser init: unable to set SO_REUSEADDR: %s\n",
182 if (bind (sockser_listen_fd
, (struct sockaddr
*) &sockaddr
, sizeof (sockaddr
)) < 0)
184 sim_io_eprintf (sd
, "sockser init: unable to bind socket address: %s\n",
186 close (sockser_listen_fd
);
187 sockser_listen_fd
= -1;
190 if (listen (sockser_listen_fd
, 1) < 0)
192 sim_io_eprintf (sd
, "sockser init: unable to set up listener: %s\n",
194 close (sockser_listen_fd
);
195 sockser_listen_fd
= -1;
199 /* Handle writes to missing client -> SIGPIPE.
200 ??? Need a central signal management module. */
202 RETSIGTYPE (*orig
) ();
203 orig
= signal (SIGPIPE
, SIG_IGN
);
204 /* If a handler is already set up, don't mess with it. */
205 if (orig
!= SIG_DFL
&& orig
!= SIG_IGN
)
206 signal (SIGPIPE
, orig
);
213 dv_sockser_uninstall (SIM_DESC sd
)
215 if (sockser_listen_fd
!= -1)
217 close (sockser_listen_fd
);
218 sockser_listen_fd
= -1;
220 if (sockser_fd
!= -1)
227 /* Provide a prototype to silence -Wmissing-prototypes. */
228 extern MODULE_INIT_FN sim_install_dv_sockser
;
231 sim_install_dv_sockser (SIM_DESC sd
)
233 SIM_ASSERT (STATE_MAGIC (sd
) == SIM_MAGIC_NUMBER
);
234 if (sim_add_option_table (sd
, NULL
, sockser_options
) != SIM_RC_OK
)
236 sim_module_add_init_fn (sd
, dv_sockser_init
);
237 sim_module_add_uninstall_fn (sd
, dv_sockser_uninstall
);
242 connected_p (SIM_DESC sd
)
247 struct sockaddr sockaddr
;
250 if (sockser_listen_fd
== -1)
255 /* FIXME: has client gone away? */
259 /* Not connected. Connect with a client if there is one. */
262 FD_SET (sockser_listen_fd
, &readfds
);
264 /* ??? One can certainly argue this should be done differently,
265 but for now this is sufficient. */
267 tv
.tv_usec
= sockser_timeout
;
269 numfds
= select (sockser_listen_fd
+ 1, &readfds
, 0, 0, &tv
);
273 addrlen
= sizeof (sockaddr
);
274 sockser_fd
= accept (sockser_listen_fd
, &sockaddr
, &addrlen
);
275 if (sockser_fd
== -1)
278 /* Set non-blocking i/o. */
279 flags
= fcntl (sockser_fd
, F_GETFL
);
280 flags
|= O_NONBLOCK
| O_NDELAY
;
281 if (fcntl (sockser_fd
, F_SETFL
, flags
) == -1)
283 sim_io_eprintf (sd
, "unable to set nonblocking i/o");
292 dv_sockser_status (SIM_DESC sd
)
294 int numrfds
,numwfds
,status
;
296 fd_set readfds
,writefds
;
298 /* status to return if the socket isn't set up, or select fails */
299 status
= DV_SOCKSER_INPUT_EMPTY
| DV_SOCKSER_OUTPUT_EMPTY
|
300 DV_SOCKSER_DISCONNECTED
;
302 if (! connected_p (sd
))
307 FD_SET (sockser_fd
, &readfds
);
308 FD_SET (sockser_fd
, &writefds
);
310 /* ??? One can certainly argue this should be done differently,
311 but for now this is sufficient. The read is done separately
312 from the write to enforce the delay which we heuristically set to
313 once every SOCKSER_TIMEOUT_FREQ tries.
314 No, this isn't great for SMP situations, blah blah blah. */
318 #define SOCKSER_TIMEOUT_FREQ 42
319 if (++n
== SOCKSER_TIMEOUT_FREQ
)
324 tv
.tv_usec
= sockser_timeout
;
325 numrfds
= select (sockser_fd
+ 1, &readfds
, 0, 0, &tv
);
328 numwfds
= select (sockser_fd
+ 1, 0, &writefds
, 0, &tv
);
330 else /* do both selects at once */
334 numrfds
= numwfds
= select (sockser_fd
+ 1, &readfds
, &writefds
, 0, &tv
);
339 if (numrfds
<= 0 || ! FD_ISSET (sockser_fd
, &readfds
))
340 status
|= DV_SOCKSER_INPUT_EMPTY
;
341 if (numwfds
<= 0 || FD_ISSET (sockser_fd
, &writefds
))
342 status
|= DV_SOCKSER_OUTPUT_EMPTY
;
347 dv_sockser_write_buffer (SIM_DESC sd
, const unsigned char *buffer
,
352 if (! connected_p (sd
))
354 n
= write (sockser_fd
, buffer
, nr_bytes
);
370 dv_sockser_write (SIM_DESC sd
, unsigned char c
)
372 return dv_sockser_write_buffer (sd
, &c
, 1);
376 dv_sockser_read (SIM_DESC sd
)
381 if (! connected_p (sd
))
383 n
= read (sockser_fd
, &c
, 1);
384 /* ??? We're assuming semantics that may not be correct for all hosts.
385 In particular (from cvssrc/src/server.c), this assumes that we are using
386 BSD or POSIX nonblocking I/O. System V nonblocking I/O returns zero if
387 there is nothing to read. */