1/* Serial port emulation using sockets.
2   Copyright (C) 1998, 2007 Free Software Foundation, Inc.
3   Contributed by Cygnus Solutions.
4
5This program is free software; you can redistribute it and/or modify
6it under the terms of the GNU General Public License as published by
7the Free Software Foundation; either version 3 of the License, or
8(at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along 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
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
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.  */
84const 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.  */
87static unsigned int sockser_timeout = DEFAULT_TIMEOUT;
88static int sockser_listen_fd = -1;
89static int sockser_fd = -1;
90
91/* FIXME: use tree properties when they're ready.  */
92
93typedef enum {
94  OPTION_ADDR = OPTION_START
95} SOCKSER_OPTIONS;
96
97static DECLARE_OPTION_HANDLER (sockser_option_handler);
98
99static 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
107static SIM_RC
108sockser_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
121static SIM_RC
122dv_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
213static void
214dv_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
228SIM_RC
229dv_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
239static int
240connected_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
289int
290dv_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
343int
344dv_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
365int
366dv_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}
388