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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-stable/] [gdb-7.2/] [sim/] [common/] [dv-sockser.c] - Diff between revs 835 and 841

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 835 Rev 841
/* Serial port emulation using sockets.
/* Serial port emulation using sockets.
   Copyright (C) 1998, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
   Copyright (C) 1998, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
   Contributed by Cygnus Solutions.
   Contributed by Cygnus Solutions.
 
 
This program is free software; you can redistribute it and/or modify
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
(at your option) any later version.
 
 
This program is distributed in the hope that it will be useful,
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
GNU General Public License for more details.
 
 
You should have received a copy of the GNU General Public License
You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 
/* FIXME: will obviously need to evolve.
/* FIXME: will obviously need to evolve.
   - connectionless sockets might be more appropriate.  */
   - connectionless sockets might be more appropriate.  */
 
 
#include "sim-main.h"
#include "sim-main.h"
 
 
#ifdef HAVE_STRING_H
#ifdef HAVE_STRING_H
#include <string.h>
#include <string.h>
#else
#else
#ifdef HAVE_STRINGS_H
#ifdef HAVE_STRINGS_H
#include <strings.h>
#include <strings.h>
#endif
#endif
#endif
#endif
#include <signal.h>
#include <signal.h>
#ifdef HAVE_STDLIB_H
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#include <stdlib.h>
#endif
#endif
#ifdef HAVE_FCNTL_H
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#include <fcntl.h>
#endif
#endif
#ifdef HAVE_UNISTD_H
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#include <unistd.h>
#endif
#endif
 
 
#include <errno.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/socket.h>
 
 
#ifndef __CYGWIN32__
#ifndef __CYGWIN32__
#include <netinet/tcp.h>
#include <netinet/tcp.h>
#endif
#endif
 
 
#include "sim-assert.h"
#include "sim-assert.h"
#include "sim-options.h"
#include "sim-options.h"
 
 
#include "dv-sockser.h"
#include "dv-sockser.h"


#ifndef HAVE_SOCKLEN_T
#ifndef HAVE_SOCKLEN_T
typedef int socklen_t;
typedef int socklen_t;
#endif
#endif
 
 
/* Get definitions for both O_NONBLOCK and O_NDELAY.  */
/* Get definitions for both O_NONBLOCK and O_NDELAY.  */
 
 
#ifndef O_NDELAY
#ifndef O_NDELAY
#ifdef FNDELAY
#ifdef FNDELAY
#define O_NDELAY FNDELAY
#define O_NDELAY FNDELAY
#else /* ! defined (FNDELAY) */
#else /* ! defined (FNDELAY) */
#define O_NDELAY 0
#define O_NDELAY 0
#endif /* ! defined (FNDELAY) */
#endif /* ! defined (FNDELAY) */
#endif /* ! defined (O_NDELAY) */
#endif /* ! defined (O_NDELAY) */
 
 
#ifndef O_NONBLOCK
#ifndef O_NONBLOCK
#ifdef FNBLOCK
#ifdef FNBLOCK
#define O_NONBLOCK FNBLOCK
#define O_NONBLOCK FNBLOCK
#else /* ! defined (FNBLOCK) */
#else /* ! defined (FNBLOCK) */
#define O_NONBLOCK 0
#define O_NONBLOCK 0
#endif /* ! defined (FNBLOCK) */
#endif /* ! defined (FNBLOCK) */
#endif /* ! defined (O_NONBLOCK) */
#endif /* ! defined (O_NONBLOCK) */


 
 
/* Compromise between eating cpu and properly busy-waiting.
/* Compromise between eating cpu and properly busy-waiting.
   One could have an option to set this but for now that seems
   One could have an option to set this but for now that seems
   like featuritis.  */
   like featuritis.  */
