xref: /netbsd-src/external/gpl3/gdb/dist/sim/common/dv-sockser.c (revision 181254a7b1bdde6873432bffef2d2decc4b5c22f)
1 /* Serial port emulation using sockets.
2    Copyright (C) 1998-2019 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 
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 
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 
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 }
401