Update copyright notices to add year 2010.
[deliverable/binutils-gdb.git] / sim / common / dv-sockser.c
CommitLineData
c906108c 1/* Serial port emulation using sockets.
dc3cf14f 2 Copyright (C) 1998, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
c906108c
SS
3 Contributed by Cygnus Solutions.
4
5This program is free software; you can redistribute it and/or modify
6it under the terms of the GNU General Public License as published by
4744ac1b
JB
7the Free Software Foundation; either version 3 of the License, or
8(at your option) any later version.
c906108c
SS
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
4744ac1b
JB
15You should have received a copy of the GNU General Public License
16along with this program. If not, see <http://www.gnu.org/licenses/>. */
c906108c
SS
17
18/* FIXME: will obviously need to evolve.
19 - connectionless sockets might be more appropriate. */
20
21#include "sim-main.h"
22
23#ifdef HAVE_STRING_H
24#include <string.h>
25#else
26#ifdef HAVE_STRINGS_H
27#include <strings.h>
28#endif
29#endif
30#include <signal.h>
31#ifdef HAVE_STDLIB_H
32#include <stdlib.h>
33#endif
34#ifdef HAVE_FCNTL_H
35#include <fcntl.h>
36#endif
37#ifdef HAVE_UNISTD_H
38#include <unistd.h>
39#endif
40
41#include <errno.h>
42#include <sys/types.h>
43#include <sys/time.h>
44#include <netinet/in.h>
45#include <arpa/inet.h>
46#include <netdb.h>
47#include <sys/socket.h>
48
49#ifndef __CYGWIN32__
50#include <netinet/tcp.h>
51#endif
52
53#include "sim-assert.h"
54#include "sim-options.h"
55
56#include "dv-sockser.h"
57\f
58/* Get definitions for both O_NONBLOCK and O_NDELAY. */
59
60#ifndef O_NDELAY
61#ifdef FNDELAY
62#define O_NDELAY FNDELAY
63#else /* ! defined (FNDELAY) */
64#define O_NDELAY 0
65#endif /* ! defined (FNDELAY) */
66#endif /* ! defined (O_NDELAY) */
67
68#ifndef O_NONBLOCK
69#ifdef FNBLOCK
70#define O_NONBLOCK FNBLOCK
71#else /* ! defined (FNBLOCK) */
72#define O_NONBLOCK 0
73#endif /* ! defined (FNBLOCK) */
74#endif /* ! defined (O_NONBLOCK) */
75\f
c906108c
SS
76
77/* Compromise between eating cpu and properly busy-waiting.
78 One could have an option to set this but for now that seems
79 like featuritis. */
80#define DEFAULT_TIMEOUT 1000 /* microseconds */
81
82/* FIXME: These should allocated at run time and kept with other simulator
83 state (duh...). Later. */
84const char * sockser_addr = NULL;
85/* Timeout in microseconds during status flag computation.
86 Setting this to zero achieves proper busy wait semantics but eats cpu. */
87static unsigned int sockser_timeout = DEFAULT_TIMEOUT;
88static int sockser_listen_fd = -1;
89static int sockser_fd = -1;
90\f
91/* FIXME: use tree properties when they're ready. */
92
93typedef enum {
94 OPTION_ADDR = OPTION_START
95} SOCKSER_OPTIONS;
96
97static DECLARE_OPTION_HANDLER (sockser_option_handler);
98
99static const OPTION sockser_options[] =
100{
101 { { "sockser-addr", required_argument, NULL, OPTION_ADDR },
102 '\0', "SOCKET ADDRESS", "Set serial emulation socket address",
103 sockser_option_handler },
104 { { NULL, no_argument, NULL, 0 }, '\0', NULL, NULL, NULL }
105};
106
107static SIM_RC
108sockser_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt,
109 char *arg, int is_command)
110{
111 switch (opt)
112 {
113 case OPTION_ADDR :
114 sockser_addr = arg;
115 break;
116 }
117
118 return SIM_RC_OK;
119}
120
121static SIM_RC
122dv_sockser_init (SIM_DESC sd)
123{
124 struct hostent *hostent;
125 struct sockaddr_in sockaddr;
126 char hostname[100];
127 const char *port_str;
128 int tmp,port;
129
130 if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT
131 || sockser_addr == NULL)
132 return SIM_RC_OK;
133
134 if (*sockser_addr == '/')
135 {
136 /* support for these can come later */
137 sim_io_eprintf (sd, "sockser init: unix domain sockets not supported: `%s'\n",
138 sockser_addr);
139 return SIM_RC_FAIL;
140 }
141
142 port_str = strchr (sockser_addr, ':');
143 if (!port_str)
144 {
145 sim_io_eprintf (sd, "sockser init: missing port number: `%s'\n",
146 sockser_addr);
147 return SIM_RC_FAIL;
148 }
548a3e15
AC
149 tmp = port_str - sockser_addr;
150 if (tmp >= sizeof hostname)
151 tmp = sizeof (hostname) - 1;
c906108c
SS
152 strncpy (hostname, sockser_addr, tmp);
153 hostname[tmp] = '\000';
154 port = atoi (port_str + 1);
155
156 hostent = gethostbyname (hostname);
157 if (! hostent)
158 {
159 sim_io_eprintf (sd, "sockser init: unknown host: %s\n",
160 hostname);
161 return SIM_RC_FAIL;
162 }
163
164 sockser_listen_fd = socket (PF_INET, SOCK_STREAM, 0);
165 if (sockser_listen_fd < 0)
166 {
167 sim_io_eprintf (sd, "sockser init: unable to get socket: %s\n",
168 strerror (errno));
169 return SIM_RC_FAIL;
170 }
171
172 sockaddr.sin_family = PF_INET;
173 sockaddr.sin_port = htons(port);
174 memcpy (&sockaddr.sin_addr.s_addr, hostent->h_addr,
175 sizeof (struct in_addr));
176
177 tmp = 1;
178 if (setsockopt (sockser_listen_fd, SOL_SOCKET, SO_REUSEADDR, (void*)& tmp, sizeof(tmp)) < 0)
179 {
180 sim_io_eprintf (sd, "sockser init: unable to set SO_REUSEADDR: %s\n",
181 strerror (errno));
182 }
183 if (bind (sockser_listen_fd, (struct sockaddr *) &sockaddr, sizeof (sockaddr)) < 0)
184 {
185 sim_io_eprintf (sd, "sockser init: unable to bind socket address: %s\n",
186 strerror (errno));
187 close (sockser_listen_fd);
188 sockser_listen_fd = -1;
189 return SIM_RC_FAIL;
190 }
191 if (listen (sockser_listen_fd, 1) < 0)
192 {
193 sim_io_eprintf (sd, "sockser init: unable to set up listener: %s\n",
194 strerror (errno));
195 close (sockser_listen_fd);
196 sockser_listen_fd = -1;
197 return SIM_RC_OK;
198 }
199
200 /* Handle writes to missing client -> SIGPIPE.
201 ??? Need a central signal management module. */
202 {
203 RETSIGTYPE (*orig) ();
204 orig = signal (SIGPIPE, SIG_IGN);
205 /* If a handler is already set up, don't mess with it. */
206 if (orig != SIG_DFL && orig != SIG_IGN)
207 signal (SIGPIPE, orig);
208 }
209
210 return SIM_RC_OK;
211}
212
213static void
214dv_sockser_uninstall (SIM_DESC sd)
215{
216 if (sockser_listen_fd != -1)
217 {
218 close (sockser_listen_fd);
219 sockser_listen_fd = -1;
220 }
221 if (sockser_fd != -1)
222 {
223 close (sockser_fd);
224 sockser_fd = -1;
225 }
226}
227
228SIM_RC
229dv_sockser_install (SIM_DESC sd)
230{
231 SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
232 if (sim_add_option_table (sd, NULL, sockser_options) != SIM_RC_OK)
233 return SIM_RC_FAIL;
234 sim_module_add_init_fn (sd, dv_sockser_init);
235 sim_module_add_uninstall_fn (sd, dv_sockser_uninstall);
236 return SIM_RC_OK;
237}
238
239static int
240connected_p (SIM_DESC sd)
241{
242 int numfds,flags;
243 struct timeval tv;
244 fd_set readfds;
245 struct sockaddr sockaddr;
246 int addrlen;
247
248 if (sockser_listen_fd == -1)
249 return 0;
250
251 if (sockser_fd >= 0)
252 {
253 /* FIXME: has client gone away? */
254 return 1;
255 }
256
257 /* Not connected. Connect with a client if there is one. */
258
259 FD_ZERO (&readfds);
260 FD_SET (sockser_listen_fd, &readfds);
261
262 /* ??? One can certainly argue this should be done differently,
263 but for now this is sufficient. */
264 tv.tv_sec = 0;
265 tv.tv_usec = sockser_timeout;
266
267 numfds = select (sockser_listen_fd + 1, &readfds, 0, 0, &tv);
268 if (numfds <= 0)
269 return 0;
270
9846de1b 271 addrlen = sizeof (sockaddr);
c906108c
SS
272 sockser_fd = accept (sockser_listen_fd, &sockaddr, &addrlen);
273 if (sockser_fd < 0)
274 return 0;
275
276 /* Set non-blocking i/o. */
277 flags = fcntl (sockser_fd, F_GETFL);
278 flags |= O_NONBLOCK | O_NDELAY;
279 if (fcntl (sockser_fd, F_SETFL, flags) == -1)
280 {
281 sim_io_eprintf (sd, "unable to set nonblocking i/o");
282 close (sockser_fd);
283 sockser_fd = -1;
284 return 0;
285 }
286 return 1;
287}
288
289int
290dv_sockser_status (SIM_DESC sd)
291{
292 int numrfds,numwfds,status;
293 struct timeval tv;
294 fd_set readfds,writefds;
295
296 /* status to return if the socket isn't set up, or select fails */
297 status = DV_SOCKSER_INPUT_EMPTY | DV_SOCKSER_OUTPUT_EMPTY;
298
299 if (! connected_p (sd))
300 return status;
301
302 FD_ZERO (&readfds);
303 FD_ZERO (&writefds);
304 FD_SET (sockser_fd, &readfds);
305 FD_SET (sockser_fd, &writefds);
306
307 /* ??? One can certainly argue this should be done differently,
308 but for now this is sufficient. The read is done separately
309 from the write to enforce the delay which we heuristically set to
310 once every SOCKSER_TIMEOUT_FREQ tries.
311 No, this isn't great for SMP situations, blah blah blah. */
312
313 {
314 static int n;
315#define SOCKSER_TIMEOUT_FREQ 42
316 if (++n == SOCKSER_TIMEOUT_FREQ)
317 n = 0;
318 if (n == 0)
319 {
320 tv.tv_sec = 0;
321 tv.tv_usec = sockser_timeout;
322 numrfds = select (sockser_fd + 1, &readfds, 0, 0, &tv);
323 tv.tv_sec = 0;
324 tv.tv_usec = 0;
325 numwfds = select (sockser_fd + 1, 0, &writefds, 0, &tv);
326 }
327 else /* do both selects at once */
328 {
329 tv.tv_sec = 0;
330 tv.tv_usec = 0;
331 numrfds = numwfds = select (sockser_fd + 1, &readfds, &writefds, 0, &tv);
332 }
333 }
334
335 status = 0;
336 if (numrfds <= 0 || ! FD_ISSET (sockser_fd, &readfds))
337 status |= DV_SOCKSER_INPUT_EMPTY;
338 if (numwfds <= 0 || FD_ISSET (sockser_fd, &writefds))
339 status |= DV_SOCKSER_OUTPUT_EMPTY;
340 return status;
341}
342
343int
344dv_sockser_write (SIM_DESC sd, unsigned char c)
345{
346 int n;
347
348 if (! connected_p (sd))
349 return -1;
350 n = write (sockser_fd, &c, 1);
351 if (n == -1)
352 {
353 if (errno == EPIPE)
354 {
355 close (sockser_fd);
356 sockser_fd = -1;
357 }
358 return -1;
359 }
360 if (n != 1)
361 return -1;
362 return 1;
363}
364
365int
366dv_sockser_read (SIM_DESC sd)
367{
368 unsigned char c;
369 int n;
370
371 if (! connected_p (sd))
372 return -1;
373 n = read (sockser_fd, &c, 1);
374 /* ??? We're assuming semantics that may not be correct for all hosts.
375 In particular (from cvssrc/src/server.c), this assumes that we are using
376 BSD or POSIX nonblocking I/O. System V nonblocking I/O returns zero if
377 there is nothing to read. */
378 if (n == 0)
379 {
380 close (sockser_fd);
381 sockser_fd = -1;
382 return -1;
383 }
384 if (n != 1)
385 return -1;
386 return c;
387}
This page took 0.593559 seconds and 4 git commands to generate.