* sun build fix for thinko (?)
[deliverable/binutils-gdb.git] / sim / common / dv-sockser.c
1 /* Serial port emulation using sockets.
2 Copyright (C) 1998 Free Software Foundation, Inc.
3 Contributed by Cygnus Solutions.
4
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)
8 any later version.
9
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.
14
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. */
18
19 /* FIXME: will obviously need to evolve.
20 - connectionless sockets might be more appropriate. */
21
22 #include "sim-main.h"
23
24 #ifdef HAVE_STRING_H
25 #include <string.h>
26 #else
27 #ifdef HAVE_STRINGS_H
28 #include <strings.h>
29 #endif
30 #endif
31 #include <signal.h>
32 #ifdef HAVE_STDLIB_H
33 #include <stdlib.h>
34 #endif
35 #ifdef HAVE_FCNTL_H
36 #include <fcntl.h>
37 #endif
38
39 #include <errno.h>
40 #include <sys/types.h>
41 #include <sys/time.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
44 #include <netdb.h>
45 #include <sys/socket.h>
46
47 #ifndef __CYGWIN32__
48 #include <netinet/tcp.h>
49 #endif
50
51 #include "sim-assert.h"
52 #include "sim-options.h"
53
54 #include "dv-sockser.h"
55 \f
56 /* Get definitions for both O_NONBLOCK and O_NDELAY. */
57
58 #ifndef O_NDELAY
59 #ifdef FNDELAY
60 #define O_NDELAY FNDELAY
61 #else /* ! defined (FNDELAY) */
62 #define O_NDELAY 0
63 #endif /* ! defined (FNDELAY) */
64 #endif /* ! defined (O_NDELAY) */
65
66 #ifndef O_NONBLOCK
67 #ifdef FNBLOCK
68 #define O_NONBLOCK FNBLOCK
69 #else /* ! defined (FNBLOCK) */
70 #define O_NONBLOCK 0
71 #endif /* ! defined (FNBLOCK) */
72 #endif /* ! defined (O_NONBLOCK) */
73 \f
74 #define MIN(a,b) ((a) < (b) ? (a) : (b))
75
76 /* Compromise between eating cpu and properly busy-waiting.
77 One could have an option to set this but for now that seems
78 like featuritis. */
79 #define DEFAULT_TIMEOUT 100 /* microseconds */
80
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;
89 \f
90 /* FIXME: use tree properties when they're ready. */
91
92 typedef enum {
93 OPTION_ADDR = OPTION_START
94 } SOCKSER_OPTIONS;
95
96 static DECLARE_OPTION_HANDLER (sockser_option_handler);
97
98 static const OPTION sockser_options[] =
99 {
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 }
104 };
105
106 static SIM_RC
107 sockser_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt,
108 char *arg, int is_command)
109 {
110 switch (opt)
111 {
112 case OPTION_ADDR :
113 sockser_addr = arg;
114 break;
115 }
116
117 return SIM_RC_OK;
118 }
119
120 static SIM_RC
121 dv_sockser_init (SIM_DESC sd)
122 {
123 struct hostent *hostent;
124 struct sockaddr_in sockaddr;
125 char hostname[100];
126 const char *port_str;
127 int tmp,port;
128
129 if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT
130 || sockser_addr == NULL)
131 return SIM_RC_OK;
132
133 if (*sockser_addr == '/')
134 {
135 /* support for these can come later */
136 sim_io_eprintf (sd, "sockser init: unix domain sockets not supported: `%s'\n",
137 sockser_addr);
138 return SIM_RC_FAIL;
139 }
140
141 port_str = strchr (sockser_addr, ':');
142 if (!port_str)
143 {
144 sim_io_eprintf (sd, "sockser init: missing port number: `%s'\n",
145 sockser_addr);
146 return SIM_RC_FAIL;
147 }
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);
152
153 hostent = gethostbyname (hostname);
154 if (! hostent)
155 {
156 sim_io_eprintf (sd, "sockser init: unknown host: %s\n",
157 hostname);
158 return SIM_RC_FAIL;
159 }
160
161 sockser_listen_fd = socket (PF_INET, SOCK_STREAM, 0);
162 if (sockser_listen_fd < 0)
163 {
164 sim_io_eprintf (sd, "sockser init: unable to get socket: %s\n",
165 strerror (errno));
166 return SIM_RC_FAIL;
167 }
168
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));
173
174 if (bind (sockser_listen_fd, (struct sockaddr *) &sockaddr, sizeof (sockaddr)) < 0)
175 {
176 sim_io_eprintf (sd, "sockser init: unable to bind socket address: %s\n",
177 strerror (errno));
178 close (sockser_listen_fd);
179 sockser_listen_fd = -1;
180 return SIM_RC_FAIL;
181 }
182 if (listen (sockser_listen_fd, 1) < 0)
183 {
184 sim_io_eprintf (sd, "sockser init: unable to set up listener: %s\n",
185 strerror (errno));
186 close (sockser_listen_fd);
187 sockser_listen_fd = -1;
188 return SIM_RC_OK;
189 }
190
191 /* Handle writes to missing client -> SIGPIPE.
192 ??? Need a central signal management module. */
193 {
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);
199 }
200
201 return SIM_RC_OK;
202 }
203
204 static void
205 dv_sockser_uninstall (SIM_DESC sd)
206 {
207 if (sockser_listen_fd != -1)
208 {
209 close (sockser_listen_fd);
210 sockser_listen_fd = -1;
211 }
212 if (sockser_fd != -1)
213 {
214 close (sockser_fd);
215 sockser_fd = -1;
216 }
217 }
218
219 SIM_RC
220 dv_sockser_install (SIM_DESC sd)
221 {
222 SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
223 if (sim_add_option_table (sd, NULL, sockser_options) != SIM_RC_OK)
224 return SIM_RC_FAIL;
225 sim_module_add_init_fn (sd, dv_sockser_init);
226 sim_module_add_uninstall_fn (sd, dv_sockser_uninstall);
227 return SIM_RC_OK;
228 }
229
230 static int
231 connected_p (SIM_DESC sd)
232 {
233 int numfds,flags;
234 struct timeval tv;
235 fd_set readfds;
236 struct sockaddr sockaddr;
237 int addrlen;
238
239 if (sockser_listen_fd == -1)
240 return 0;
241
242 if (sockser_fd >= 0)
243 {
244 /* FIXME: has client gone away? */
245 return 1;
246 }
247
248 /* Not connected. Connect with a client if there is one. */
249
250 FD_ZERO (&readfds);
251 FD_SET (sockser_listen_fd, &readfds);
252
253 /* ??? One can certainly argue this should be done differently,
254 but for now this is sufficient. */
255 tv.tv_sec = 0;
256 tv.tv_usec = sockser_timeout;
257
258 numfds = select (sockser_listen_fd + 1, &readfds, 0, 0, &tv);
259 if (numfds <= 0)
260 return 0;
261
262 sockser_fd = accept (sockser_listen_fd, &sockaddr, &addrlen);
263 if (sockser_fd < 0)
264 return 0;
265
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)
270 {
271 sim_io_eprintf (sd, "unable to set nonblocking i/o");
272 close (sockser_fd);
273 sockser_fd = -1;
274 return 0;
275 }
276 return 1;
277 }
278
279 int
280 dv_sockser_status (SIM_DESC sd)
281 {
282 int numrfds,numwfds,status;
283 struct timeval tv;
284 fd_set readfds,writefds;
285
286 /* status to return if the socket isn't set up, or select fails */
287 status = DV_SOCKSER_INPUT_EMPTY | DV_SOCKSER_OUTPUT_EMPTY;
288
289 if (! connected_p (sd))
290 return status;
291
292 FD_ZERO (&readfds);
293 FD_ZERO (&writefds);
294 FD_SET (sockser_fd, &readfds);
295 FD_SET (sockser_fd, &writefds);
296
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. */
302
303 {
304 static int n;
305 #define SOCKSER_TIMEOUT_FREQ 42
306 if (++n == SOCKSER_TIMEOUT_FREQ)
307 n = 0;
308 if (n == 0)
309 {
310 tv.tv_sec = 0;
311 tv.tv_usec = sockser_timeout;
312 numrfds = select (sockser_fd + 1, &readfds, 0, 0, &tv);
313 tv.tv_sec = 0;
314 tv.tv_usec = 0;
315 numwfds = select (sockser_fd + 1, 0, &writefds, 0, &tv);
316 }
317 else /* do both selects at once */
318 {
319 tv.tv_sec = 0;
320 tv.tv_usec = 0;
321 numrfds = numwfds = select (sockser_fd + 1, &readfds, &writefds, 0, &tv);
322 }
323 }
324
325 status = 0;
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;
330 return status;
331 }
332
333 int
334 dv_sockser_write (SIM_DESC sd, unsigned char c)
335 {
336 int n;
337
338 if (! connected_p (sd))
339 return -1;
340 n = write (sockser_fd, &c, 1);
341 if (n == -1)
342 {
343 if (errno == EPIPE)
344 {
345 close (sockser_fd);
346 sockser_fd = -1;
347 }
348 return -1;
349 }
350 if (n != 1)
351 return -1;
352 return 1;
353 }
354
355 int
356 dv_sockser_read (SIM_DESC sd)
357 {
358 unsigned char c;
359 int n;
360
361 if (! connected_p (sd))
362 return -1;
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. */
368 if (n == 0)
369 {
370 close (sockser_fd);
371 sockser_fd = -1;
372 return -1;
373 }
374 if (n != 1)
375 return -1;
376 return c;
377 }
This page took 0.03959 seconds and 4 git commands to generate.