1/* Serial port emulation using sockets.
2   Copyright (C) 1998, 2007, 2008, 2009, 2010, 2011
3   Free Software Foundation, Inc.
4   Contributed by Cygnus Solutions.
5
6This program is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 3 of the License, or
9(at your option) any later version.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
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#ifndef HAVE_SOCKLEN_T
60typedef 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.  */
89const 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.  */
92static unsigned int sockser_timeout = DEFAULT_TIMEOUT;
93static int sockser_listen_fd = -1;
94static int sockser_fd = -1;
95
96/* FIXME: use tree properties when they're ready.  */
97
98typedef enum {
99  OPTION_ADDR = OPTION_START
100} SOCKSER_OPTIONS;
101
102static DECLARE_OPTION_HANDLER (sockser_option_handler);
103
104static 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
112static SIM_RC
113sockser_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
126static SIM_RC
127dv_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
218static void
219dv_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
233SIM_RC
234dv_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
244static int
245connected_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
294int
295dv_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
349int
350dv_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
372int
373dv_sockser_write (SIM_DESC sd, unsigned char c)
374{
375  return dv_sockser_write_buffer (sd, &c, 1);
376}
377
378int
379dv_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