1 /* Serial port emulation using sockets.
2 Copyright (C) 1998 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 2, or (at your option)
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 along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
19 /* FIXME: will obviously need to evolve.
20 - 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 /* Get definitions for both O_NONBLOCK and O_NDELAY. */
63 #define O_NDELAY FNDELAY
64 #else /* ! defined (FNDELAY) */
66 #endif /* ! defined (FNDELAY) */
67 #endif /* ! defined (O_NDELAY) */
71 #define O_NONBLOCK FNBLOCK
72 #else /* ! defined (FNBLOCK) */
74 #endif /* ! defined (FNBLOCK) */
75 #endif /* ! defined (O_NONBLOCK) */
78 /* Compromise between eating cpu and properly busy-waiting.
79 One could have an option to set this but for now that seems
81 #define DEFAULT_TIMEOUT 1000 /* microseconds */
83 /* FIXME: These should allocated at run time and kept with other simulator
84 state (duh...). Later. */
85 const char * sockser_addr = NULL;
86 /* Timeout in microseconds during status flag computation.
87 Setting this to zero achieves proper busy wait semantics but eats cpu. */
88 static unsigned int sockser_timeout = DEFAULT_TIMEOUT;
89 static int sockser_listen_fd = -1;
90 static int sockser_fd = -1;
92 /* FIXME: use tree properties when they're ready. */
95 OPTION_ADDR = OPTION_START
98 static DECLARE_OPTION_HANDLER (sockser_option_handler);
100 static const OPTION sockser_options[] =
102 { { "sockser-addr", required_argument, NULL, OPTION_ADDR },
103 '\0', "SOCKET ADDRESS", "Set serial emulation socket address",
104 sockser_option_handler },
105 { { NULL, no_argument, NULL, 0 }, '\0', NULL, NULL, NULL }
109 sockser_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt,
110 char *arg, int is_command)
123 dv_sockser_init (SIM_DESC sd)
125 struct hostent *hostent;
126 struct sockaddr_in sockaddr;
128 const char *port_str;
131 if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT
132 || sockser_addr == NULL)
135 if (*sockser_addr == '/')
137 /* support for these can come later */
138 sim_io_eprintf (sd, "sockser init: unix domain sockets not supported: `%s'\n",
143 port_str = strchr (sockser_addr, ':');
146 sim_io_eprintf (sd, "sockser init: missing port number: `%s'\n",
150 tmp = port_str - sockser_addr;
151 if (tmp >= sizeof hostname)
152 tmp = sizeof (hostname) - 1;
153 strncpy (hostname, sockser_addr, tmp);
154 hostname[tmp] = '\000';
155 port = atoi (port_str + 1);
157 hostent = gethostbyname (hostname);
160 sim_io_eprintf (sd, "sockser init: unknown host: %s\n",
165 sockser_listen_fd = socket (PF_INET, SOCK_STREAM, 0);
166 if (sockser_listen_fd < 0)
168 sim_io_eprintf (sd, "sockser init: unable to get socket: %s\n",
173 sockaddr.sin_family = PF_INET;
174 sockaddr.sin_port = htons(port);
175 memcpy (&sockaddr.sin_addr.s_addr, hostent->h_addr,
176 sizeof (struct in_addr));
179 if (setsockopt (sockser_listen_fd, SOL_SOCKET, SO_REUSEADDR, (void*)& tmp, sizeof(tmp)) < 0)
181 sim_io_eprintf (sd, "sockser init: unable to set SO_REUSEADDR: %s\n",
184 if (bind (sockser_listen_fd, (struct sockaddr *) &sockaddr, sizeof (sockaddr)) < 0)
186 sim_io_eprintf (sd, "sockser init: unable to bind socket address: %s\n",
188 close (sockser_listen_fd);
189 sockser_listen_fd = -1;
192 if (listen (sockser_listen_fd, 1) < 0)
194 sim_io_eprintf (sd, "sockser init: unable to set up listener: %s\n",
196 close (sockser_listen_fd);
197 sockser_listen_fd = -1;
201 /* Handle writes to missing client -> SIGPIPE.
202 ??? Need a central signal management module. */
204 RETSIGTYPE (*orig) ();
205 orig = signal (SIGPIPE, SIG_IGN);
206 /* If a handler is already set up, don't mess with it. */
207 if (orig != SIG_DFL && orig != SIG_IGN)
208 signal (SIGPIPE, orig);
215 dv_sockser_uninstall (SIM_DESC sd)
217 if (sockser_listen_fd != -1)
219 close (sockser_listen_fd);
220 sockser_listen_fd = -1;
222 if (sockser_fd != -1)
230 dv_sockser_install (SIM_DESC sd)
232 SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
233 if (sim_add_option_table (sd, NULL, sockser_options) != SIM_RC_OK)
235 sim_module_add_init_fn (sd, dv_sockser_init);
236 sim_module_add_uninstall_fn (sd, dv_sockser_uninstall);
241 connected_p (SIM_DESC sd)
246 struct sockaddr sockaddr;
249 if (sockser_listen_fd == -1)
254 /* FIXME: has client gone away? */
258 /* Not connected. Connect with a client if there is one. */
261 FD_SET (sockser_listen_fd, &readfds);
263 /* ??? One can certainly argue this should be done differently,
264 but for now this is sufficient. */
266 tv.tv_usec = sockser_timeout;
268 numfds = select (sockser_listen_fd + 1, &readfds, 0, 0, &tv);
272 addrlen = sizeof (sockaddr);
273 sockser_fd = accept (sockser_listen_fd, &sockaddr, &addrlen);
277 /* Set non-blocking i/o. */
278 flags = fcntl (sockser_fd, F_GETFL);
279 flags |= O_NONBLOCK | O_NDELAY;
280 if (fcntl (sockser_fd, F_SETFL, flags) == -1)
282 sim_io_eprintf (sd, "unable to set nonblocking i/o");
291 dv_sockser_status (SIM_DESC sd)
293 int numrfds,numwfds,status;
295 fd_set readfds,writefds;
297 /* status to return if the socket isn't set up, or select fails */
298 status = DV_SOCKSER_INPUT_EMPTY | DV_SOCKSER_OUTPUT_EMPTY;
300 if (! connected_p (sd))
305 FD_SET (sockser_fd, &readfds);
306 FD_SET (sockser_fd, &writefds);
308 /* ??? One can certainly argue this should be done differently,
309 but for now this is sufficient. The read is done separately
310 from the write to enforce the delay which we heuristically set to
311 once every SOCKSER_TIMEOUT_FREQ tries.
312 No, this isn't great for SMP situations, blah blah blah. */
316 #define SOCKSER_TIMEOUT_FREQ 42
317 if (++n == SOCKSER_TIMEOUT_FREQ)
322 tv.tv_usec = sockser_timeout;
323 numrfds = select (sockser_fd + 1, &readfds, 0, 0, &tv);
326 numwfds = select (sockser_fd + 1, 0, &writefds, 0, &tv);
328 else /* do both selects at once */
332 numrfds = numwfds = select (sockser_fd + 1, &readfds, &writefds, 0, &tv);
337 if (numrfds <= 0 || ! FD_ISSET (sockser_fd, &readfds))
338 status |= DV_SOCKSER_INPUT_EMPTY;
339 if (numwfds <= 0 || FD_ISSET (sockser_fd, &writefds))
340 status |= DV_SOCKSER_OUTPUT_EMPTY;
345 dv_sockser_write (SIM_DESC sd, unsigned char c)
349 if (! connected_p (sd))
351 n = write (sockser_fd, &c, 1);
367 dv_sockser_read (SIM_DESC sd)
372 if (! connected_p (sd))
374 n = read (sockser_fd, &c, 1);
375 /* ??? We're assuming semantics that may not be correct for all hosts.
376 In particular (from cvssrc/src/server.c), this assumes that we are using
377 BSD or POSIX nonblocking I/O. System V nonblocking I/O returns zero if
378 there is nothing to read. */