1 /* Serial port emulation using sockets.
2 Copyright (C) 1998-2019 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. */
43 #include <sys/types.h>
45 #include <netinet/in.h>
46 #include <arpa/inet.h>
48 #include <sys/socket.h>
51 #include <netinet/tcp.h>
54 #include "sim-assert.h"
55 #include "sim-options.h"
57 #include "dv-sockser.h"
59 #ifndef HAVE_SOCKLEN_T
60 typedef int socklen_t
;
63 /* Get definitions for both O_NONBLOCK and O_NDELAY. */
67 #define O_NDELAY FNDELAY
68 #else /* ! defined (FNDELAY) */
70 #endif /* ! defined (FNDELAY) */
71 #endif /* ! defined (O_NDELAY) */
75 #define O_NONBLOCK FNBLOCK
76 #else /* ! defined (FNBLOCK) */
78 #endif /* ! defined (FNBLOCK) */
79 #endif /* ! defined (O_NONBLOCK) */
82 /* Compromise between eating cpu and properly busy-waiting.
83 One could have an option to set this but for now that seems
85 #define DEFAULT_TIMEOUT 1000 /* microseconds */
87 /* FIXME: These should allocated at run time and kept with other simulator
88 state (duh...). Later. */
89 const 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. */
92 static unsigned int sockser_timeout
= DEFAULT_TIMEOUT
;
93 static int sockser_listen_fd
= -1;
94 static int sockser_fd
= -1;
96 /* FIXME: use tree properties when they're ready. */
99 OPTION_ADDR
= OPTION_START
102 static DECLARE_OPTION_HANDLER (sockser_option_handler
);
104 static const OPTION sockser_options
[] =
106 { { "sockser-addr", required_argument
, NULL
, OPTION_ADDR
},
107 '\0', "SOCKET ADDRESS", "Set serial emulation socket address",
108 sockser_option_handler
, NULL
},
109 { { NULL
, no_argument
, NULL
, 0 }, '\0', NULL
, NULL
, NULL
, NULL
}
113 sockser_option_handler (SIM_DESC sd
, sim_cpu
*cpu
, int opt
,
114 char *arg
, int is_command
)
127 dv_sockser_init (SIM_DESC sd
)
129 struct hostent
*hostent
;
130 struct sockaddr_in sockaddr
;
132 const char *port_str
;
135 if (STATE_ENVIRONMENT (sd
) != OPERATING_ENVIRONMENT
136 || sockser_addr
== NULL
)
139 if (*sockser_addr
== '/')
141 /* support for these can come later */
142 sim_io_eprintf (sd
, "sockser init: unix domain sockets not supported: `%s'\n",
147 port_str
= strchr (sockser_addr
, ':');
150 sim_io_eprintf (sd
, "sockser init: missing port number: `%s'\n",
154 tmp
= port_str
- sockser_addr
;
155 if (tmp
>= sizeof hostname
)
156 tmp
= sizeof (hostname
) - 1;
157 strncpy (hostname
, sockser_addr
, tmp
);
158 hostname
[tmp
] = '\000';
159 port
= atoi (port_str
+ 1);
161 hostent
= gethostbyname (hostname
);
164 sim_io_eprintf (sd
, "sockser init: unknown host: %s\n",
169 sockser_listen_fd
= socket (PF_INET
, SOCK_STREAM
, 0);
170 if (sockser_listen_fd
== -1)
172 sim_io_eprintf (sd
, "sockser init: unable to get socket: %s\n",
177 sockaddr
.sin_family
= PF_INET
;
178 sockaddr
.sin_port
= htons (port
);
179 memcpy (&sockaddr
.sin_addr
.s_addr
, hostent
->h_addr
,
180 sizeof (struct in_addr
));
183 if (setsockopt (sockser_listen_fd
, SOL_SOCKET
, SO_REUSEADDR
, (void*)& tmp
, sizeof (tmp
)) < 0)
185 sim_io_eprintf (sd
, "sockser init: unable to set SO_REUSEADDR: %s\n",
188 if (bind (sockser_listen_fd
, (struct sockaddr
*) &sockaddr
, sizeof (sockaddr
)) < 0)
190 sim_io_eprintf (sd
, "sockser init: unable to bind socket address: %s\n",
192 close (sockser_listen_fd
);
193 sockser_listen_fd
= -1;
196 if (listen (sockser_listen_fd
, 1) < 0)
198 sim_io_eprintf (sd
, "sockser init: unable to set up listener: %s\n",
200 close (sockser_listen_fd
);
201 sockser_listen_fd
= -1;
205 /* Handle writes to missing client -> SIGPIPE.
206 ??? Need a central signal management module. */
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
);
219 dv_sockser_uninstall (SIM_DESC sd
)
221 if (sockser_listen_fd
!= -1)
223 close (sockser_listen_fd
);
224 sockser_listen_fd
= -1;
226 if (sockser_fd
!= -1)
234 dv_sockser_install (SIM_DESC sd
)
236 SIM_ASSERT (STATE_MAGIC (sd
) == SIM_MAGIC_NUMBER
);
237 if (sim_add_option_table (sd
, NULL
, sockser_options
) != SIM_RC_OK
)
239 sim_module_add_init_fn (sd
, dv_sockser_init
);
240 sim_module_add_uninstall_fn (sd
, dv_sockser_uninstall
);
245 connected_p (SIM_DESC sd
)
250 struct sockaddr sockaddr
;
253 if (sockser_listen_fd
== -1)
258 /* FIXME: has client gone away? */
262 /* Not connected. Connect with a client if there is one. */
265 FD_SET (sockser_listen_fd
, &readfds
);
267 /* ??? One can certainly argue this should be done differently,
268 but for now this is sufficient. */
270 tv
.tv_usec
= sockser_timeout
;
272 numfds
= select (sockser_listen_fd
+ 1, &readfds
, 0, 0, &tv
);
276 addrlen
= sizeof (sockaddr
);
277 sockser_fd
= accept (sockser_listen_fd
, &sockaddr
, &addrlen
);
278 if (sockser_fd
== -1)
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)
286 sim_io_eprintf (sd
, "unable to set nonblocking i/o");
295 dv_sockser_status (SIM_DESC sd
)
297 int numrfds
,numwfds
,status
;
299 fd_set readfds
,writefds
;
301 /* status to return if the socket isn't set up, or select fails */
302 status
= DV_SOCKSER_INPUT_EMPTY
| DV_SOCKSER_OUTPUT_EMPTY
|
303 DV_SOCKSER_DISCONNECTED
;
305 if (! connected_p (sd
))
310 FD_SET (sockser_fd
, &readfds
);
311 FD_SET (sockser_fd
, &writefds
);
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. */
321 #define SOCKSER_TIMEOUT_FREQ 42
322 if (++n
== SOCKSER_TIMEOUT_FREQ
)
327 tv
.tv_usec
= sockser_timeout
;
328 numrfds
= select (sockser_fd
+ 1, &readfds
, 0, 0, &tv
);
331 numwfds
= select (sockser_fd
+ 1, 0, &writefds
, 0, &tv
);
333 else /* do both selects at once */
337 numrfds
= numwfds
= select (sockser_fd
+ 1, &readfds
, &writefds
, 0, &tv
);
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
;
350 dv_sockser_write_buffer (SIM_DESC sd
, const unsigned char *buffer
,
355 if (! connected_p (sd
))
357 n
= write (sockser_fd
, buffer
, nr_bytes
);
373 dv_sockser_write (SIM_DESC sd
, unsigned char c
)
375 return dv_sockser_write_buffer (sd
, &c
, 1);
379 dv_sockser_read (SIM_DESC sd
)
384 if (! connected_p (sd
))
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. */