* Makefile.in: Add new file ser-tcp.c.
authorStu Grossman <grossman@cygnus>
Sat, 29 May 1993 01:33:36 +0000 (01:33 +0000)
committerStu Grossman <grossman@cygnus>
Sat, 29 May 1993 01:33:36 +0000 (01:33 +0000)
* defs.h (memcmp):  Add decl for memcmp to #ifndef MEM_FNS_DECLARED.
* findvar.c (write_register):  See if we are writing back the same
value that's already in the register.  If so, don't bother.
* remote.c (putpkt, getpkt):  Improve handling of communication
problems.
* ser-go32.c:  Prototype it to death.  Update serial_ops and add
dummy routines where appropriate.
* ser-tcp.c:  New module to implement serial I/O via TCP
connections.
* ser-unix.c:  Clean up getting/setting of tty state.  Get rid of
SERIAL_RESTORE, add SERIAL_{GET|SET}_TTY_STATE interfaces.
* serial.c:  Add start of support for connect command.
(serial_open):  Distinguish between tcp and local devices.
* serial.h (struct serial_ops):  Get rid of restore, add
get_tty_state and set_tty_state.  Define protoypes and macros for
this mess.
* gdbserver/remote-utils.c:  Add tcp support.  (readchar):  Do
some real buffering.  Handle error conditions gracefully.
* gdbserver/remote-inflow-sparc.c:  Update to remote-inflow.c
(Lynx), remove lots of cruft.

gdb/ChangeLog
gdb/Makefile.in
gdb/defs.h
gdb/gdbserver/remote-inflow-sparc.c
gdb/gdbserver/remote-utils.c
gdb/ser-go32.c
gdb/ser-tcp.c [new file with mode: 0644]
gdb/ser-unix.c
gdb/serial.c
gdb/serial.h

