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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [sim/] [common/] [dv-sockser.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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