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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [gdb-7.2/] [sim/] [common/] [dv-sockser.c] - Blame information for rev 438

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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