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