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

Subversion Repositories or1k

[/] [or1k/] [tags/] [final_interface/] [gdb-5.0/] [sim/] [common/] [dv-sockser.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 106 markom
/* 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
#define MIN(a,b) ((a) < (b) ? (a) : (b))
78
 
79
/* Compromise between eating cpu and properly busy-waiting.
80
   One could have an option to set this but for now that seems
81
   like featuritis.  */
82
#define DEFAULT_TIMEOUT 1000 /* microseconds */
83
 
84
/* FIXME: These should allocated at run time and kept with other simulator
85
   state (duh...).  Later.  */
86
const char * sockser_addr = NULL;
87
/* Timeout in microseconds during status flag computation.
88
   Setting this to zero achieves proper busy wait semantics but eats cpu.  */
89
static unsigned int sockser_timeout = DEFAULT_TIMEOUT;
90
static int sockser_listen_fd = -1;
91
static int sockser_fd = -1;
92
 
93
/* FIXME: use tree properties when they're ready.  */
94
 
95
typedef enum {
96
  OPTION_ADDR = OPTION_START
97
} SOCKSER_OPTIONS;
98
 
99
static DECLARE_OPTION_HANDLER (sockser_option_handler);
100
 
101
static const OPTION sockser_options[] =
102
{
103
  { { "sockser-addr", required_argument, NULL, OPTION_ADDR },
104
      '\0', "SOCKET ADDRESS", "Set serial emulation socket address",
105
      sockser_option_handler },
106
  { { NULL, no_argument, NULL, 0 }, '\0', NULL, NULL, NULL }
107
};
108
 
109
static SIM_RC
110
sockser_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt,
111
                        char *arg, int is_command)
112
{
113
  switch (opt)
114
    {
115
    case OPTION_ADDR :
116
      sockser_addr = arg;
117
      break;
118
    }
119
 
120
  return SIM_RC_OK;
121
}
122
 
123
static SIM_RC
124
dv_sockser_init (SIM_DESC sd)
125
{
126
  struct hostent *hostent;
127
  struct sockaddr_in sockaddr;
128
  char hostname[100];
129
  const char *port_str;
130
  int tmp,port;
131
 
132
  if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT
133
      || sockser_addr == NULL)
134
    return SIM_RC_OK;
135
 
136
  if (*sockser_addr == '/')
137
    {
138
      /* support for these can come later */
139
      sim_io_eprintf (sd, "sockser init: unix domain sockets not supported: `%s'\n",
140
                      sockser_addr);
141
      return SIM_RC_FAIL;
142
    }
143
 
144
  port_str = strchr (sockser_addr, ':');
145
  if (!port_str)
146
    {
147
      sim_io_eprintf (sd, "sockser init: missing port number: `%s'\n",
148
                      sockser_addr);
149
      return SIM_RC_FAIL;
150
    }
151
  tmp = MIN (port_str - sockser_addr, (int) 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.