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. */
40 #include <sys/types.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
45 #include <sys/socket.h>
48 #include <netinet/tcp.h>
51 #include "sim-assert.h"
52 #include "sim-options.h"
54 #include "dv-sockser.h"
56 /* Get definitions for both O_NONBLOCK and O_NDELAY. */
60 #define O_NDELAY FNDELAY
61 #else /* ! defined (FNDELAY) */
63 #endif /* ! defined (FNDELAY) */
64 #endif /* ! defined (O_NDELAY) */
68 #define O_NONBLOCK FNBLOCK
69 #else /* ! defined (FNBLOCK) */
71 #endif /* ! defined (FNBLOCK) */
72 #endif /* ! defined (O_NONBLOCK) */
74 #define MIN(a,b) ((a) < (b) ? (a) : (b))
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 100 /* 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
},
103 { { NULL
, no_argument
, NULL
, 0 }, '\0', 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
= MIN (port_str
- sockser_addr
, (int) sizeof hostname
- 1);
149 strncpy (hostname
, sockser_addr
, tmp
);
150 hostname
[tmp
] = '\000';
151 port
= atoi (port_str
+ 1);
153 hostent
= gethostbyname (hostname
);
156 sim_io_eprintf (sd
, "sockser init: unknown host: %s\n",
161 sockser_listen_fd
= socket (PF_INET
, SOCK_STREAM
, 0);
162 if (sockser_listen_fd
< 0)
164 sim_io_eprintf (sd
, "sockser init: unable to get socket: %s\n",
169 sockaddr
.sin_family
= PF_INET
;
170 sockaddr
.sin_port
= htons(port
);
171 memcpy (&sockaddr
.sin_addr
.s_addr
, hostent
->h_addr
,
172 sizeof (struct in_addr
));
174 if (bind (sockser_listen_fd
, (struct sockaddr
*) &sockaddr
, sizeof (sockaddr
)) < 0)
176 sim_io_eprintf (sd
, "sockser init: unable to bind socket address: %s\n",
178 close (sockser_listen_fd
);
179 sockser_listen_fd
= -1;
182 if (listen (sockser_listen_fd
, 1) < 0)
184 sim_io_eprintf (sd
, "sockser init: unable to set up listener: %s\n",
186 close (sockser_listen_fd
);
187 sockser_listen_fd
= -1;
191 /* Handle writes to missing client -> SIGPIPE.
192 ??? Need a central signal management module. */
194 RETSIGTYPE (*orig
) ();
195 orig
= signal (SIGPIPE
, SIG_IGN
);
196 /* If a handler is already set up, don't mess with it. */
197 if (orig
!= SIG_DFL
&& orig
!= SIG_IGN
)
198 signal (SIGPIPE
, orig
);
205 dv_sockser_uninstall (SIM_DESC sd
)
207 if (sockser_listen_fd
!= -1)
209 close (sockser_listen_fd
);
210 sockser_listen_fd
= -1;
212 if (sockser_fd
!= -1)
220 dv_sockser_install (SIM_DESC sd
)
222 SIM_ASSERT (STATE_MAGIC (sd
) == SIM_MAGIC_NUMBER
);
223 if (sim_add_option_table (sd
, NULL
, sockser_options
) != SIM_RC_OK
)
225 sim_module_add_init_fn (sd
, dv_sockser_init
);
226 sim_module_add_uninstall_fn (sd
, dv_sockser_uninstall
);
231 connected_p (SIM_DESC sd
)
236 struct sockaddr sockaddr
;
239 if (sockser_listen_fd
== -1)
244 /* FIXME: has client gone away? */
248 /* Not connected. Connect with a client if there is one. */
251 FD_SET (sockser_listen_fd
, &readfds
);
253 /* ??? One can certainly argue this should be done differently,
254 but for now this is sufficient. */
256 tv
.tv_usec
= sockser_timeout
;
258 numfds
= select (sockser_listen_fd
+ 1, &readfds
, 0, 0, &tv
);
262 sockser_fd
= accept (sockser_listen_fd
, &sockaddr
, &addrlen
);
266 /* Set non-blocking i/o. */
267 flags
= fcntl (sockser_fd
, F_GETFL
);
268 flags
|= O_NONBLOCK
| O_NDELAY
;
269 if (fcntl (sockser_fd
, F_SETFL
, flags
) == -1)
271 sim_io_eprintf (sd
, "unable to set nonblocking i/o");
280 dv_sockser_status (SIM_DESC sd
)
282 int numrfds
,numwfds
,status
;
284 fd_set readfds
,writefds
;
286 /* status to return if the socket isn't set up, or select fails */
287 status
= DV_SOCKSER_INPUT_EMPTY
| DV_SOCKSER_OUTPUT_EMPTY
;
289 if (! connected_p (sd
))
294 FD_SET (sockser_fd
, &readfds
);
295 FD_SET (sockser_fd
, &writefds
);
297 /* ??? One can certainly argue this should be done differently,
298 but for now this is sufficient. The read is done separately
299 from the write to enforce the delay which we heuristically set to
300 once every SOCKSER_TIMEOUT_FREQ tries.
301 No, this isn't great for SMP situations, blah blah blah. */
305 #define SOCKSER_TIMEOUT_FREQ 42
306 if (++n
== SOCKSER_TIMEOUT_FREQ
)
311 tv
.tv_usec
= sockser_timeout
;
312 numrfds
= select (sockser_fd
+ 1, &readfds
, 0, 0, &tv
);
315 numwfds
= select (sockser_fd
+ 1, 0, &writefds
, 0, &tv
);
317 else /* do both selects at once */
321 numrfds
= numwfds
= select (sockser_fd
+ 1, &readfds
, &writefds
, 0, &tv
);
326 if (numrfds
<= 0 || ! FD_ISSET (sockser_fd
, &readfds
))
327 status
|= DV_SOCKSER_INPUT_EMPTY
;
328 if (numwfds
<= 0 || FD_ISSET (sockser_fd
, &writefds
))
329 status
|= DV_SOCKSER_OUTPUT_EMPTY
;
334 dv_sockser_write (SIM_DESC sd
, unsigned char c
)
338 if (! connected_p (sd
))
340 n
= write (sockser_fd
, &c
, 1);
356 dv_sockser_read (SIM_DESC sd
)
361 if (! connected_p (sd
))
363 n
= read (sockser_fd
, &c
, 1);
364 /* ??? We're assuming semantics that may not be correct for all hosts.
365 In particular (from cvssrc/src/server.c), this assumes that we are using
366 BSD or POSIX nonblocking I/O. System V nonblocking I/O returns zero if
367 there is nothing to read. */