OpenCores
URL https://opencores.org/ocsvn/scarts/scarts/trunk

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gdb/] [gdb-6.8/] [sim/] [common/] [dv-sockser.c] - Blame information for rev 26

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 26 jlechner
/* Serial port emulation using sockets.
2
   Copyright (C) 1998, 2007, 2008 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
 
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.  */
84
const 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.  */
87
static unsigned int sockser_timeout = DEFAULT_TIMEOUT;
88
static int sockser_listen_fd = -1;
89
static int sockser_fd = -1;
90
 
91
/* FIXME: use tree properties when they're ready.  */
92
 
93
typedef enum {
94
  OPTION_ADDR = OPTION_START
95
} SOCKSER_OPTIONS;
96
 
97
static DECLARE_OPTION_HANDLER (sockser_option_handler);
98
 
99
static 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
 
107
static SIM_RC
108
sockser_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
 
121
static SIM_RC
122
dv_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
 
213
static void
214
dv_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
 
228
SIM_RC
229
dv_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
 
239
static int
240
connected_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
 
289
int
290
dv_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
 
343
int
344
dv_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
 
365
int
366
dv_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
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.