#define DEFAULT_TIMEOUT 1000 /* microseconds */
#define DEFAULT_TIMEOUT 1000 /* microseconds */
 
 
/* FIXME: These should allocated at run time and kept with other simulator
/* FIXME: These should allocated at run time and kept with other simulator
   state (duh...).  Later.  */
   state (duh...).  Later.  */
const char * sockser_addr = NULL;
const char * sockser_addr = NULL;
/* Timeout in microseconds during status flag computation.
/* Timeout in microseconds during status flag computation.
   Setting this to zero achieves proper busy wait semantics but eats cpu.  */
   Setting this to zero achieves proper busy wait semantics but eats cpu.  */
static unsigned int sockser_timeout = DEFAULT_TIMEOUT;
static unsigned int sockser_timeout = DEFAULT_TIMEOUT;
static int sockser_listen_fd = -1;
static int sockser_listen_fd = -1;
static int sockser_fd = -1;
static int sockser_fd = -1;


/* FIXME: use tree properties when they're ready.  */
/* FIXME: use tree properties when they're ready.  */
 
 
typedef enum {
typedef enum {
  OPTION_ADDR = OPTION_START
  OPTION_ADDR = OPTION_START
} SOCKSER_OPTIONS;
} SOCKSER_OPTIONS;
 
 
static DECLARE_OPTION_HANDLER (sockser_option_handler);
static DECLARE_OPTION_HANDLER (sockser_option_handler);
 
 
static const OPTION sockser_options[] =
static const OPTION sockser_options[] =
{
{
  { { "sockser-addr", required_argument, NULL, OPTION_ADDR },
  { { "sockser-addr", required_argument, NULL, OPTION_ADDR },
      '\0', "SOCKET ADDRESS", "Set serial emulation socket address",
      '\0', "SOCKET ADDRESS", "Set serial emulation socket address",
      sockser_option_handler, NULL },
      sockser_option_handler, NULL },
  { { NULL, no_argument, NULL, 0 }, '\0', NULL, NULL, NULL, NULL }
  { { NULL, no_argument, NULL, 0 }, '\0', NULL, NULL, NULL, NULL }
};
};
 
 
static SIM_RC
static SIM_RC
sockser_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt,
sockser_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt,
                        char *arg, int is_command)
                        char *arg, int is_command)
{
{
  switch (opt)
  switch (opt)
    {
    {
    case OPTION_ADDR :
    case OPTION_ADDR :
      sockser_addr = arg;
      sockser_addr = arg;
      break;
      break;
    }
    }
 
 
  return SIM_RC_OK;
  return SIM_RC_OK;
}
}
 
 
static SIM_RC
static SIM_RC
dv_sockser_init (SIM_DESC sd)
dv_sockser_init (SIM_DESC sd)
{
{
  struct hostent *hostent;
  struct hostent *hostent;
  struct sockaddr_in sockaddr;
  struct sockaddr_in sockaddr;
  char hostname[100];
  char hostname[100];
  const char *port_str;
  const char *port_str;
  int tmp,port;
  int tmp,port;
 
 
  if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT
  if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT
      || sockser_addr == NULL)
      || sockser_addr == NULL)
    return SIM_RC_OK;
    return SIM_RC_OK;
 
 
  if (*sockser_addr == '/')
  if (*sockser_addr == '/')
    {
    {
      /* support for these can come later */
      /* support for these can come later */
      sim_io_eprintf (sd, "sockser init: unix domain sockets not supported: `%s'\n",
      sim_io_eprintf (sd, "sockser init: unix domain sockets not supported: `%s'\n",
                      sockser_addr);
                      sockser_addr);
      return SIM_RC_FAIL;
      return SIM_RC_FAIL;
    }
    }
 
 
  port_str = strchr (sockser_addr, ':');
  port_str = strchr (sockser_addr, ':');
  if (!port_str)
  if (!port_str)
    {
    {
      sim_io_eprintf (sd, "sockser init: missing port number: `%s'\n",
      sim_io_eprintf (sd, "sockser init: missing port number: `%s'\n",
                      sockser_addr);
                      sockser_addr);
      return SIM_RC_FAIL;
      return SIM_RC_FAIL;
    }
    }
  tmp = port_str - sockser_addr;
  tmp = port_str - sockser_addr;
  if (tmp >= sizeof hostname)
  if (tmp >= sizeof hostname)
    tmp = sizeof (hostname) - 1;
    tmp = sizeof (hostname) - 1;
  strncpy (hostname, sockser_addr, tmp);
  strncpy (hostname, sockser_addr, tmp);
  hostname[tmp] = '\000';
  hostname[tmp] = '\000';
  port = atoi (port_str + 1);
  port = atoi (port_str + 1);
 
 
  hostent = gethostbyname (hostname);
  hostent = gethostbyname (hostname);
  if (! hostent)
  if (! hostent)
    {
    {
      sim_io_eprintf (sd, "sockser init: unknown host: %s\n",
      sim_io_eprintf (sd, "sockser init: unknown host: %s\n",
                      hostname);
                      hostname);
      return SIM_RC_FAIL;
      return SIM_RC_FAIL;
    }
    }
 
 
  sockser_listen_fd = socket (PF_INET, SOCK_STREAM, 0);
  sockser_listen_fd = socket (PF_INET, SOCK_STREAM, 0);
  if (sockser_listen_fd == -1)
  if (sockser_listen_fd == -1)
    {
    {
      sim_io_eprintf (sd, "sockser init: unable to get socket: %s\n",
      sim_io_eprintf (sd, "sockser init: unable to get socket: %s\n",
                      strerror (errno));
                      strerror (errno));
      return SIM_RC_FAIL;
      return SIM_RC_FAIL;
    }
    }
 
 
  sockaddr.sin_family = PF_INET;
  sockaddr.sin_family = PF_INET;
  sockaddr.sin_port = htons(port);
  sockaddr.sin_port = htons(port);
  memcpy (&sockaddr.sin_addr.s_addr, hostent->h_addr,
  memcpy (&sockaddr.sin_addr.s_addr, hostent->h_addr,
          sizeof (struct in_addr));
          sizeof (struct in_addr));
 
 
  tmp = 1;
  tmp = 1;
  if (setsockopt (sockser_listen_fd, SOL_SOCKET, SO_REUSEADDR, (void*)& tmp, sizeof(tmp)) < 0)
  if (setsockopt (sockser_listen_fd, SOL_SOCKET, SO_REUSEADDR, (void*)& tmp, sizeof(tmp)) < 0)
    {
    {
      sim_io_eprintf (sd, "sockser init: unable to set SO_REUSEADDR: %s\n",
      sim_io_eprintf (sd, "sockser init: unable to set SO_REUSEADDR: %s\n",
                      strerror (errno));
                      strerror (errno));
    }
    }
  if (bind (sockser_listen_fd, (struct sockaddr *) &sockaddr, sizeof (sockaddr)) < 0)
  if (bind (sockser_listen_fd, (struct sockaddr *) &sockaddr, sizeof (sockaddr)) < 0)
    {
    {
      sim_io_eprintf (sd, "sockser init: unable to bind socket address: %s\n",
      sim_io_eprintf (sd, "sockser init: unable to bind socket address: %s\n",
                      strerror (errno));
                      strerror (errno));
      close (sockser_listen_fd);
      close (sockser_listen_fd);
      sockser_listen_fd = -1;
      sockser_listen_fd = -1;
      return SIM_RC_FAIL;
      return SIM_RC_FAIL;
    }
    }
  if (listen (sockser_listen_fd, 1) < 0)
  if (listen (sockser_listen_fd, 1) < 0)
    {
    {
      sim_io_eprintf (sd, "sockser init: unable to set up listener: %s\n",
      sim_io_eprintf (sd, "sockser init: unable to set up listener: %s\n",
                      strerror (errno));
                      strerror (errno));
      close (sockser_listen_fd);
      close (sockser_listen_fd);
      sockser_listen_fd = -1;
      sockser_listen_fd = -1;
      return SIM_RC_OK;
      return SIM_RC_OK;
    }
    }
 
 
  /* Handle writes to missing client -> SIGPIPE.
  /* Handle writes to missing client -> SIGPIPE.
     ??? Need a central signal management module.  */
     ??? Need a central signal management module.  */
  {
  {
    RETSIGTYPE (*orig) ();
    RETSIGTYPE (*orig) ();
    orig = signal (SIGPIPE, SIG_IGN);
    orig = signal (SIGPIPE, SIG_IGN);
    /* If a handler is already set up, don't mess with it.  */
    /* If a handler is already set up, don't mess with it.  */
    if (orig != SIG_DFL && orig != SIG_IGN)
    if (orig != SIG_DFL && orig != SIG_IGN)
      signal (SIGPIPE, orig);
      signal (SIGPIPE, orig);
  }
  }
 
 
  return SIM_RC_OK;
  return SIM_RC_OK;
}
}
 
 
static void
static void
dv_sockser_uninstall (SIM_DESC sd)
dv_sockser_uninstall (SIM_DESC sd)
{
{
  if (sockser_listen_fd != -1)
  if (sockser_listen_fd != -1)
    {
    {
      close (sockser_listen_fd);
      close (sockser_listen_fd);
      sockser_listen_fd = -1;
      sockser_listen_fd = -1;
    }
    }
  if (sockser_fd != -1)
  if (sockser_fd != -1)
    {
    {
      close (sockser_fd);
      close (sockser_fd);
      sockser_fd = -1;
      sockser_fd = -1;
    }
    }
}
}
 
 
SIM_RC
SIM_RC
dv_sockser_install (SIM_DESC sd)
dv_sockser_install (SIM_DESC sd)
{
{
  SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
  SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
  if (sim_add_option_table (sd, NULL, sockser_options) != SIM_RC_OK)
  if (sim_add_option_table (sd, NULL, sockser_options) != SIM_RC_OK)
    return SIM_RC_FAIL;
    return SIM_RC_FAIL;
  sim_module_add_init_fn (sd, dv_sockser_init);
  sim_module_add_init_fn (sd, dv_sockser_init);
  sim_module_add_uninstall_fn (sd, dv_sockser_uninstall);
  sim_module_add_uninstall_fn (sd, dv_sockser_uninstall);
  return SIM_RC_OK;
  return SIM_RC_OK;
}
}
 
 
static int
static int
connected_p (SIM_DESC sd)
connected_p (SIM_DESC sd)
{
{
  int numfds,flags;
  int numfds,flags;
  struct timeval tv;
  struct timeval tv;
  fd_set readfds;
  fd_set readfds;
  struct sockaddr sockaddr;
  struct sockaddr sockaddr;
  socklen_t addrlen;
  socklen_t addrlen;
 
 
  if (sockser_listen_fd == -1)
  if (sockser_listen_fd == -1)
    return 0;
    return 0;
 
 
  if (sockser_fd >= 0)
  if (sockser_fd >= 0)
    {
    {
      /* FIXME: has client gone away? */
      /* FIXME: has client gone away? */
      return 1;
      return 1;
    }
    }
 
 
  /* Not connected.  Connect with a client if there is one.  */
  /* Not connected.  Connect with a client if there is one.  */
 
 
  FD_ZERO (&readfds);
  FD_ZERO (&readfds);
  FD_SET (sockser_listen_fd, &readfds);
  FD_SET (sockser_listen_fd, &readfds);
 
 
  /* ??? One can certainly argue this should be done differently,
  /* ??? One can certainly argue this should be done differently,
     but for now this is sufficient.  */
     but for now this is sufficient.  */
  tv.tv_sec = 0;
  tv.tv_sec = 0;
  tv.tv_usec = sockser_timeout;
  tv.tv_usec = sockser_timeout;
 
 
  numfds = select (sockser_listen_fd + 1, &readfds, 0, 0, &tv);
  numfds = select (sockser_listen_fd + 1, &readfds, 0, 0, &tv);
  if (numfds <= 0)
  if (numfds <= 0)
    return 0;
    return 0;
 
 
  addrlen = sizeof (sockaddr);
  addrlen = sizeof (sockaddr);
  sockser_fd = accept (sockser_listen_fd, &sockaddr, &addrlen);
  sockser_fd = accept (sockser_listen_fd, &sockaddr, &addrlen);
  if (sockser_fd == -1)
  if (sockser_fd == -1)
    return 0;
    return 0;
 
 
  /* Set non-blocking i/o.  */
  /* Set non-blocking i/o.  */
  flags = fcntl (sockser_fd, F_GETFL);
  flags = fcntl (sockser_fd, F_GETFL);
  flags |= O_NONBLOCK | O_NDELAY;
  flags |= O_NONBLOCK | O_NDELAY;
  if (fcntl (sockser_fd, F_SETFL, flags) == -1)
  if (fcntl (sockser_fd, F_SETFL, flags) == -1)
    {
    {
      sim_io_eprintf (sd, "unable to set nonblocking i/o");
      sim_io_eprintf (sd, "unable to set nonblocking i/o");
      close (sockser_fd);
      close (sockser_fd);
      sockser_fd = -1;
      sockser_fd = -1;
      return 0;
      return 0;
    }
    }
  return 1;
  return 1;
}
}
 
 
int
int
dv_sockser_status (SIM_DESC sd)
dv_sockser_status (SIM_DESC sd)
{
{
  int numrfds,numwfds,status;
  int numrfds,numwfds,status;
  struct timeval tv;
  struct timeval tv;
  fd_set readfds,writefds;
  fd_set readfds,writefds;
 
 
  /* status to return if the socket isn't set up, or select fails */
  /* status to return if the socket isn't set up, or select fails */
  status = DV_SOCKSER_INPUT_EMPTY | DV_SOCKSER_OUTPUT_EMPTY |
  status = DV_SOCKSER_INPUT_EMPTY | DV_SOCKSER_OUTPUT_EMPTY |
           DV_SOCKSER_DISCONNECTED;
           DV_SOCKSER_DISCONNECTED;
 
 
  if (! connected_p (sd))
  if (! connected_p (sd))
    return status;
    return status;
 
 
  FD_ZERO (&readfds);
  FD_ZERO (&readfds);
  FD_ZERO (&writefds);
  FD_ZERO (&writefds);
  FD_SET (sockser_fd, &readfds);
  FD_SET (sockser_fd, &readfds);
  FD_SET (sockser_fd, &writefds);
  FD_SET (sockser_fd, &writefds);
 
 
  /* ??? One can certainly argue this should be done differently,
  /* ??? One can certainly argue this should be done differently,
     but for now this is sufficient.  The read is done separately
     but for now this is sufficient.  The read is done separately
     from the write to enforce the delay which we heuristically set to
     from the write to enforce the delay which we heuristically set to
     once every SOCKSER_TIMEOUT_FREQ tries.
     once every SOCKSER_TIMEOUT_FREQ tries.
     No, this isn't great for SMP situations, blah blah blah.  */
     No, this isn't great for SMP situations, blah blah blah.  */
 
 
  {
  {
    static int n;
    static int n;
#define SOCKSER_TIMEOUT_FREQ 42
#define SOCKSER_TIMEOUT_FREQ 42
    if (++n == SOCKSER_TIMEOUT_FREQ)
    if (++n == SOCKSER_TIMEOUT_FREQ)
      n = 0;
      n = 0;
    if (n == 0)
    if (n == 0)
      {
      {
        tv.tv_sec = 0;
        tv.tv_sec = 0;
        tv.tv_usec = sockser_timeout;
        tv.tv_usec = sockser_timeout;
        numrfds = select (sockser_fd + 1, &readfds, 0, 0, &tv);
        numrfds = select (sockser_fd + 1, &readfds, 0, 0, &tv);
        tv.tv_sec = 0;
        tv.tv_sec = 0;
        tv.tv_usec = 0;
        tv.tv_usec = 0;
        numwfds = select (sockser_fd + 1, 0, &writefds, 0, &tv);
        numwfds = select (sockser_fd + 1, 0, &writefds, 0, &tv);
      }
      }
    else /* do both selects at once */
    else /* do both selects at once */
      {
      {
        tv.tv_sec = 0;
        tv.tv_sec = 0;
        tv.tv_usec = 0;
        tv.tv_usec = 0;
        numrfds = numwfds = select (sockser_fd + 1, &readfds, &writefds, 0, &tv);
        numrfds = numwfds = select (sockser_fd + 1, &readfds, &writefds, 0, &tv);
      }
      }
  }
  }
 
 
  status = 0;
  status = 0;
  if (numrfds <= 0 || ! FD_ISSET (sockser_fd, &readfds))
  if (numrfds <= 0 || ! FD_ISSET (sockser_fd, &readfds))
    status |= DV_SOCKSER_INPUT_EMPTY;
    status |= DV_SOCKSER_INPUT_EMPTY;
  if (numwfds <= 0 || FD_ISSET (sockser_fd, &writefds))
  if (numwfds <= 0 || FD_ISSET (sockser_fd, &writefds))
    status |= DV_SOCKSER_OUTPUT_EMPTY;
    status |= DV_SOCKSER_OUTPUT_EMPTY;
  return status;
  return status;
}
}
 
 
int
int
dv_sockser_write (SIM_DESC sd, unsigned char c)
dv_sockser_write (SIM_DESC sd, unsigned char c)
{
{
  int n;
  int n;
 
 
  if (! connected_p (sd))
  if (! connected_p (sd))
    return -1;
    return -1;
  n = write (sockser_fd, &c, 1);
  n = write (sockser_fd, &c, 1);
  if (n == -1)
  if (n == -1)
    {
    {
      if (errno == EPIPE)
      if (errno == EPIPE)
        {
        {
          close (sockser_fd);
          close (sockser_fd);
          sockser_fd = -1;
          sockser_fd = -1;
        }
        }
      return -1;
      return -1;
    }
    }
  if (n != 1)
  if (n != 1)
    return -1;
    return -1;
  return 1;
  return 1;
}
}
 
 
int
int
dv_sockser_read (SIM_DESC sd)
dv_sockser_read (SIM_DESC sd)
{
{
  unsigned char c;
  unsigned char c;
  int n;
  int n;
 
 
  if (! connected_p (sd))
  if (! connected_p (sd))
    return -1;
    return -1;
  n = read (sockser_fd, &c, 1);
  n = read (sockser_fd, &c, 1);
  /* ??? We're assuming semantics that may not be correct for all hosts.
  /* ??? We're assuming semantics that may not be correct for all hosts.
     In particular (from cvssrc/src/server.c), this assumes that we are using
     In particular (from cvssrc/src/server.c), this assumes that we are using
     BSD or POSIX nonblocking I/O.  System V nonblocking I/O returns zero if
     BSD or POSIX nonblocking I/O.  System V nonblocking I/O returns zero if
     there is nothing to read.  */
     there is nothing to read.  */
  if (n == 0)
  if (n == 0)
    {
    {
      close (sockser_fd);
      close (sockser_fd);
      sockser_fd = -1;
      sockser_fd = -1;
      return -1;
      return -1;
    }
    }
  if (n != 1)
  if (n != 1)
    return -1;
    return -1;
  return c;
  return c;
}
}
 
 

powered by: WebSVN 2.1.0

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