119370Spst/* Serial interface for raw TCP connections on Un*x like systems
298944Sobrien   Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2001
398944Sobrien   Free Software Foundation, Inc.
419370Spst
598944Sobrien   This file is part of GDB.
619370Spst
798944Sobrien   This program is free software; you can redistribute it and/or modify
898944Sobrien   it under the terms of the GNU General Public License as published by
998944Sobrien   the Free Software Foundation; either version 2 of the License, or
1098944Sobrien   (at your option) any later version.
1119370Spst
1298944Sobrien   This program is distributed in the hope that it will be useful,
1398944Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
1498944Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1598944Sobrien   GNU General Public License for more details.
1619370Spst
1798944Sobrien   You should have received a copy of the GNU General Public License
1898944Sobrien   along with this program; if not, write to the Free Software
1998944Sobrien   Foundation, Inc., 59 Temple Place - Suite 330,
2098944Sobrien   Boston, MA 02111-1307, USA.  */
2119370Spst
2219370Spst#include "defs.h"
2319370Spst#include "serial.h"
2498944Sobrien#include "ser-unix.h"
2598944Sobrien
2619370Spst#include <sys/types.h>
2798944Sobrien
2898944Sobrien#ifdef HAVE_SYS_FILIO_H
2998944Sobrien#include <sys/filio.h>  /* For FIONBIO. */
3098944Sobrien#endif
3198944Sobrien#ifdef HAVE_SYS_IOCTL_H
3298944Sobrien#include <sys/ioctl.h>  /* For FIONBIO. */
3398944Sobrien#endif
3498944Sobrien
3519370Spst#include <sys/time.h>
3619370Spst#include <netinet/in.h>
3719370Spst#include <arpa/inet.h>
3819370Spst#include <netdb.h>
3919370Spst#include <sys/socket.h>
4019370Spst#include <netinet/tcp.h>
4146283Sdfr
4298944Sobrien#include <signal.h>
4319370Spst#include "gdb_string.h"
4419370Spst
45130803Smarcelstatic int net_open (struct serial *scb, const char *name);
46130803Smarcelstatic void net_close (struct serial *scb);
4798944Sobrienextern int (*ui_loop_hook) (int);
4898944Sobrienvoid _initialize_ser_tcp (void);
4919370Spst
5098944Sobrien/* seconds to wait for connect */
5198944Sobrien#define TIMEOUT 15
5298944Sobrien/* how many times per second to poll ui_loop_hook */
5398944Sobrien#define POLL_INTERVAL 2
5419370Spst
5598944Sobrien/* Open a tcp socket */
5646283Sdfr
5719370Spststatic int
58130803Smarcelnet_open (struct serial *scb, const char *name)
5919370Spst{
6098944Sobrien  char *port_str, hostname[100];
6198944Sobrien  int n, port, tmp;
62130803Smarcel  int use_udp;
6319370Spst  struct hostent *hostent;
6419370Spst  struct sockaddr_in sockaddr;
6519370Spst
66130803Smarcel  use_udp = 0;
67130803Smarcel  if (strncmp (name, "udp:", 4) == 0)
68130803Smarcel    {
69130803Smarcel      use_udp = 1;
70130803Smarcel      name = name + 4;
71130803Smarcel    }
72130803Smarcel  else if (strncmp (name, "tcp:", 4) == 0)
73130803Smarcel    name = name + 4;
74130803Smarcel
7519370Spst  port_str = strchr (name, ':');
7619370Spst
7719370Spst  if (!port_str)
78130803Smarcel    error ("net_open: No colon in host name!");	   /* Shouldn't ever happen */
7919370Spst
8019370Spst  tmp = min (port_str - name, (int) sizeof hostname - 1);
8198944Sobrien  strncpy (hostname, name, tmp);	/* Don't want colon */
8219370Spst  hostname[tmp] = '\000';	/* Tie off host name */
8319370Spst  port = atoi (port_str + 1);
8419370Spst
8598944Sobrien  /* default hostname is localhost */
8698944Sobrien  if (!hostname[0])
8798944Sobrien    strcpy (hostname, "localhost");
8898944Sobrien
8919370Spst  hostent = gethostbyname (hostname);
9019370Spst  if (!hostent)
9119370Spst    {
9219370Spst      fprintf_unfiltered (gdb_stderr, "%s: unknown host\n", hostname);
9319370Spst      errno = ENOENT;
9419370Spst      return -1;
9519370Spst    }
9619370Spst
97130803Smarcel  if (use_udp)
98130803Smarcel    scb->fd = socket (PF_INET, SOCK_DGRAM, 0);
99130803Smarcel  else
100130803Smarcel    scb->fd = socket (PF_INET, SOCK_STREAM, 0);
101130803Smarcel
10298944Sobrien  if (scb->fd < 0)
10319370Spst    return -1;
10498944Sobrien
10598944Sobrien  sockaddr.sin_family = PF_INET;
10698944Sobrien  sockaddr.sin_port = htons (port);
10798944Sobrien  memcpy (&sockaddr.sin_addr.s_addr, hostent->h_addr,
10898944Sobrien	  sizeof (struct in_addr));
10919370Spst
11098944Sobrien  /* set socket nonblocking */
11119370Spst  tmp = 1;
11298944Sobrien  ioctl (scb->fd, FIONBIO, &tmp);
11319370Spst
11498944Sobrien  /* Use Non-blocking connect.  connect() will return 0 if connected already. */
11598944Sobrien  n = connect (scb->fd, (struct sockaddr *) &sockaddr, sizeof (sockaddr));
11619370Spst
11798944Sobrien  if (n < 0 && errno != EINPROGRESS)
11819370Spst    {
119130803Smarcel      net_close (scb);
12098944Sobrien      return -1;
12119370Spst    }
12219370Spst
12398944Sobrien  if (n)
12419370Spst    {
12598944Sobrien      /* looks like we need to wait for the connect */
12698944Sobrien      struct timeval t;
12798944Sobrien      fd_set rset, wset;
12898944Sobrien      int polls = 0;
12998944Sobrien      FD_ZERO (&rset);
13019370Spst
13198944Sobrien      do
13298944Sobrien	{
13398944Sobrien	  /* While we wait for the connect to complete
13498944Sobrien	     poll the UI so it can update or the user can
13598944Sobrien	     interrupt. */
13698944Sobrien	  if (ui_loop_hook)
13798944Sobrien	    {
13898944Sobrien	      if (ui_loop_hook (0))
13998944Sobrien		{
14098944Sobrien		  errno = EINTR;
141130803Smarcel		  net_close (scb);
14298944Sobrien		  return -1;
14398944Sobrien		}
14498944Sobrien	    }
14598944Sobrien
14698944Sobrien	  FD_SET (scb->fd, &rset);
14798944Sobrien	  wset = rset;
14898944Sobrien	  t.tv_sec = 0;
14998944Sobrien	  t.tv_usec = 1000000 / POLL_INTERVAL;
15098944Sobrien
15198944Sobrien	  n = select (scb->fd + 1, &rset, &wset, NULL, &t);
15298944Sobrien	  polls++;
15398944Sobrien	}
15498944Sobrien      while (n == 0 && polls <= TIMEOUT * POLL_INTERVAL);
15598944Sobrien      if (n < 0 || polls > TIMEOUT * POLL_INTERVAL)
15698944Sobrien	{
15798944Sobrien	  if (polls > TIMEOUT * POLL_INTERVAL)
15898944Sobrien	    errno = ETIMEDOUT;
159130803Smarcel	  net_close (scb);
16098944Sobrien	  return -1;
16198944Sobrien	}
16246283Sdfr    }
16319370Spst
16498944Sobrien  /* Got something.  Is it an error? */
16598944Sobrien  {
16698944Sobrien    int res, err, len;
16798944Sobrien    len = sizeof(err);
16898944Sobrien    res = getsockopt (scb->fd, SOL_SOCKET, SO_ERROR, &err, &len);
16998944Sobrien    if (res < 0 || err)
17098944Sobrien      {
17198944Sobrien	if (err)
17298944Sobrien	  errno = err;
173130803Smarcel	net_close (scb);
17498944Sobrien	return -1;
17598944Sobrien      }
17698944Sobrien  }
177130803Smarcel
17898944Sobrien  /* turn off nonblocking */
17998944Sobrien  tmp = 0;
18098944Sobrien  ioctl (scb->fd, FIONBIO, &tmp);
18119370Spst
182130803Smarcel  if (use_udp == 0)
183130803Smarcel    {
184130803Smarcel      /* Disable Nagle algorithm. Needed in some cases. */
185130803Smarcel      tmp = 1;
186130803Smarcel      setsockopt (scb->fd, IPPROTO_TCP, TCP_NODELAY,
187130803Smarcel		  (char *)&tmp, sizeof (tmp));
188130803Smarcel    }
189130803Smarcel
19098944Sobrien  /* If we don't do this, then GDB simply exits
19198944Sobrien     when the remote side dies.  */
19298944Sobrien  signal (SIGPIPE, SIG_IGN);
19319370Spst
19419370Spst  return 0;
19519370Spst}
19619370Spst
19719370Spststatic void
198130803Smarcelnet_close (struct serial *scb)
19919370Spst{
20019370Spst  if (scb->fd < 0)
20119370Spst    return;
20219370Spst
20398944Sobrien  close (scb->fd);
20419370Spst  scb->fd = -1;
20519370Spst}
20619370Spst
20719370Spstvoid
20898944Sobrien_initialize_ser_tcp (void)
20919370Spst{
21098944Sobrien  struct serial_ops *ops = XMALLOC (struct serial_ops);
211130803Smarcel  memset (ops, 0, sizeof (struct serial_ops));
21298944Sobrien  ops->name = "tcp";
21398944Sobrien  ops->next = 0;
214130803Smarcel  ops->open = net_open;
215130803Smarcel  ops->close = net_close;
21698944Sobrien  ops->readchar = ser_unix_readchar;
21798944Sobrien  ops->write = ser_unix_write;
21898944Sobrien  ops->flush_output = ser_unix_nop_flush_output;
21998944Sobrien  ops->flush_input = ser_unix_flush_input;
22098944Sobrien  ops->send_break = ser_unix_nop_send_break;
22198944Sobrien  ops->go_raw = ser_unix_nop_raw;
22298944Sobrien  ops->get_tty_state = ser_unix_nop_get_tty_state;
22398944Sobrien  ops->set_tty_state = ser_unix_nop_set_tty_state;
22498944Sobrien  ops->print_tty_state = ser_unix_nop_print_tty_state;
22598944Sobrien  ops->noflush_set_tty_state = ser_unix_nop_noflush_set_tty_state;
22698944Sobrien  ops->setbaudrate = ser_unix_nop_setbaudrate;
22798944Sobrien  ops->setstopbits = ser_unix_nop_setstopbits;
22898944Sobrien  ops->drain_output = ser_unix_nop_drain_output;
22998944Sobrien  ops->async = ser_unix_async;
23098944Sobrien  serial_add_interface (ops);
23119370Spst}
232