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