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