OSDN Git Service

919519090d435214a3558d7d5857cae5e8fda559
[pf3gnuchains/pf3gnuchains4x.git] / sim / common / dv-sockser.c
1 /* Serial port emulation using sockets.
2    Copyright (C) 1998, 2007, 2008, 2009, 2010 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 "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
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.  */
84 const 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.  */
87 static unsigned int sockser_timeout = DEFAULT_TIMEOUT;
88 static int sockser_listen_fd = -1;
89 static int sockser_fd = -1;
90 \f
91 /* FIXME: use tree properties when they're ready.  */
92
93 typedef enum {
94   OPTION_ADDR = OPTION_START
95 } SOCKSER_OPTIONS;
96
97 static DECLARE_OPTION_HANDLER (sockser_option_handler);
98
99 static 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
107 static SIM_RC
108 sockser_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
121 static SIM_RC
122 dv_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     }
149   tmp = port_str - sockser_addr;
150   if (tmp >= sizeof hostname)
151     tmp = 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   addrlen = sizeof (sockaddr);
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
289 int
290 dv_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
343 int
344 dv_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
365 int
366 dv_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 }