index 429b9ee1e6f288986386ff8d95fb433511cc9588..f517e43022d60108c12b05427e1e997de6e9c8f8 100644 (file)
@@ -1,3 +1,27 @@
+Fri May 28 17:18:05 1993  Stu Grossman  (grossman@cygnus.com)
+
+       * Makefile.in:  Add new file ser-tcp.c.
+       * defs.h (memcmp):  Add decl for memcmp to #ifndef MEM_FNS_DECLARED.
+       * findvar.c (write_register):  See if we are writing back the same
+       value that's already in the register.  If so, don't bother.
+       * remote.c (putpkt, getpkt):  Improve handling of communication
+       problems.
+       * ser-go32.c:  Prototype it to death.  Update serial_ops and add
+       dummy routines where appropriate.
+       * ser-tcp.c:  New module to implement serial I/O via TCP
+       connections.
+       * ser-unix.c:  Clean up getting/setting of tty state.  Get rid of
+       SERIAL_RESTORE, add SERIAL_{GET|SET}_TTY_STATE interfaces.
+       * serial.c:  Add start of support for connect command.
+       (serial_open):  Distinguish between tcp and local devices.
+       * serial.h (struct serial_ops):  Get rid of restore, add
+       get_tty_state and set_tty_state.  Define protoypes and macros for
+       this mess.
+       * gdbserver/remote-utils.c:  Add tcp support.  (readchar):  Do
+       some real buffering.  Handle error conditions gracefully.
+       * gdbserver/remote-inflow-sparc.c:  Update to remote-inflow.c
+       (Lynx), remove lots of cruft.
+
 Fri May 28 17:24:51 1993  david d `zoo' zuhn  (zoo at cirdan.cygnus.com)
 
        * printcmd.c (print_address_symbolic): turn this into an assigment
index f88588a7906c7c2698dcceec941abcd2bbe7a2bb..0e345214033ccf7fa4babe842cac94d062b9b9c7 100644 (file)
@@ -185,7 +185,7 @@ RUNTESTFLAGS=
 # part of libiberty) a POSIX interface.  But at least for now the
 # host-dependent makefile fragment might need to use something else
 # besides ser-unix.o
-SER_HARDWIRE=ser-unix.o
+SER_HARDWIRE=ser-unix.o ser-tcp.o
 
 # Host and target-dependent makefile fragments come in here.
 ####
@@ -304,7 +304,7 @@ SFILES = ${srcdir}/blockframe.c ${srcdir}/breakpoint.c ${srcdir}/buildsym.c \
   ${srcdir}/target.c ${srcdir}/typeprint.c ${srcdir}/utils.c \
   ${srcdir}/valarith.c \
   ${srcdir}/valops.c ${srcdir}/valprint.c ${srcdir}/values.c \
-  ${srcdir}/serial.c ${srcdir}/ser-unix.c
+  ${srcdir}/serial.c ${srcdir}/ser-unix.c ${srcdir}/ser-tcp.c
 
 # Files that are not source code, but need to go into gdb-$(VERSION).tar.Z.
 NONSRC = ${srcdir}/Makefile.in ${srcdir}/depend ${srcdir}/alldeps.mak \
index 3d03b9a232a5763b3858291673528851bc5e4a0a..031f2be14230cbf0d9f98ac9ebf304ef0c8da8f5 100644 (file)
@@ -434,20 +434,23 @@ enum val_prettyprint
 /* Defaults for system-wide constants (if not defined by xm.h, we fake it).  */
 
 #if !defined (UINT_MAX)
-#define UINT_MAX 0xffffffff
-#endif
-
-#if !defined (LONG_MAX)
-#define LONG_MAX 0x7fffffff
+#define        UINT_MAX ((unsigned int)(~0))           /* 0xFFFFFFFF for 32-bits */
 #endif
 
 #if !defined (INT_MAX)
-#define INT_MAX 0x7fffffff
+#define        INT_MAX (UINT_MAX >> 1)                 /* 0x7FFFFFFF for 32-bits */
 #endif
 
 #if !defined (INT_MIN)
-/* Two's complement, 32 bit.  */
-#define INT_MIN -0x80000000
+#define INT_MIN (-INT_MAX - 1)                 /* 0x80000000 for 32-bits */
+#endif
+
+#if !defined (ULONG_MAX)
+#define        ULONG_MAX ((unsigned long)(~0L))        /* 0xFFFFFFFF for 32-bits */
+#endif
+
+#if !defined (LONG_MAX)
+#define        LONG_MAX ((long)(ULONG_MAX >> 1))       /* 0x7FFFFFFF for 32-bits */
 #endif
 
 /* Number of bits in a char or unsigned char for the target machine.
@@ -722,10 +725,10 @@ qsort PARAMS ((void *base, size_t nmemb,          /* 4.10.5.2 */
 #ifndef        MEM_FNS_DECLARED        /* Some non-ANSI use void *, not char *.  */
 extern PTR
 memcpy PARAMS ((void *, const void *, size_t));                /* 4.11.2.1 */
-#endif
 
 extern int
 memcmp PARAMS ((const void *, const void *, size_t));  /* 4.11.4.1 */
+#endif
 
 extern char *
 strchr PARAMS ((const char *, int));                   /* 4.11.5.2 */
index 12b0b3aa8f4e104cfc90410ad365fa47a0897bd4..e71f56ca7ac6def0271b68600bfc7ebfdc6e243b 100644 (file)
@@ -1,9 +1,24 @@
-/* Low level interface to ptrace, for GDB when running under Unix.
-   Copyright (C) 1986, 1987 Free Software Foundation, Inc.
-*/
+/* Low level interface to ptrace, for the remote server for GDB.
+   Copyright (C) 1986, 1987, 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+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 of the License, 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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 #include "defs.h"
-#include "wait.h"
+#include "/usr/include/sys/wait.h"
 #include "frame.h"
 #include "inferior.h"
 /***************************
@@ -38,12 +53,6 @@ extern int errno;
 extern int inferior_pid;
 void error (), quit (), perror_with_name ();
 int query ();
-void supply_register (), write_register ();
-CORE_ADDR read_register ();
-
-/* Nonzero if we are debugging an attached outside process
-   rather than an inferior.  */
-
 
 /* Start an inferior process and returns its pid.
    ALLARGS is a vector of program-name and args.
@@ -101,52 +110,52 @@ kill_inferior ()
   /*************inferior_died ();****VK**************/
 }
 
-/* Resume execution of the inferior process.
-   If STEP is nonzero, single-step it.
-   If SIGNAL is nonzero, give it that signal.  */
+/* Wait for process, returns status */
 
 unsigned char
-myresume (step, signal, status)
-     int step;
-     int signal;
+mywait (status)
      char *status;
 {
   int pid;
-  WAITTYPE w;
+  union wait w;
 
-  errno = 0;
-  ptrace (step ? 9 : 7, inferior_pid, 1, signal);
-  if (errno)
-    perror_with_name ("ptrace");
   pid = wait (&w);
   if (pid != inferior_pid)
     perror_with_name ("wait");
 
-  fetch_inferior_registers (0);
-
   if (WIFEXITED (w))
     {
-      printf ("\nChild exited with retcode = %x \n", WEXITSTATUS (w));
+      fprintf (stderr, "\nChild exited with retcode = %x \n", WEXITSTATUS (w));
       *status = 'E';
       return ((unsigned char) WEXITSTATUS (w));
     }
   else if (!WIFSTOPPED (w))
     {
-      printf ("\nChild terminated with signal = %x \n", WTERMSIG (w));
+      fprintf (stderr, "\nChild terminated with signal = %x \n", WTERMSIG (w));
       *status = 'T';
       return ((unsigned char) WTERMSIG (w));
     }
-  else
-    {
-      printf ("\nChild stopped with signal = %x \n", WSTOPSIG (w));
-      *status = 'S';
-      return ((unsigned char) WSTOPSIG (w));
-    }
+
+  fetch_inferior_registers (0);
+
+  *status = 'S';
+  return ((unsigned char) WSTOPSIG (w));
 }
 
-#define        INT_REGS        1
-#define        STACK_REGS      2
-#define        FP_REGS         4
+/* Resume execution of the inferior process.
+   If STEP is nonzero, single-step it.
+   If SIGNAL is nonzero, give it that signal.  */
+
+void
+myresume (step, signal)
+     int step;
+     int signal;
+{
+  errno = 0;
+  ptrace (step ? PTRACE_SINGLESTEP : PTRACE_CONT, inferior_pid, 1, signal);
+  if (errno)
+    perror_with_name ("ptrace");
+}
 
 /* Fetch one or more registers from the inferior.  REGNO == -1 to get
    them all.  We actually fetch more than requested, when convenient,
@@ -234,63 +243,6 @@ store_inferior_registers (ignored)
     perror("ptrace_setfpregs");
 }
 
-#if 0
-void
-fetch_inferior_registers ()
-{
-  struct regs inferior_registers;
-  struct fp_status inferior_fp_registers;
-  extern char registers[];
-
-  ptrace (PTRACE_GETREGS, inferior_pid, &inferior_registers);
-  if (errno)
-    perror_with_name ("ptrace");
-  /**********debugging begin **********/
-  print_some_registers (&inferior_registers);
-  /**********debugging end **********/
-  ptrace (PTRACE_GETFPREGS, inferior_pid, &inferior_fp_registers);
-  if (errno)
-    perror_with_name ("ptrace");
-
-  bcopy (&inferior_registers, registers, 16 * 4);
-  bcopy (&inferior_fp_registers, &registers[REGISTER_BYTE (FP0_REGNUM)],
-        sizeof inferior_fp_registers.fpu_regs);
-  *(int *) &registers[REGISTER_BYTE (PS_REGNUM)] = inferior_registers.r_ps;
-  *(int *) &registers[REGISTER_BYTE (PC_REGNUM)] = inferior_registers.r_pc;
-  bcopy (&inferior_fp_registers.fpu_flags,
-        &registers[REGISTER_BYTE (FPC_REGNUM)],
-      sizeof inferior_fp_registers - sizeof inferior_fp_registers.fpu_regs);
-}
-
-/* Store our register values back into the inferior.
-   If REGNO is -1, do this for all registers.
-   Otherwise, REGNO specifies which register (so we can save time).  */
-
-store_inferior_registers (regno)
-     int regno;
-{
-  struct regs inferior_registers;
-  struct fp_status inferior_fp_registers;
-  extern char registers[];
-
-  bcopy (registers, &inferior_registers, 16 * 4);
-  bcopy (&registers[REGISTER_BYTE (FP0_REGNUM)], &inferior_fp_registers,
-        sizeof inferior_fp_registers.fps_regs);
-  inferior_registers.r_ps = *(int *) &registers[REGISTER_BYTE (PS_REGNUM)];
-  inferior_registers.r_pc = *(int *) &registers[REGISTER_BYTE (PC_REGNUM)];
-  bcopy (&registers[REGISTER_BYTE (FPC_REGNUM)],
-        &inferior_fp_registers.fps_control,
-      sizeof inferior_fp_registers - sizeof inferior_fp_registers.fps_regs);
-
-  ptrace (PTRACE_SETREGS, inferior_pid, &inferior_registers);
-  if (errno)
-    perror_with_name ("ptrace");
-  ptrace (PTRACE_SETFPREGS, inferior_pid, &inferior_fp_registers);
-  if (errno)
-    perror_with_name ("ptrace");
-}
-#endif /* 0 */
-
 /* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory
    in the NEW_SUN_PTRACE case.
    It ought to be straightforward.  But it appears that writing did
@@ -373,79 +325,14 @@ write_inferior_memory (memaddr, myaddr, len)
   return 0;
 }
 \f
-void
-try_writing_regs_command ()
-{
-  register int i;
-  register int val;
-
-  if (inferior_pid == 0)
-    error ("There is no inferior process now.");
-
-  fetch_inferior_registers (0);
-  for (i = 0; i < 18; i++)
-    {
-      QUIT;
-      errno = 0;
-      val = read_register (i);
-      write_register (i, val);
-      if (errno == 0)
-       {
-         printf (" Succeeded with register %d; value 0x%x (%d).\n",
-                 i, val, val);
-       }
-      else
-       printf (" Failed with register %d.\n", i);
-    }
-}
-
 void
 initialize ()
 {
-
   inferior_pid = 0;
-
-
-}
-
-
-/* Return the contents of register REGNO,
-   regarding it as an integer.  */
-
-CORE_ADDR
-read_register (regno)
-     int regno;
-{
-  /* This loses when REGISTER_RAW_SIZE (regno) != sizeof (int) */
-  return *(int *) &registers[REGISTER_BYTE (regno)];
-}
-
-/* Store VALUE in the register number REGNO, regarded as an integer.  */
-
-void
-write_register (regno, val)
-     int regno, val;
-{
-  /* This loses when REGISTER_RAW_SIZE (regno) != sizeof (int) */
-  *(int *) &registers[REGISTER_BYTE (regno)] = val;
-
-  if (have_inferior_p ())
-    store_inferior_registers (regno);
 }
 
-
 int
 have_inferior_p ()
 {
   return inferior_pid != 0;
 }
-
-print_some_registers (regs)
-     int regs[];
-{
-  register int i;
-  for (i = 0; i < 18; i++)
-    {
-      printf ("reg[%d] = %x\n", i, regs[i]);
-    }
-}
index 2781ac5e35c5818f106be8c1797699db20e287ea..a16ba0aee179c858d9ea952079c46e7b0bcd4d2f 100644 (file)
@@ -25,10 +25,15 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include <a.out.h>
 #include <sys/file.h>
 #include <sgtty.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/tcp.h>
+#include <sys/time.h>
 
 extern int remote_desc;
 extern int remote_debugging;
-extern int kiodebug;
 
 void remote_open ();
 void remote_send ();
@@ -53,13 +58,56 @@ remote_open (name, from_tty)
 
   remote_debugging = 0;
 
-  remote_desc = open (name, O_RDWR);
-  if (remote_desc < 0)
-    perror_with_name ("Could not open remote device");
+  if (!strchr (name, ':'))
+    {
+      remote_desc = open (name, O_RDWR);
+      if (remote_desc < 0)
+       perror_with_name ("Could not open remote device");
+
+      ioctl (remote_desc, TIOCGETP, &sg);
+      sg.sg_flags = RAW;
+      ioctl (remote_desc, TIOCSETP, &sg);
+    }
+  else
+    {
+      char *port_str;
+      int port;
+      struct sockaddr_in sockaddr;
+      int tmp;
+
+      port_str = strchr (name, ':');
+
+      port = atoi (port_str + 1);
+
+      remote_desc = socket (PF_INET, SOCK_STREAM, 0);
+      if (remote_desc < 0)
+       perror_with_name ("Can't open socket");
+
+      /* Allow rapid reuse of this port. */
+      tmp = 1;
+      setsockopt (remote_desc, SOL_SOCKET, SO_REUSEADDR, (char *)&tmp,
+                 sizeof(tmp));
+
+      /* Enable TCP keep alive process. */
+      tmp = 1;
+      setsockopt (remote_desc, SOL_SOCKET, SO_KEEPALIVE, (char *)&tmp, sizeof(tmp));
+
+      sockaddr.sin_family = PF_INET;
+      sockaddr.sin_port = htons(port);
+      sockaddr.sin_addr.s_addr = INADDR_ANY;
 
-  ioctl (remote_desc, TIOCGETP, &sg);
-  sg.sg_flags = RAW;
-  ioctl (remote_desc, TIOCSETP, &sg);
+      if (bind (remote_desc, &sockaddr, sizeof (sockaddr))
+         || listen (remote_desc, 1))
+       perror_with_name ("Can't bind address");
+
+      tmp = sizeof (sockaddr);
+      remote_desc = accept (remote_desc, &sockaddr, &tmp);
+      if (remote_desc == -1)
+       perror_with_name ("Accept failed");
+
+      tmp = 1;
+      setsockopt (remote_desc, 6, TCP_NODELAY, (char *)&tmp, sizeof(tmp));
+    }
 
   fprintf (stderr, "Remote debugging using %s\n", name);
   remote_debugging = 1;
@@ -148,9 +196,24 @@ putpkt (buf)
 static int
 readchar ()
 {
-  char buf[1];
-  while (read (remote_desc, buf, 1) != 1);
-  return buf[0] & 0x7f;
+  static char buf[BUFSIZ];
+  static int bufcnt = 0;
+  static char *bufp;
+
+  if (bufcnt-- > 0)
+    return *bufp++ & 0x7f;
+
+  bufcnt = read (remote_desc, buf, sizeof (buf));
+
+  if (bufcnt <= 0)
+    {
+      perror ("readchar");
+      fatal ("read error, quitting");
+    }
+
+  bufp = buf;
+  bufcnt--;
+  return *bufp++ & 0x7f;
 }
 
 /* Read a packet from the remote machine, with error checking,
@@ -161,12 +224,13 @@ getpkt (buf)
      char *buf;
 {
   char *bp;
-  unsigned char csum, c, c1, c2;
-  extern kiodebug;
+  unsigned char csum, c1, c2;
+  int c;
 
   while (1)
     {
       csum = 0;
+
       while ((c = readchar ()) != '$');
 
       bp = buf;
index 1d930a884804d3cc190844b5f6b4ab4cf2e37ffc..c9770a93b4659dcca826f975b61538024c065fa5 100644 (file)
@@ -21,6 +21,33 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "serial.h"
 #include <sys/dos.h>
 
+/* This is unused for now.  We just return a placeholder. */
+struct go32_ttystate
+{
+  int bogus;
+};
+
+static int go32_open PARAMS ((serial_t scb, const char *name));
+static void go32_raw PARAMS ((serial_t scb));
+static int wait_for PARAMS ((serial_t scb, int timeout));
+static int go32_readchar PARAMS ((serial_t scb, int timeout));
+static int rate_to_code PARAMS ((int rate));
+static int go32_setbaudrate PARAMS ((serial_t scb, int rate));
+static int go32_write PARAMS ((serial_t scb, const char *str, int len));
+static void go32_restore PARAMS ((serial_t scb));
+static void go32_close PARAMS ((serial_t scb));
+serial_ttystate go32_get_tty_state PARAMS ((serial_t scb));
+static int go32_set_tty_state PARAMS ((serial_t scb, serial_ttystate state));
+static int strncasecmp PARAMS ((char *str1, char *str2, int len));
+static char *aptr PARAMS ((short p));
+static ASYNC_STRUCT *getivec PARAMS ((int which));
+static int dos_async_init PARAMS ((int port));
+static void dos_async_tx PARAMS ((const char c));
+static int dos_async_ready PARAMS (());
+static int dos_async_rx PARAMS (());
+static int dosasync_read PARAMS ((int fd, char *buf, int len, int timeout));
+static int dosasync_write PARAMS ((int fd, const char *buf, int len, int timeout));
+
 #define SIGNATURE 0x4154
 #define VERSION 1
 #define OFFSET 0x104
@@ -260,6 +287,30 @@ go32_readchar (scb, timeout)
     return SERIAL_TIMEOUT;
 }
 
+/* go32_{get set}_tty_state() are both dummys to fill out the function
+   vector.  Someday, they may do something real... */
+
+static serial_ttystate
+go32_get_tty_state(scb)
+     serial_t scb;
+{
+  struct go32_ttystate *state;
+
+  state = (struct go32_ttystate *)xmalloc(sizeof *state);
+
+  return (serial_ttystate)state;
+}
+
+static int
+go32_set_tty_state(scb, ttystate)
+     serial_t scb;
+     serial_ttystate ttystate;
+{
+  struct go32_ttystate *state;
+
+  return 0;
+}
+
 static int
 go32_setbaudrate (scb, rate)
      serial_t scb;
@@ -284,12 +335,6 @@ go32_close ()
 {
 }
 
-static void
-go32_restore (scb)
-     serial_t scb;
-{
-}
-
 static struct serial_ops go32_ops =
 {
   "hardwire",
@@ -299,7 +344,8 @@ static struct serial_ops go32_ops =
   go32_readchar,
   go32_write,
   go32_raw,
-  go32_restore,
+  go32_get_tty_state,
+  go32_set_tty_state,
   go32_setbaudrate
 };
 
diff --git a/gdb/ser-tcp.c b/gdb/ser-tcp.c
new file mode 100644 (file)
index 0000000..4f4fcdb
--- /dev/null
@@ -0,0 +1,270 @@
+/* Serial interface for raw TCP connections on Un*x like systems
+   Copyright 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+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 of the License, 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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include "defs.h"
+#include "serial.h"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <netinet/tcp.h>
+#include "signals.h"
+
+struct tcp_ttystate
+{
+  int bogus;
+};
+
+static int tcp_open PARAMS ((serial_t scb, const char *name));
+static void tcp_raw PARAMS ((serial_t scb));
+static int wait_for PARAMS ((serial_t scb, int timeout));
+static int tcp_readchar PARAMS ((serial_t scb, int timeout));
+static int tcp_setbaudrate PARAMS ((serial_t scb, int rate));
+static int tcp_write PARAMS ((serial_t scb, const char *str, int len));
+static void tcp_restore PARAMS ((serial_t scb));
+static void tcp_close PARAMS ((serial_t scb));
+static serial_ttystate tcp_get_tty_state PARAMS ((serial_t scb));
+static int tcp_set_tty_state PARAMS ((serial_t scb, serial_ttystate state));
+
+/* Open up a raw tcp socket */
+
+static int
+tcp_open(scb, name)
+     serial_t scb;
+     const char *name;
+{
+  char *port_str;
+  int port;
+  struct hostent *hostent;
+  struct sockaddr_in sockaddr;
+  int tmp;
+  char hostname[100];
+
+  port_str = strchr (name, ':');
+
+  if (!port_str)
+    error ("tcp_open: No colon in host name!"); /* Shouldn't ever happen */
+
+  tmp = min(port_str - name + 1, sizeof hostname);
+  strncpy (hostname, name, tmp - 1); /* Don't want colon */
+  port = atoi (port_str + 1);
+
+  hostent = gethostbyname (hostname);
+
+  if (!hostent)
+    {
+      errno = ENOENT;
+      return -1;
+    }
+
+  scb->fd = socket (PF_INET, SOCK_STREAM, 0);
+  if (scb->fd < 0)
+    return -1;
+
+  /* Allow rapid reuse of this port. */
+  tmp = 1;
+  setsockopt (scb->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&tmp, sizeof(tmp));
+
+  /* Enable TCP keep alive process. */
+  tmp = 1;
+  setsockopt (scb->fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&tmp, sizeof(tmp));
+
+  sockaddr.sin_family = PF_INET;
+  sockaddr.sin_port = htons(port);
+  memcpy (&sockaddr.sin_addr.s_addr, hostent->h_addr,
+         sizeof (struct in_addr));
+
+  if (connect(scb->fd, &sockaddr, sizeof(sockaddr)))
+    {
+      close(scb->fd);
+      return -1;
+    }
+
+  tmp = 1;
+  if (setsockopt (scb->fd, 6, TCP_NODELAY, (char *)&tmp, sizeof(tmp)))
+    return -1;
+
+  signal(SIGPIPE, SIG_IGN);    /* If we don't do this, then GDB simply exits
+                                  when the remote side dies.  */
+
+  return 0;
+}
+
+static serial_ttystate
+tcp_get_tty_state(scb)
+     serial_t scb;
+{
+  struct tcp_ttystate *state;
+
+  state = (struct tcp_ttystate *)xmalloc(sizeof *state);
+
+  return (serial_ttystate)state;
+}
+
+static int
+tcp_set_tty_state(scb, ttystate)
+     serial_t scb;
+     serial_ttystate ttystate;
+{
+  struct tcp_ttystate *state;
+
+  state = (struct tcp_ttystate *)ttystate;
+
+  return 0;
+}
+
+static void
+tcp_raw(scb)
+     serial_t scb;
+{
+  return;                      /* Always in raw mode */
+}
+
+/* Wait for input on scb, with timeout seconds.  Returns 0 on success,
+   otherwise SERIAL_TIMEOUT or SERIAL_ERROR.
+
+   For termio{s}, we actually just setup VTIME if necessary, and let the
+   timeout occur in the read() in tcp_read().
+ */
+
+static int
+wait_for(scb, timeout)
+     serial_t scb;
+     int timeout;
+{
+  int numfds;
+  struct timeval tv;
+  fd_set readfds;
+
+  FD_ZERO (&readfds);
+
+  tv.tv_sec = timeout;
+  tv.tv_usec = 0;
+
+  FD_SET(scb->fd, &readfds);
+
+  if (timeout >= 0)
+    numfds = select(scb->fd+1, &readfds, 0, 0, &tv);
+  else
+    numfds = select(scb->fd+1, &readfds, 0, 0, 0);
+
+  if (numfds <= 0)
+    if (numfds == 0)
+      return SERIAL_TIMEOUT;
+    else
+      return SERIAL_ERROR;     /* Got an error from select or poll */
+
+  return 0;
+}
+
+/* Read a character with user-specified timeout.  TIMEOUT is number of seconds
+   to wait, or -1 to wait forever.  Use timeout of 0 to effect a poll.  Returns
+   char if successful.  Returns -2 if timeout expired, EOF if line dropped
+   dead, or -3 for any other error (see errno in that case). */
+
+static int
+tcp_readchar(scb, timeout)
+     serial_t scb;
+     int timeout;
+{
+  int status;
+
+  if (scb->bufcnt-- > 0)
+    return *scb->bufp++;
+
+  status = wait_for(scb, timeout);
+
+  if (status < 0)
+    return status;
+
+  scb->bufcnt = read(scb->fd, scb->buf, BUFSIZ);
+
+  if (scb->bufcnt <= 0)
+    if (scb->bufcnt == 0)
+      return SERIAL_TIMEOUT;   /* 0 chars means timeout [may need to
+                                  distinguish between EOF & timeouts
+                                  someday] */
+    else
+      return SERIAL_ERROR;     /* Got an error from read */
+
+  scb->bufcnt--;
+  scb->bufp = scb->buf;
+  return *scb->bufp++;
+}
+
+static int
+tcp_setbaudrate(scb, rate)
+     serial_t scb;
+     int rate;
+{
+  return 0;                    /* Never fails! */
+}
+
+static int
+tcp_write(scb, str, len)
+     serial_t scb;
+     const char *str;
+     int len;
+{
+  int cc;
+
+  while (len > 0)
+    {
+      cc = write(scb->fd, str, len);
+
+      if (cc < 0)
+       return 1;
+      len -= cc;
+      str += cc;
+    }
+  return 0;
+}
+
+static void
+tcp_close(scb)
+     serial_t scb;
+{
+  if (scb->fd < 0)
+    return;
+
+  close(scb->fd);
+  scb->fd = -1;
+}
+
+static struct serial_ops tcp_ops =
+{
+  "tcp",
+  0,
+  tcp_open,
+  tcp_close,
+  tcp_readchar,
+  tcp_write,
+  tcp_raw,
+  tcp_get_tty_state,
+  tcp_set_tty_state,
+  tcp_setbaudrate,
+};
+
+void
+_initialize_ser_tcp ()
+{
+  serial_add_interface (&tcp_ops);
+}
index 5f1622dfa2efe61487db9000e8d6399d299f1651..6c142e75c82acc25dd34b7c4eaa2130e2316cecf 100644 (file)
@@ -30,12 +30,29 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #ifdef HAVE_TERMIOS
 #include <termios.h>
 #include <unistd.h>
+
+struct hardwire_ttystate
+{
+  struct termios termios;
+};
 #endif
+
 #ifdef HAVE_TERMIO
 #include <termio.h>
+
+struct hardwire_ttystate
+{
+  struct termio termio;
+};
 #endif
+
 #ifdef HAVE_SGTTY
 #include <sgtty.h>
+
+struct hardwire_ttystate
+{
+  struct sgttyb sgttyb;
+};
 #endif
 
 static int hardwire_open PARAMS ((serial_t scb, const char *name));
@@ -47,6 +64,10 @@ static int hardwire_setbaudrate PARAMS ((serial_t scb, int rate));
 static int hardwire_write PARAMS ((serial_t scb, const char *str, int len));
 static void hardwire_restore PARAMS ((serial_t scb));
 static void hardwire_close PARAMS ((serial_t scb));
+static int get_tty_state PARAMS ((serial_t scb, struct hardwire_ttystate *state));
+static int set_tty_state PARAMS ((serial_t scb, struct hardwire_ttystate *state));
+static serial_ttystate hardwire_get_tty_state PARAMS ((serial_t scb));
+static int hardwire_set_tty_state PARAMS ((serial_t scb, serial_ttystate state));
 
 /* Open up a real live device for serial I/O */
 
@@ -62,68 +83,108 @@ hardwire_open(scb, name)
   return 0;
 }
 
-static void
-hardwire_raw(scb)
+static int
+get_tty_state(scb, state)
      serial_t scb;
+     struct hardwire_ttystate *state;
 {
 #ifdef HAVE_TERMIOS
-  struct termios termios;
+  return tcgetattr(scb->fd, &state->termios);
+#endif
 
-  if (tcgetattr(scb->fd, &termios))
-    {
-      fprintf(stderr, "tcgetattr failed: %s\n", safe_strerror(errno));
-    }
+#ifdef HAVE_TERMIO
+  return ioctl (scb->fd, TCGETA, &state->termio);
+#endif
 
-  termios.c_iflag = 0;
-  termios.c_oflag = 0;
-  termios.c_lflag = 0;
-  termios.c_cflag &= ~(CSIZE|PARENB);
-  termios.c_cflag |= CS8;
-  termios.c_cc[VMIN] = 0;
-  termios.c_cc[VTIME] = 0;
+#ifdef HAVE_SGTTY
+  return ioctl (scb->fd, TIOCGETP, &state->sgttyb);
+#endif
+}
 
-  if (tcsetattr(scb->fd, TCSANOW, &termios))
-    {
-      fprintf(stderr, "tcsetattr failed: %s\n", safe_strerror(errno));
-    }
+static int
+set_tty_state(scb, state)
+     serial_t scb;
+     struct hardwire_ttystate *state;
+{
+  int err;
+
+#ifdef HAVE_TERMIOS
+  return tcsetattr(scb->fd, TCSANOW, &state->termios);
 #endif
 
 #ifdef HAVE_TERMIO
-  struct termio termio;
+  return ioctl (scb->fd, TCSETA, &state->termio);
+#endif
 
-  if (ioctl (scb->fd, TCGETA, &termio))
-    {
-      fprintf(stderr, "TCGETA failed: %s\n", safe_strerror(errno));
-    }
+#ifdef HAVE_SGTTY
+  return ioctl (scb->fd, TIOCSETP, &state->sgttyb);
+#endif
+}
 
-  termio.c_iflag = 0;
-  termio.c_oflag = 0;
-  termio.c_lflag = 0;
-  termio.c_cflag &= ~(CSIZE|PARENB);
-  termio.c_cflag |= CS8;
-  termio.c_cc[VMIN] = 0;
-  termio.c_cc[VTIME] = 0;
+static serial_ttystate
+hardwire_get_tty_state(scb)
+     serial_t scb;
+{
+  struct hardwire_ttystate *state;
 
-  if (ioctl (scb->fd, TCSETA, &termio))
-    {
-      fprintf(stderr, "TCSETA failed: %s\n", safe_strerror(errno));
-    }
-#endif
+  state = (struct hardwire_ttystate *)xmalloc(sizeof *state);
 
-#ifdef HAVE_SGTTY
-  struct sgttyb sgttyb;
+  if (get_tty_state(scb, state))
+    return NULL;
 
-  if (ioctl (scb->fd, TIOCGETP, &sgttyb))
-    fprintf(stderr, "TIOCGETP failed: %s\n", safe_strerror(errno));
+  return (serial_ttystate)state;
+}
 
-  sgttyb.sg_flags |= RAW | ANYP;
-  sgttyb.sg_flags &= ~(CBREAK | ECHO);
+static int
+hardwire_set_tty_state(scb, ttystate)
+     serial_t scb;
+     serial_ttystate ttystate;
+{
+  struct hardwire_ttystate *state;
 
-  if (ioctl (scb->fd, TIOCSETP, &sgttyb))
-    fprintf(stderr, "TIOCSETP failed: %s\n", safe_strerror(errno));
+  state = (struct hardwire_ttystate *)ttystate;
+
+  return set_tty_state(scb, state);
+}
+
+static void
+hardwire_raw(scb)
+     serial_t scb;
+{
+  struct hardwire_ttystate state;
+
+  if (get_tty_state(scb, &state))
+    fprintf(stderr, "get_tty_state failed: %s\n", safe_strerror(errno));
+
+#ifdef HAVE_TERMIOS
+  state.termios.c_iflag = 0;
+  state.termios.c_oflag = 0;
+  state.termios.c_lflag = 0;
+  state.termios.c_cflag &= ~(CSIZE|PARENB);
+  state.termios.c_cflag |= CS8;
+  state.termios.c_cc[VMIN] = 0;
+  state.termios.c_cc[VTIME] = 0;
+#endif
+
+#ifdef HAVE_TERMIO
+  state.termio.c_iflag = 0;
+  state.termio.c_oflag = 0;
+  state.termio.c_lflag = 0;
+  state.termio.c_cflag &= ~(CSIZE|PARENB);
+  state.termio.c_cflag |= CS8;
+  state.termio.c_cc[VMIN] = 0;
+  state.termio.c_cc[VTIME] = 0;
+#endif
+
+#ifdef HAVE_SGTTY
+  state.sgttyb.sg_flags |= RAW | ANYP;
+  state.sgttyb.sg_flags &= ~(CBREAK | ECHO);
 #endif
 
   scb->current_timeout = 0;
+
+  if (set_tty_state (scb, &state))
+    fprintf(stderr, "set_tty_state failed: %s\n", safe_strerror(errno));
 }
 
 /* Wait for input on scb, with timeout seconds.  Returns 0 on success,
@@ -171,31 +232,24 @@ wait_for(scb, timeout)
     return 0;
 
   {
-#ifdef HAVE_TERMIOS
-    struct termios termios;
-
-    if (tcgetattr(scb->fd, &termios))
-      fprintf(stderr, "wait_for() tcgetattr failed: %s\n", safe_strerror(errno));
+    struct hardwire_ttystate state;
 
-  termios.c_cc[VTIME] = timeout * 10;
+    if (get_tty_state(scb, &state))
+      fprintf(stderr, "get_tty_state failed: %s\n", safe_strerror(errno));
 
-  if (tcsetattr(scb->fd, TCSANOW, &termios))
-    fprintf(stderr, "wait_for() tcsetattr failed: %s\n", safe_strerror(errno));
-#endif /* HAVE_TERMIOS */
+#ifdef HAVE_TERMIOS
+    state.termios.c_cc[VTIME] = timeout * 10;
+#endif
 
 #ifdef HAVE_TERMIO
-  struct termio termio;
-
-  if (ioctl (scb->fd, TCGETA, &termio))
-    fprintf(stderr, "wait_for() TCGETA failed: %s\n", safe_strerror(errno));
+    state.termio.c_cc[VTIME] = timeout * 10;
+#endif
 
-  termio.c_cc[VTIME] = timeout * 10;
+    scb->current_timeout = timeout;
 
-  if (ioctl (scb->fd, TCSETA, &termio))
-      fprintf(stderr, "TCSETA failed: %s\n", safe_strerror(errno));
-#endif /* HAVE_TERMIO */
+    if (set_tty_state (scb, &state))
+      fprintf(stderr, "set_tty_state failed: %s\n", safe_strerror(errno));
 
-    scb->current_timeout = timeout;
     return 0;
   }
 #endif /* HAVE_TERMIO || HAVE_TERMIOS */
@@ -290,49 +344,31 @@ hardwire_setbaudrate(scb, rate)
      serial_t scb;
      int rate;
 {
-#ifdef HAVE_TERMIOS
-  struct termios termios;
+  struct hardwire_ttystate state;
 
-  if (tcgetattr (scb->fd, &termios))
+  if (get_tty_state(scb, &state))
     return -1;
 
-  cfsetospeed (&termios, rate_to_code (rate));
-  cfsetispeed (&termios, rate_to_code (rate));
-
-  if (tcsetattr (scb->fd, TCSANOW, &termios))
-    return -1;
+#ifdef HAVE_TERMIOS
+  cfsetospeed (&state.termios, rate_to_code (rate));
+  cfsetispeed (&state.termios, rate_to_code (rate));
 #endif
 
 #ifdef HAVE_TERMIO
-  struct termio termio;
-
-  if (ioctl (scb->fd, TCGETA, &termio))
-    return -1;
-
 #ifndef CIBAUD
 #define CIBAUD CBAUD
 #endif
 
-  termio.c_cflag &= ~(CBAUD | CIBAUD);
-  termio.c_cflag |= rate_to_code (rate);
-
-  if (ioctl (scb->fd, TCSETA, &termio))
-    return -1;
+  state.termio.c_cflag &= ~(CBAUD | CIBAUD);
+  state.termio.c_cflag |= rate_to_code (rate);
 #endif
 
 #ifdef HAVE_SGTTY
-  struct sgttyb sgttyb;
-
-  if (ioctl (scb->fd, TIOCGETP, &sgttyb))
-    return -1;
-
-  sgttyb.sg_ispeed = rate_to_code (rate);
-  sgttyb.sg_ospeed = rate_to_code (rate);
-
-  if (ioctl (scb->fd, TIOCSETP, &sgttyb))
-    return -1;
+  state.sgttyb.sg_ispeed = rate_to_code (rate);
+  state.sgttyb.sg_ospeed = rate_to_code (rate);
 #endif
-  return 0;
+
+  return set_tty_state (scb, &state);
 }
 
 static int
@@ -355,12 +391,6 @@ hardwire_write(scb, str, len)
   return 0;
 }
 
-static void
-hardwire_restore(scb)
-     serial_t scb;
-{
-}
-
 static void
 hardwire_close(scb)
      serial_t scb;
@@ -381,8 +411,9 @@ static struct serial_ops hardwire_ops =
   hardwire_readchar,
   hardwire_write,
   hardwire_raw,
-  hardwire_restore,
-  hardwire_setbaudrate
+  hardwire_get_tty_state,
+  hardwire_set_tty_state,
+  hardwire_setbaudrate,
 };
 
 void
index e4c8cbf10b70c51c9b2a7ec10aab7ab128c46e4d..e5ccf1d18e1fc38ad8dc10938f3df94b1e0a921c 100644 (file)
@@ -20,10 +20,14 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "defs.h"
 #include "serial.h"
 
-/* Open up a device or a network socket, depending upon the syntax of NAME. */
+/* Linked list of serial I/O handlers */
 
 static struct serial_ops *serial_ops_list = NULL;
 
+/* This is the last serial stream opened.  Used by connect command. */
+
+static serial_t last_serial_opened = NULL;
+
 static struct serial_ops *
 serial_interface_lookup (name)
      char *name;
@@ -45,6 +49,8 @@ serial_add_interface(optable)
   serial_ops_list = optable;
 }
 
+/* Open up a device or a network socket, depending upon the syntax of NAME. */
+
 serial_t
 serial_open(name)
      const char *name;
@@ -52,7 +58,10 @@ serial_open(name)
   serial_t scb;
   struct serial_ops *ops;
 
-  ops = serial_interface_lookup ("hardwire");
+  if (strchr (name, ':'))
+    ops = serial_interface_lookup ("tcp");
+  else
+    ops = serial_interface_lookup ("hardwire");
 
   if (!ops)
     return NULL;
@@ -70,6 +79,34 @@ serial_open(name)
       return NULL;
     }
 
+  last_serial_opened = scb;
+
+  return scb;
+}
+
+serial_t
+serial_fdopen(fd)
+     const int fd;
+{
+  serial_t scb;
+  struct serial_ops *ops;
+
+  ops = serial_interface_lookup ("hardwire");
+
+  if (!ops)
+    return NULL;
+
+  scb = (serial_t)xmalloc (sizeof (struct _serial_t));
+
+  scb->ops = ops;
+
+  scb->bufcnt = 0;
+  scb->bufp = scb->buf;
+
+  scb->fd = fd;
+
+  last_serial_opened = scb;
+
   return scb;
 }
 
@@ -77,21 +114,28 @@ void
 serial_close(scb)
      serial_t scb;
 {
+  last_serial_opened = NULL;
+
   scb->ops->close(scb);
 
   free(scb);
 }
 
 #if 0
+
 /* Connect the user directly to the remote system.  This command acts just like
    the 'cu' or 'tip' command.  Use <CR>~. or <CR>~^D to break out.  */
 
+static serial_t tty_desc;              /* Controlling terminal */
+
 static void
 cleanup_tty(ttystate)
-     struct ttystate ttystate;
+     serial_ttystate ttystate;
 {
-  printf("\r\n[Exiting connect mode]\r\n");
-  serial_restore(0, &ttystate);
+  printf ("\r\n[Exiting connect mode]\r\n");
+  SERIAL_SET_TTY_STATE (tty_desc, ttystate);
+  free (ttystate);
+  SERIAL_CLOSE (tty_desc);
 }
 
 static void
@@ -99,87 +143,94 @@ connect_command (args, fromtty)
      char      *args;
      int       fromtty;
 {
-  fd_set readfds;
-  int numfds;
   int c;
   char cur_esc = 0;
-  static struct ttystate ttystate;
+  serial_ttystate ttystate;
+  serial_t port_desc;          /* TTY port */
 
   dont_repeat();
 
-  if (desc < 0)
-    error("target not open.");
-  
   if (args)
-    fprintf("This command takes no args.  They have been ignored.\n");
+    fprintf(stderr, "This command takes no args.  They have been ignored.\n");
        
   printf("[Entering connect mode.  Use ~. or ~^D to escape]\n");
 
-  serial_raw(0, &ttystate);
+  tty_desc = SERIAL_FDOPEN (0);
+  port_desc = last_serial_opened;
 
-  make_cleanup(cleanup_tty, &ttystate);
+  ttystate = SERIAL_GET_TTY_STATE (tty_desc);
 
-  FD_ZERO(&readfds);
+  SERIAL_RAW (tty_desc);
+  SERIAL_RAW (port_desc);
+
+  make_cleanup (cleanup_tty, ttystate);
 
   while (1)
     {
-      do
-       {
-         FD_SET(0, &readfds);
-         FD_SET(desc, &readfds);
-         numfds = select(sizeof(readfds)*8, &readfds, 0, 0, 0);
-       }
-      while (numfds == 0);
+      int mask;
 
-      if (numfds < 0)
-       perror_with_name("select");
+      mask = SERIAL_WAIT_2 (tty_desc, port_desc, -1);
 
-      if (FD_ISSET(0, &readfds))
-       {                       /* tty input, send to stdebug */
+      if (mask & 2)
+       {                       /* tty input */
          char cx;
 
-         c = serial_readchar(-1);
-         if (c < 0)
-           perror_with_name("connect");
-
-         cx = c;
-         serial_write(&cx, 1);
-         switch (cur_esc)
+         while (1)
            {
-           case 0:
-             if (c == '\r')
-               cur_esc = c;
-             break;
-           case '\r':
-             if (c == '~')
-               cur_esc = c;
-             else
-               cur_esc = 0;
-             break;
-           case '~':
-             if (c == '.' || c == '\004')
-               return;
-             else
-               cur_esc = 0;
+             c = SERIAL_READCHAR(tty_desc, 0);
+
+             if (c == SERIAL_TIMEOUT)
+                 break;
+
+             if (c < 0)
+               perror_with_name("connect");
+
+             cx = c;
+             SERIAL_WRITE(port_desc, &cx, 1);
+
+             switch (cur_esc)
+               {
+               case 0:
+                 if (c == '\r')
+                   cur_esc = c;
+                 break;
+               case '\r':
+                 if (c == '~')
+                   cur_esc = c;
+                 else
+                   cur_esc = 0;
+                 break;
+               case '~':
+                 if (c == '.' || c == '\004')
+                   return;
+                 else
+                   cur_esc = 0;
+               }
            }
        }
 
-      if (FD_ISSET(desc, &readfds))
-       {
+      if (mask & 1)
+       {                       /* Port input */
+         char cx;
+
          while (1)
            {
-             c = serial_readchar(-1);
+             c = SERIAL_READCHAR(port_desc, 0);
+
+             if (c == SERIAL_TIMEOUT)
+                 break;
+
              if (c < 0)
-               break;
-             putchar(c);
+               perror_with_name("connect");
+
+             cx = c;
+
+             SERIAL_WRITE(tty_desc, &cx, 1);
            }
-         fflush(stdout);
        }
     }
 }
-#endif
 
-#if 0
 void
 _initialize_serial ()
 {
@@ -187,4 +238,4 @@ _initialize_serial ()
           "Connect the terminal directly up to the command monitor.\n\
 Use <CR>~. or <CR>~^D to break out.");
 }
-#endif
+#endif /* 0 */
index 9aa94250c97b0fa89f6edfc88d227dfa90ffaefd..f83fda7045f42141331fc7377916cdbd649ee430 100644 (file)
@@ -19,13 +19,13 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 /* Terminal state pointer.  This is specific to each type of interface. */
 
-typedef PTR ttystate;
+typedef PTR serial_ttystate;
 
 struct _serial_t
 {
   int fd;                      /* File descriptor */
   struct serial_ops *ops;      /* Function vector */
-  ttystate ttystate;           /* Not used (yet) */
+  serial_ttystate ttystate;    /* Not used (yet) */
   int bufcnt;                  /* Amount of data in receive buffer */
   unsigned char *bufp;         /* Current byte */
   unsigned char buf[BUFSIZ];   /* Da buffer itself */
@@ -42,7 +42,8 @@ struct serial_ops {
   int (*readchar) PARAMS ((serial_t, int timeout));
   int (*write) PARAMS ((serial_t, const char *str, int len));
   void (*go_raw) PARAMS ((serial_t));
-  void (*restore) PARAMS ((serial_t));
+  serial_ttystate (*get_tty_state) PARAMS ((serial_t));
+  int (*set_tty_state) PARAMS ((serial_t, serial_ttystate));
   int (*setbaudrate) PARAMS ((serial_t, int rate));
 };
 
@@ -52,6 +53,8 @@ void serial_add_interface PARAMS ((struct serial_ops *optable));
 
 serial_t serial_open PARAMS ((const char *name));
 
+serial_t serial_fdopen PARAMS ((int fd));
+
 /* For most routines, if a failure is indicated, then errno should be
    examined.  */
 
@@ -60,10 +63,18 @@ serial_t serial_open PARAMS ((const char *name));
 
 #define SERIAL_OPEN(NAME) serial_open(NAME)
 
+/* Open a new serial stream using a file handle.  */
+
+#define SERIAL_FDOPEN(FD) serial_fdopen(FD)
+
 /* Turn the port into raw mode. */
 
 #define SERIAL_RAW(SERIAL_T) (SERIAL_T)->ops->go_raw((SERIAL_T))
 
+#define SERIAL_GET_TTY_STATE(SERIAL_T) (SERIAL_T)->ops->get_tty_state((SERIAL_T))
+
+#define SERIAL_SET_TTY_STATE(SERIAL_T, TTYSTATE) (SERIAL_T)->ops->set_tty_state((SERIAL_T), (TTYSTATE))
+
 /* Read one char from the serial device with TIMEOUT seconds timeout.
    Returns char if ok, else one of the following codes.  Note that all
    error codes are guaranteed to be < 0.  */
@@ -90,7 +101,3 @@ void serial_close PARAMS ((serial_t));
 
 #define SERIAL_CLOSE(SERIAL_T) serial_close(SERIAL_T)
 
-/* Restore the serial port to the state saved in oldstate.  XXX - currently
-   unused! */
-
-#define SERIAL_RESTORE(SERIAL_T) (SERIAL_T)->ops->restore((SERIAL_T))