| /* Serial interface for raw TCP connections on Un*x like systems. | 
 |  | 
 |    Copyright (C) 1992-2023 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 3 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, see <http://www.gnu.org/licenses/>.  */ | 
 |  | 
 | #include "defs.h" | 
 | #include "serial.h" | 
 | #include "ser-base.h" | 
 | #include "ser-tcp.h" | 
 | #include "gdbcmd.h" | 
 | #include "cli/cli-decode.h" | 
 | #include "cli/cli-setshow.h" | 
 | #include "gdbsupport/filestuff.h" | 
 | #include "gdbsupport/netstuff.h" | 
 |  | 
 | #include <sys/types.h> | 
 |  | 
 | #ifdef HAVE_SYS_FILIO_H | 
 | #include <sys/filio.h>  /* For FIONBIO.  */ | 
 | #endif | 
 | #ifdef HAVE_SYS_IOCTL_H | 
 | #include <sys/ioctl.h>  /* For FIONBIO.  */ | 
 | #endif | 
 |  | 
 | #include "gdbsupport/gdb_sys_time.h" | 
 |  | 
 | #ifdef USE_WIN32API | 
 | #include <ws2tcpip.h> | 
 | #ifndef ETIMEDOUT | 
 | #define ETIMEDOUT WSAETIMEDOUT | 
 | #endif | 
 | /* Gnulib defines close too, but gnulib's replacement | 
 |    doesn't call closesocket unless we import the | 
 |    socketlib module.  */ | 
 | #undef close | 
 | #define close(fd) closesocket (fd) | 
 | #define ioctl ioctlsocket | 
 | #else | 
 | #include <netinet/in.h> | 
 | #include <arpa/inet.h> | 
 | #include <netdb.h> | 
 | #include <sys/socket.h> | 
 | #include <netinet/tcp.h> | 
 | #endif | 
 |  | 
 | #include <signal.h> | 
 | #include "gdbsupport/gdb_select.h" | 
 | #include <algorithm> | 
 |  | 
 | #ifndef HAVE_SOCKLEN_T | 
 | typedef int socklen_t; | 
 | #endif | 
 |  | 
 | /* For "set tcp" and "show tcp".  */ | 
 |  | 
 | static struct cmd_list_element *tcp_set_cmdlist; | 
 | static struct cmd_list_element *tcp_show_cmdlist; | 
 |  | 
 | /* Whether to auto-retry refused connections.  */ | 
 |  | 
 | static bool tcp_auto_retry = true; | 
 |  | 
 | /* Timeout period for connections, in seconds.  */ | 
 |  | 
 | static unsigned int tcp_retry_limit = 15; | 
 |  | 
 | /* How many times per second to poll deprecated_ui_loop_hook.  */ | 
 |  | 
 | #define POLL_INTERVAL 5 | 
 |  | 
 | /* Helper function to wait a while.  If SOCK is not -1, wait on its | 
 |    file descriptor.  Otherwise just wait on a timeout, updating | 
 |    *POLLS.  Returns -1 on timeout or interrupt, otherwise the value of | 
 |    select.  */ | 
 |  | 
 | static int | 
 | wait_for_connect (int sock, unsigned int *polls) | 
 | { | 
 |   struct timeval t; | 
 |   int n; | 
 |  | 
 |   /* While we wait for the connect to complete,  | 
 |      poll the UI so it can update or the user can  | 
 |      interrupt.  */ | 
 |   if (deprecated_ui_loop_hook && deprecated_ui_loop_hook (0)) | 
 |     { | 
 |       errno = EINTR; | 
 |       return -1; | 
 |     } | 
 |  | 
 |   /* Check for timeout.  */ | 
 |   if (*polls > tcp_retry_limit * POLL_INTERVAL) | 
 |     { | 
 |       errno = ETIMEDOUT; | 
 |       return -1; | 
 |     } | 
 |  | 
 |   /* Back off to polling once per second after the first POLL_INTERVAL | 
 |      polls.  */ | 
 |   if (*polls < POLL_INTERVAL) | 
 |     { | 
 |       t.tv_sec = 0; | 
 |       t.tv_usec = 1000000 / POLL_INTERVAL; | 
 |     } | 
 |   else | 
 |     { | 
 |       t.tv_sec = 1; | 
 |       t.tv_usec = 0; | 
 |     } | 
 |  | 
 |   if (sock >= 0) | 
 |     { | 
 |       fd_set rset, wset, eset; | 
 |  | 
 |       FD_ZERO (&rset); | 
 |       FD_SET (sock, &rset); | 
 |       wset = rset; | 
 |       eset = rset; | 
 |  | 
 |       /* POSIX systems return connection success or failure by signalling | 
 | 	 wset.  Windows systems return success in wset and failure in | 
 | 	 eset. | 
 |  | 
 | 	 We must call select here, rather than gdb_select, because | 
 | 	 the serial structure has not yet been initialized - the | 
 | 	 MinGW select wrapper will not know that this FD refers | 
 | 	 to a socket.  */ | 
 |       n = select (sock + 1, &rset, &wset, &eset, &t); | 
 |     } | 
 |   else | 
 |     /* Use gdb_select here, since we have no file descriptors, and on | 
 |        Windows, plain select doesn't work in that case.  */ | 
 |     n = interruptible_select (0, NULL, NULL, NULL, &t); | 
 |  | 
 |   /* If we didn't time out, only count it as one poll.  */ | 
 |   if (n > 0 || *polls < POLL_INTERVAL) | 
 |     (*polls)++; | 
 |   else | 
 |     (*polls) += POLL_INTERVAL; | 
 |  | 
 |   return n; | 
 | } | 
 |  | 
 | /* Try to connect to the host represented by AINFO.  If the connection | 
 |    succeeds, return its socket.  Otherwise, return -1 and set ERRNO | 
 |    accordingly.  POLLS is used when 'connect' returns EINPROGRESS, and | 
 |    we need to invoke 'wait_for_connect' to obtain the status.  */ | 
 |  | 
 | static int | 
 | try_connect (const struct addrinfo *ainfo, unsigned int *polls) | 
 | { | 
 |   int sock = gdb_socket_cloexec (ainfo->ai_family, ainfo->ai_socktype, | 
 | 				 ainfo->ai_protocol); | 
 |  | 
 |   if (sock < 0) | 
 |     return -1; | 
 |  | 
 |   /* Set socket nonblocking.  */ | 
 | #ifdef USE_WIN32API | 
 |   u_long ioarg = 1; | 
 | #else | 
 |   int ioarg = 1; | 
 | #endif | 
 |  | 
 |   ioctl (sock, FIONBIO, &ioarg); | 
 |  | 
 |   /* Use Non-blocking connect.  connect() will return 0 if connected | 
 |      already.  */ | 
 |   if (connect (sock, ainfo->ai_addr, ainfo->ai_addrlen) < 0) | 
 |     { | 
 | #ifdef USE_WIN32API | 
 |       int err = WSAGetLastError(); | 
 | #else | 
 |       int err = errno; | 
 | #endif | 
 |  | 
 |       /* If we've got a "connection refused" error, just return | 
 | 	 -1.  The caller will know what to do.  */ | 
 |       if ( | 
 | #ifdef USE_WIN32API | 
 | 	  err == WSAECONNREFUSED | 
 | #else | 
 | 	  err == ECONNREFUSED | 
 | #endif | 
 | 	  ) | 
 | 	{ | 
 | 	  close (sock); | 
 | 	  errno = err; | 
 | 	  return -1; | 
 | 	} | 
 |  | 
 |       if ( | 
 | 	  /* Any other error (except EINPROGRESS) will be "swallowed" | 
 | 	     here.  We return without specifying a return value, and | 
 | 	     set errno if the caller wants to inspect what | 
 | 	     happened.  */ | 
 | #ifdef USE_WIN32API | 
 | 	  /* Under Windows, calling "connect" with a non-blocking socket | 
 | 	     results in WSAEWOULDBLOCK, not WSAEINPROGRESS.  */ | 
 | 	  err != WSAEWOULDBLOCK | 
 | #else | 
 | 	  err != EINPROGRESS | 
 | #endif | 
 | 	  ) | 
 | 	{ | 
 | 	  close (sock); | 
 | 	  errno = err; | 
 | 	  return -1; | 
 | 	} | 
 |  | 
 |       /* Looks like we need to wait for the connect.  */ | 
 |       int n; | 
 |  | 
 |       do | 
 | 	n = wait_for_connect (sock, polls); | 
 |       while (n == 0); | 
 |  | 
 |       if (n < 0) | 
 | 	{ | 
 | 	  int saved_errno = errno; | 
 |  | 
 | 	  /* A negative value here means that we either timed out or | 
 | 	     got interrupted by the user.  Just return.  */ | 
 | 	  close (sock); | 
 | 	  errno = saved_errno; | 
 | 	  return -1; | 
 | 	} | 
 |     } | 
 |  | 
 |   /* Got something.  Is it an error?  */ | 
 |   int err; | 
 |   socklen_t len = sizeof (err); | 
 |  | 
 |   /* On Windows, the fourth parameter to getsockopt is a "char *"; | 
 |      on UNIX systems it is generally "void *".  The cast to "char *" | 
 |      is OK everywhere, since in C++ any data pointer type can be | 
 |      implicitly converted to "void *".  */ | 
 |   int ret = getsockopt (sock, SOL_SOCKET, SO_ERROR, (char *) &err, &len); | 
 |  | 
 |   if (ret < 0) | 
 |     { | 
 |       int saved_errno = errno; | 
 |  | 
 |       close (sock); | 
 |       errno = saved_errno; | 
 |       return -1; | 
 |     } | 
 |   else if (ret == 0 && err != 0) | 
 |     { | 
 |       close (sock); | 
 |       errno = err; | 
 |       return -1; | 
 |     } | 
 |  | 
 |   /* The connection succeeded.  Return the socket.  */ | 
 |   return sock; | 
 | } | 
 |  | 
 | /* Open a tcp socket.  */ | 
 |  | 
 | int | 
 | net_open (struct serial *scb, const char *name) | 
 | { | 
 |   struct addrinfo hint; | 
 |   struct addrinfo *ainfo; | 
 |  | 
 |   memset (&hint, 0, sizeof (hint)); | 
 |   /* Assume no prefix will be passed, therefore we should use | 
 |      AF_UNSPEC.  */ | 
 |   hint.ai_family = AF_UNSPEC; | 
 |   hint.ai_socktype = SOCK_STREAM; | 
 |   hint.ai_protocol = IPPROTO_TCP; | 
 |  | 
 |   parsed_connection_spec parsed = parse_connection_spec (name, &hint); | 
 |  | 
 |   if (parsed.port_str.empty ()) | 
 |     error (_("Missing port on hostname '%s'"), name); | 
 |  | 
 |   int r = getaddrinfo (parsed.host_str.c_str (), | 
 | 		       parsed.port_str.c_str (), | 
 | 		       &hint, &ainfo); | 
 |  | 
 |   if (r != 0) | 
 |     { | 
 |       gdb_printf (gdb_stderr, _("%s: cannot resolve name: %s\n"), | 
 | 		  name, gai_strerror (r)); | 
 |       errno = ENOENT; | 
 |       return -1; | 
 |     } | 
 |  | 
 |   scoped_free_addrinfo free_ainfo (ainfo); | 
 |  | 
 |   /* Flag to indicate whether we've got a connection refused.  It will | 
 |      be true if any of the connections tried was refused.  */ | 
 |   bool got_connrefused; | 
 |   /* If a connection succeeds, SUCCESS_AINFO will point to the | 
 |      'struct addrinfo' that succeed.  */ | 
 |   struct addrinfo *success_ainfo = NULL; | 
 |   unsigned int polls = 0; | 
 |  | 
 |   /* Assume the worst.  */ | 
 |   scb->fd = -1; | 
 |  | 
 |   do | 
 |     { | 
 |       got_connrefused = false; | 
 |  | 
 |       for (addrinfo *iter = ainfo; iter != NULL; iter = iter->ai_next) | 
 | 	{ | 
 | 	  /* Iterate over the list of possible addresses to connect | 
 | 	     to.  For each, we'll try to connect and see if it | 
 | 	     succeeds.  */ | 
 | 	  int sock = try_connect (iter, &polls); | 
 |  | 
 | 	  if (sock >= 0) | 
 | 	    { | 
 | 	      /* We've gotten a successful connection.  Save its | 
 | 		 'struct addrinfo', the socket, and break.  */ | 
 | 	      success_ainfo = iter; | 
 | 	      scb->fd = sock; | 
 | 	      break; | 
 | 	    } | 
 | 	  else if ( | 
 | #ifdef USE_WIN32API | 
 | 	  errno == WSAECONNREFUSED | 
 | #else | 
 | 	  errno == ECONNREFUSED | 
 | #endif | 
 | 		   ) | 
 | 	    got_connrefused = true; | 
 | 	} | 
 |     } | 
 |   /* Just retry if: | 
 |  | 
 |      - tcp_auto_retry is true, and | 
 |      - We haven't gotten a connection yet, and | 
 |      - Any of our connection attempts returned with ECONNREFUSED, and | 
 |      - wait_for_connect signals that we can keep going.  */ | 
 |   while (tcp_auto_retry | 
 | 	 && success_ainfo == NULL | 
 | 	 && got_connrefused | 
 | 	 && wait_for_connect (-1, &polls) >= 0); | 
 |  | 
 |   if (success_ainfo == NULL) | 
 |     { | 
 |       net_close (scb); | 
 |       return -1; | 
 |     } | 
 |  | 
 |   /* Turn off nonblocking.  */ | 
 | #ifdef USE_WIN32API | 
 |   u_long ioarg = 0; | 
 | #else | 
 |   int ioarg = 0; | 
 | #endif | 
 |  | 
 |   ioctl (scb->fd, FIONBIO, &ioarg); | 
 |  | 
 |   if (success_ainfo->ai_protocol == IPPROTO_TCP) | 
 |     { | 
 |       /* Disable Nagle algorithm.  Needed in some cases.  */ | 
 |       int tmp = 1; | 
 |  | 
 |       setsockopt (scb->fd, IPPROTO_TCP, TCP_NODELAY, | 
 | 		  (char *) &tmp, sizeof (tmp)); | 
 |     } | 
 |  | 
 | #ifdef SIGPIPE | 
 |   /* If we don't do this, then GDB simply exits | 
 |      when the remote side dies.  */ | 
 |   signal (SIGPIPE, SIG_IGN); | 
 | #endif | 
 |  | 
 |   return 0; | 
 | } | 
 |  | 
 | void | 
 | net_close (struct serial *scb) | 
 | { | 
 |   if (scb->fd == -1) | 
 |     return; | 
 |  | 
 |   close (scb->fd); | 
 |   scb->fd = -1; | 
 | } | 
 |  | 
 | int | 
 | net_read_prim (struct serial *scb, size_t count) | 
 | { | 
 |   /* Need to cast to silence -Wpointer-sign on MinGW, as Winsock's | 
 |      'recv' takes 'char *' as second argument, while 'scb->buf' is | 
 |      'unsigned char *'.  */ | 
 |   return recv (scb->fd, (char *) scb->buf, count, 0); | 
 | } | 
 |  | 
 | int | 
 | net_write_prim (struct serial *scb, const void *buf, size_t count) | 
 | { | 
 |   /* On Windows, the second parameter to send is a "const char *"; on | 
 |      UNIX systems it is generally "const void *".  The cast to "const | 
 |      char *" is OK everywhere, since in C++ any data pointer type can | 
 |      be implicitly converted to "const void *".  */ | 
 |   return send (scb->fd, (const char *) buf, count, 0); | 
 | } | 
 |  | 
 | int | 
 | ser_tcp_send_break (struct serial *scb) | 
 | { | 
 |   /* Send telnet IAC and BREAK characters.  */ | 
 |   return (serial_write (scb, "\377\363", 2)); | 
 | } | 
 |  | 
 | #ifndef USE_WIN32API | 
 |  | 
 | /* The TCP ops.  */ | 
 |  | 
 | static const struct serial_ops tcp_ops = | 
 | { | 
 |   "tcp", | 
 |   net_open, | 
 |   net_close, | 
 |   NULL, | 
 |   ser_base_readchar, | 
 |   ser_base_write, | 
 |   ser_base_flush_output, | 
 |   ser_base_flush_input, | 
 |   ser_tcp_send_break, | 
 |   ser_base_raw, | 
 |   ser_base_get_tty_state, | 
 |   ser_base_copy_tty_state, | 
 |   ser_base_set_tty_state, | 
 |   ser_base_print_tty_state, | 
 |   ser_base_setbaudrate, | 
 |   ser_base_setstopbits, | 
 |   ser_base_setparity, | 
 |   ser_base_drain_output, | 
 |   ser_base_async, | 
 |   net_read_prim, | 
 |   net_write_prim | 
 | }; | 
 |  | 
 | #endif /* USE_WIN32API */ | 
 |  | 
 | void _initialize_ser_tcp (); | 
 | void | 
 | _initialize_ser_tcp () | 
 | { | 
 | #ifdef USE_WIN32API | 
 |   /* Do nothing; the TCP serial operations will be initialized in | 
 |      ser-mingw.c.  */ | 
 | #else | 
 |   serial_add_interface (&tcp_ops); | 
 | #endif /* USE_WIN32API */ | 
 |  | 
 |   add_setshow_prefix_cmd ("tcp", class_maintenance, | 
 | 			  _("\ | 
 | TCP protocol specific variables.\n\ | 
 | Configure variables specific to remote TCP connections."), | 
 | 			  _("\ | 
 | TCP protocol specific variables.\n\ | 
 | Configure variables specific to remote TCP connections."), | 
 | 			  &tcp_set_cmdlist, &tcp_show_cmdlist, | 
 | 			  &setlist, &showlist); | 
 |  | 
 |   add_setshow_boolean_cmd ("auto-retry", class_obscure, | 
 | 			   &tcp_auto_retry, _("\ | 
 | Set auto-retry on socket connect."), _("\ | 
 | Show auto-retry on socket connect."), | 
 | 			   NULL, NULL, NULL, | 
 | 			   &tcp_set_cmdlist, &tcp_show_cmdlist); | 
 |  | 
 |   add_setshow_uinteger_cmd ("connect-timeout", class_obscure, | 
 | 			    &tcp_retry_limit, _("\ | 
 | Set timeout limit in seconds for socket connection."), _("\ | 
 | Show timeout limit in seconds for socket connection."), _("\ | 
 | If set to \"unlimited\", GDB will keep attempting to establish a\n\ | 
 | connection forever, unless interrupted with Ctrl-c.\n\ | 
 | The default is 15 seconds."), | 
 | 			    NULL, NULL, | 
 | 			    &tcp_set_cmdlist, &tcp_show_cmdlist); | 
 | } |