From 071ea11e85eb9d529cc5eb3d35f6247466a21b99 Mon Sep 17 00:00:00 2001 From: Stan Shebs Date: Fri, 16 Apr 1999 01:34:07 +0000 Subject: Initial creation of sourceware repository --- sim/common/dv-sockser.c | 377 ------------------------------------------------ 1 file changed, 377 deletions(-) delete mode 100644 sim/common/dv-sockser.c (limited to 'sim/common/dv-sockser.c') diff --git a/sim/common/dv-sockser.c b/sim/common/dv-sockser.c deleted file mode 100644 index d90c817..0000000 --- a/sim/common/dv-sockser.c +++ /dev/null @@ -1,377 +0,0 @@ -/* Serial port emulation using sockets. - Copyright (C) 1998 Free Software Foundation, Inc. - Contributed by Cygnus Solutions. - -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 -the Free Software Foundation; either version 2, or (at your option) -any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -/* FIXME: will obviously need to evolve. - - connectionless sockets might be more appropriate. */ - -#include "sim-main.h" - -#ifdef HAVE_STRING_H -#include -#else -#ifdef HAVE_STRINGS_H -#include -#endif -#endif -#include -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_FCNTL_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include - -#ifndef __CYGWIN32__ -#include -#endif - -#include "sim-assert.h" -#include "sim-options.h" - -#include "dv-sockser.h" - -/* Get definitions for both O_NONBLOCK and O_NDELAY. */ - -#ifndef O_NDELAY -#ifdef FNDELAY -#define O_NDELAY FNDELAY -#else /* ! defined (FNDELAY) */ -#define O_NDELAY 0 -#endif /* ! defined (FNDELAY) */ -#endif /* ! defined (O_NDELAY) */ - -#ifndef O_NONBLOCK -#ifdef FNBLOCK -#define O_NONBLOCK FNBLOCK -#else /* ! defined (FNBLOCK) */ -#define O_NONBLOCK 0 -#endif /* ! defined (FNBLOCK) */ -#endif /* ! defined (O_NONBLOCK) */ - -#define MIN(a,b) ((a) < (b) ? (a) : (b)) - -/* Compromise between eating cpu and properly busy-waiting. - One could have an option to set this but for now that seems - like featuritis. */ -#define DEFAULT_TIMEOUT 100 /* microseconds */ - -/* FIXME: These should allocated at run time and kept with other simulator - state (duh...). Later. */ -const char * sockser_addr = NULL; -/* Timeout in microseconds during status flag computation. - Setting this to zero achieves proper busy wait semantics but eats cpu. */ -static unsigned int sockser_timeout = DEFAULT_TIMEOUT; -static int sockser_listen_fd = -1; -static int sockser_fd = -1; - -/* FIXME: use tree properties when they're ready. */ - -typedef enum { - OPTION_ADDR = OPTION_START -} SOCKSER_OPTIONS; - -static DECLARE_OPTION_HANDLER (sockser_option_handler); - -static const OPTION sockser_options[] = -{ - { { "sockser-addr", required_argument, NULL, OPTION_ADDR }, - '\0', "SOCKET ADDRESS", "Set serial emulation socket address", - sockser_option_handler }, - { { NULL, no_argument, NULL, 0 }, '\0', NULL, NULL, NULL } -}; - -static SIM_RC -sockser_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt, - char *arg, int is_command) -{ - switch (opt) - { - case OPTION_ADDR : - sockser_addr = arg; - break; - } - - return SIM_RC_OK; -} - -static SIM_RC -dv_sockser_init (SIM_DESC sd) -{ - struct hostent *hostent; - struct sockaddr_in sockaddr; - char hostname[100]; - const char *port_str; - int tmp,port; - - if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT - || sockser_addr == NULL) - return SIM_RC_OK; - - if (*sockser_addr == '/') - { - /* support for these can come later */ - sim_io_eprintf (sd, "sockser init: unix domain sockets not supported: `%s'\n", - sockser_addr); - return SIM_RC_FAIL; - } - - port_str = strchr (sockser_addr, ':'); - if (!port_str) - { - sim_io_eprintf (sd, "sockser init: missing port number: `%s'\n", - sockser_addr); - return SIM_RC_FAIL; - } - tmp = MIN (port_str - sockser_addr, (int) sizeof hostname - 1); - strncpy (hostname, sockser_addr, tmp); - hostname[tmp] = '\000'; - port = atoi (port_str + 1); - - hostent = gethostbyname (hostname); - if (! hostent) - { - sim_io_eprintf (sd, "sockser init: unknown host: %s\n", - hostname); - return SIM_RC_FAIL; - } - - sockser_listen_fd = socket (PF_INET, SOCK_STREAM, 0); - if (sockser_listen_fd < 0) - { - sim_io_eprintf (sd, "sockser init: unable to get socket: %s\n", - strerror (errno)); - return SIM_RC_FAIL; - } - - sockaddr.sin_family = PF_INET; - sockaddr.sin_port = htons(port); - memcpy (&sockaddr.sin_addr.s_addr, hostent->h_addr, - sizeof (struct in_addr)); - - if (bind (sockser_listen_fd, (struct sockaddr *) &sockaddr, sizeof (sockaddr)) < 0) - { - sim_io_eprintf (sd, "sockser init: unable to bind socket address: %s\n", - strerror (errno)); - close (sockser_listen_fd); - sockser_listen_fd = -1; - return SIM_RC_FAIL; - } - if (listen (sockser_listen_fd, 1) < 0) - { - sim_io_eprintf (sd, "sockser init: unable to set up listener: %s\n", - strerror (errno)); - close (sockser_listen_fd); - sockser_listen_fd = -1; - return SIM_RC_OK; - } - - /* Handle writes to missing client -> SIGPIPE. - ??? Need a central signal management module. */ - { - RETSIGTYPE (*orig) (); - orig = signal (SIGPIPE, SIG_IGN); - /* If a handler is already set up, don't mess with it. */ - if (orig != SIG_DFL && orig != SIG_IGN) - signal (SIGPIPE, orig); - } - - return SIM_RC_OK; -} - -static void -dv_sockser_uninstall (SIM_DESC sd) -{ - if (sockser_listen_fd != -1) - { - close (sockser_listen_fd); - sockser_listen_fd = -1; - } - if (sockser_fd != -1) - { - close (sockser_fd); - sockser_fd = -1; - } -} - -SIM_RC -dv_sockser_install (SIM_DESC sd) -{ - SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); - if (sim_add_option_table (sd, NULL, sockser_options) != SIM_RC_OK) - return SIM_RC_FAIL; - sim_module_add_init_fn (sd, dv_sockser_init); - sim_module_add_uninstall_fn (sd, dv_sockser_uninstall); - return SIM_RC_OK; -} - -static int -connected_p (SIM_DESC sd) -{ - int numfds,flags; - struct timeval tv; - fd_set readfds; - struct sockaddr sockaddr; - int addrlen; - - if (sockser_listen_fd == -1) - return 0; - - if (sockser_fd >= 0) - { - /* FIXME: has client gone away? */ - return 1; - } - - /* Not connected. Connect with a client if there is one. */ - - FD_ZERO (&readfds); - FD_SET (sockser_listen_fd, &readfds); - - /* ??? One can certainly argue this should be done differently, - but for now this is sufficient. */ - tv.tv_sec = 0; - tv.tv_usec = sockser_timeout; - - numfds = select (sockser_listen_fd + 1, &readfds, 0, 0, &tv); - if (numfds <= 0) - return 0; - - sockser_fd = accept (sockser_listen_fd, &sockaddr, &addrlen); - if (sockser_fd < 0) - return 0; - - /* Set non-blocking i/o. */ - flags = fcntl (sockser_fd, F_GETFL); - flags |= O_NONBLOCK | O_NDELAY; - if (fcntl (sockser_fd, F_SETFL, flags) == -1) - { - sim_io_eprintf (sd, "unable to set nonblocking i/o"); - close (sockser_fd); - sockser_fd = -1; - return 0; - } - return 1; -} - -int -dv_sockser_status (SIM_DESC sd) -{ - int numrfds,numwfds,status; - struct timeval tv; - fd_set readfds,writefds; - - /* status to return if the socket isn't set up, or select fails */ - status = DV_SOCKSER_INPUT_EMPTY | DV_SOCKSER_OUTPUT_EMPTY; - - if (! connected_p (sd)) - return status; - - FD_ZERO (&readfds); - FD_ZERO (&writefds); - FD_SET (sockser_fd, &readfds); - FD_SET (sockser_fd, &writefds); - - /* ??? One can certainly argue this should be done differently, - but for now this is sufficient. The read is done separately - from the write to enforce the delay which we heuristically set to - once every SOCKSER_TIMEOUT_FREQ tries. - No, this isn't great for SMP situations, blah blah blah. */ - - { - static int n; -#define SOCKSER_TIMEOUT_FREQ 42 - if (++n == SOCKSER_TIMEOUT_FREQ) - n = 0; - if (n == 0) - { - tv.tv_sec = 0; - tv.tv_usec = sockser_timeout; - numrfds = select (sockser_fd + 1, &readfds, 0, 0, &tv); - tv.tv_sec = 0; - tv.tv_usec = 0; - numwfds = select (sockser_fd + 1, 0, &writefds, 0, &tv); - } - else /* do both selects at once */ - { - tv.tv_sec = 0; - tv.tv_usec = 0; - numrfds = numwfds = select (sockser_fd + 1, &readfds, &writefds, 0, &tv); - } - } - - status = 0; - if (numrfds <= 0 || ! FD_ISSET (sockser_fd, &readfds)) - status |= DV_SOCKSER_INPUT_EMPTY; - if (numwfds <= 0 || FD_ISSET (sockser_fd, &writefds)) - status |= DV_SOCKSER_OUTPUT_EMPTY; - return status; -} - -int -dv_sockser_write (SIM_DESC sd, unsigned char c) -{ - int n; - - if (! connected_p (sd)) - return -1; - n = write (sockser_fd, &c, 1); - if (n == -1) - { - if (errno == EPIPE) - { - close (sockser_fd); - sockser_fd = -1; - } - return -1; - } - if (n != 1) - return -1; - return 1; -} - -int -dv_sockser_read (SIM_DESC sd) -{ - unsigned char c; - int n; - - if (! connected_p (sd)) - return -1; - n = read (sockser_fd, &c, 1); - /* ??? 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 - BSD or POSIX nonblocking I/O. System V nonblocking I/O returns zero if - there is nothing to read. */ - if (n == 0) - { - close (sockser_fd); - sockser_fd = -1; - return -1; - } - if (n != 1) - return -1; - return c; -} -- cgit v1.1