]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/common/dv-sockser.c
Initial creation of sourceware repository
[thirdparty/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 #ifdef HAVE_UNISTD_H
39 #include <unistd.h>
40 #endif
41
42 #include <errno.h>
43 #include <sys/types.h>
44 #include <sys/time.h>
45 #include <netinet/in.h>
46 #include <arpa/inet.h>
47 #include <netdb.h>
48 #include <sys/socket.h>
49
50 #ifndef __CYGWIN32__
51 #include <netinet/tcp.h>
52 #endif
53
54 #include "sim-assert.h"
55 #include "sim-options.h"
56
57 #include "dv-sockser.h"
58 \f
59 /* Get definitions for both O_NONBLOCK and O_NDELAY. */
60
61 #ifndef O_NDELAY
62 #ifdef FNDELAY
63 #define O_NDELAY FNDELAY
64 #else /* ! defined (FNDELAY) */
65 #define O_NDELAY 0
66 #endif /* ! defined (FNDELAY) */
67 #endif /* ! defined (O_NDELAY) */
68
69 #ifndef O_NONBLOCK
70 #ifdef FNBLOCK
71 #define O_NONBLOCK FNBLOCK
72 #else /* ! defined (FNBLOCK) */
73 #define O_NONBLOCK 0
74 #endif /* ! defined (FNBLOCK) */
75 #endif /* ! defined (O_NONBLOCK) */
76 \f
77 #define MIN(a,b) ((a) < (b) ? (a) : (b))
78
79 /* Compromise between eating cpu and properly busy-waiting.
80 One could have an option to set this but for now that seems
81 like featuritis. */
82 #define DEFAULT_TIMEOUT 1000 /* microseconds */
83
84 /* FIXME: These should allocated at run time and kept with other simulator
85 state (duh...). Later. */
86 const char * sockser_addr = NULL;
87 /* Timeout in microseconds during status flag computation.
88 Setting this to zero achieves proper busy wait semantics but eats cpu. */
89 static unsigned int sockser_timeout = DEFAULT_TIMEOUT;
90 static int sockser_listen_fd = -1;
91 static int sockser_fd = -1;
92 \f
93 /* FIXME: use tree properties when they're ready. */
94
95 typedef enum {
96 OPTION_ADDR = OPTION_START
97 } SOCKSER_OPTIONS;
98
99 static DECLARE_OPTION_HANDLER (sockser_option_handler);
100
101 static const OPTION sockser_options[] =
102 {
103 { { "sockser-addr", required_argument, NULL, OPTION_ADDR },
104 '\0', "SOCKET ADDRESS", "Set serial emulation socket address",
105 sockser_option_handler },
106 { { NULL, no_argument, NULL, 0 }, '\0', NULL, NULL, NULL }
107 };
108
109 static SIM_RC
110 sockser_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt,
111 char *arg, int is_command)
112 {
113 switch (opt)
114 {
115 case OPTION_ADDR :
116 sockser_addr = arg;
117 break;
118 }
119
120 return SIM_RC_OK;
121 }
122
123 static SIM_RC
124 dv_sockser_init (SIM_DESC sd)
125 {
126 struct hostent *hostent;
127 struct sockaddr_in sockaddr;
128 char hostname[100];
129 const char *port_str;
130 int tmp,port;
131
132 if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT
133 || sockser_addr == NULL)
134 return SIM_RC_OK;
135
136 if (*sockser_addr == '/')
137 {
138 /* support for these can come later */
139 sim_io_eprintf (sd, "sockser init: unix domain sockets not supported: `%s'\n",
140 sockser_addr);
141 return SIM_RC_FAIL;
142 }
143
144 port_str = strchr (sockser_addr, ':');
145 if (!port_str)
146 {
147 sim_io_eprintf (sd, "sockser init: missing port number: `%s'\n",
148 sockser_addr);
149 return SIM_RC_FAIL;
150 }
151 tmp = MIN (port_str - sockser_addr, (int) sizeof hostname - 1);
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
213 static void
214 dv_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
228 SIM_RC
229 dv_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
239 static int
240 connected_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
271 sockser_fd = accept (sockser_listen_fd, &sockaddr, &addrlen);
272 if (sockser_fd < 0)
273 return 0;
274
275 /* Set non-blocking i/o. */
276 flags = fcntl (sockser_fd, F_GETFL);
277 flags |= O_NONBLOCK | O_NDELAY;
278 if (fcntl (sockser_fd, F_SETFL, flags) == -1)
279 {
280 sim_io_eprintf (sd, "unable to set nonblocking i/o");
281 close (sockser_fd);
282 sockser_fd = -1;
283 return 0;
284 }
285 return 1;
286 }
287
288 int
289 dv_sockser_status (SIM_DESC sd)
290 {
291 int numrfds,numwfds,status;
292 struct timeval tv;
293 fd_set readfds,writefds;
294
295 /* status to return if the socket isn't set up, or select fails */
296 status = DV_SOCKSER_INPUT_EMPTY | DV_SOCKSER_OUTPUT_EMPTY;
297
298 if (! connected_p (sd))
299 return status;
300
301 FD_ZERO (&readfds);
302 FD_ZERO (&writefds);
303 FD_SET (sockser_fd, &readfds);
304 FD_SET (sockser_fd, &writefds);
305
306 /* ??? One can certainly argue this should be done differently,
307 but for now this is sufficient. The read is done separately
308 from the write to enforce the delay which we heuristically set to
309 once every SOCKSER_TIMEOUT_FREQ tries.
310 No, this isn't great for SMP situations, blah blah blah. */
311
312 {
313 static int n;
314 #define SOCKSER_TIMEOUT_FREQ 42
315 if (++n == SOCKSER_TIMEOUT_FREQ)
316 n = 0;
317 if (n == 0)
318 {
319 tv.tv_sec = 0;
320 tv.tv_usec = sockser_timeout;
321 numrfds = select (sockser_fd + 1, &readfds, 0, 0, &tv);
322 tv.tv_sec = 0;
323 tv.tv_usec = 0;
324 numwfds = select (sockser_fd + 1, 0, &writefds, 0, &tv);
325 }
326 else /* do both selects at once */
327 {
328 tv.tv_sec = 0;
329 tv.tv_usec = 0;
330 numrfds = numwfds = select (sockser_fd + 1, &readfds, &writefds, 0, &tv);
331 }
332 }
333
334 status = 0;
335 if (numrfds <= 0 || ! FD_ISSET (sockser_fd, &readfds))
336 status |= DV_SOCKSER_INPUT_EMPTY;
337 if (numwfds <= 0 || FD_ISSET (sockser_fd, &writefds))
338 status |= DV_SOCKSER_OUTPUT_EMPTY;
339 return status;
340 }
341
342 int
343 dv_sockser_write (SIM_DESC sd, unsigned char c)
344 {
345 int n;
346
347 if (! connected_p (sd))
348 return -1;
349 n = write (sockser_fd, &c, 1);
350 if (n == -1)
351 {
352 if (errno == EPIPE)
353 {
354 close (sockser_fd);
355 sockser_fd = -1;
356 }
357 return -1;
358 }
359 if (n != 1)
360 return -1;
361 return 1;
362 }
363
364 int
365 dv_sockser_read (SIM_DESC sd)
366 {
367 unsigned char c;
368 int n;
369
370 if (! connected_p (sd))
371 return -1;
372 n = read (sockser_fd, &c, 1);
373 /* ??? We're assuming semantics that may not be correct for all hosts.
374 In particular (from cvssrc/src/server.c), this assumes that we are using
375 BSD or POSIX nonblocking I/O. System V nonblocking I/O returns zero if
376 there is nothing to read. */
377 if (n == 0)
378 {
379 close (sockser_fd);
380 sockser_fd = -1;
381 return -1;
382 }
383 if (n != 1)
384 return -1;
385 return c;
386 }