⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 connect.c

📁 开放源码的编译器open watcom 1.6.0版的源代码
💻 C
字号:
/*
 *
 *   BSD sockets functionality for Waterloo TCP/IP
 *
 *   Version
 *
 *   0.5 : Dec 18, 1997 : G. Vanem - created
 */

#include "socket.h"

#if defined(USE_BSD_FUNC)

static int  tcp_connect  (Socket *socket);
static int  udp_connect  (Socket *socket);
static int  raw_connect  (Socket *socket);
static int  nblk_connect (Socket *socket);
static void set_keepalive(Socket *sock);

/*
 * connect
 *  "connect" will attempt to open a connection on a foreign IP address and
 *  foreign port address.  This is achieved by specifying the foreign IP
 *  address and foreign port number in the "servaddr".
 */

int connect (int s, const struct sockaddr *servaddr, int addrlen)
{
  struct   sockaddr_in *addr   = (struct sockaddr_in*) servaddr;
  struct   Socket      *socket = _socklist_find (s);
  volatile int rc;

  SOCK_PROLOGUE (socket, "\nconnect:%d", s);

  if (socket->so_type == SOCK_STREAM)
  {
    if (socket->so_state & SS_ISCONNECTED)
    {
      SOCK_DEBUGF ((socket, ", EISCONN"));
      SOCK_ERR (EISCONN);
      return (-1);
    }
    if (socket->so_options & SO_ACCEPTCONN)
    {
      SOCK_DEBUGF ((socket, ", EOPNOTSUPP (listen sock)"));
      SOCK_ERR (EOPNOTSUPP);
      return (-1);
    }
    if (IN_MULTICAST(ntohl(addr->sin_addr.s_addr)))
    {
      SOCK_DEBUGF ((socket, ", EINVAL (mc)"));
      SOCK_ERR (EINVAL);
      return (-1);
    }
  }

  if (!addr || addrlen < sizeof(*servaddr))
  {
    SOCK_DEBUGF ((socket, ", EINVAL"));
    SOCK_ERR (EINVAL);
    return (-1);
  } 

  if (socket->remote_addr)
  {
    if ((socket->so_type == SOCK_STREAM) &&
        (socket->so_state & SS_NBIO))
       return nblk_connect (socket);

    SOCK_DEBUGF ((socket, ", connect already done!"));
    SOCK_ERR (EISCONN);
    return (-1);
  }

  socket->remote_addr = SOCK_CALLOC (sizeof(*socket->remote_addr));
  if (!socket->remote_addr)
  {
    SOCK_DEBUGF ((socket, ", ENOMEM (rem)"));
    SOCK_ERR (ENOMEM);
    return (-1);
  }

  socket->remote_addr->sin_family = AF_INET;
  socket->remote_addr->sin_port   = addr->sin_port;
  socket->remote_addr->sin_addr   = addr->sin_addr;


  if (!socket->local_addr)
  {
    SOCK_DEBUGF ((socket, ", auto-binding"));

    socket->local_addr = SOCK_CALLOC (sizeof(*socket->local_addr));
    if (!socket->local_addr)
    {
      free (socket->remote_addr);
      socket->remote_addr = NULL;
      SOCK_DEBUGF ((socket, ", ENOMEM (loc)"));
      SOCK_ERR (ENOMEM);
      return (-1);
    }
    socket->local_addr->sin_family      = AF_INET;
    socket->local_addr->sin_port        = htons (findfreeport(0,TRUE));
    socket->local_addr->sin_addr.s_addr = htonl (my_ip_addr);
  }

  SOCK_DEBUGF ((socket, ", loc/rem ports: %u/%u",
                ntohs(socket->local_addr->sin_port),
                ntohs(socket->remote_addr->sin_port)));


  /* Not safe to run sock_daemon() now
   */
  _sock_start_crit();

  /* Setup SIGINT handler now.
   */
  if (_sock_sig_setup() < 0)
  {
    SOCK_ERR (EINTR);
    rc = -1;
    goto connect_fail;
  }

  switch (socket->so_type)
  {
    case SOCK_STREAM:
         rc = tcp_connect (socket);
         break;

    case SOCK_DGRAM:
         rc = udp_connect (socket);
         break;

    case SOCK_RAW:
         rc = raw_connect (socket);
         break;

    default:
         SOCK_ERR (EPROTONOSUPPORT);
         rc = -1;
  }

connect_fail:
  _sock_stop_crit();
  _sock_sig_restore();
  return (rc);
}

/*
 *  Handle SOCK_DGRAM connection. Always blocking in _arp_resolve()
 */
static int udp_connect (Socket *socket)
{
  if (!_UDP_open (socket,
                  socket->remote_addr->sin_addr,
                  socket->local_addr->sin_port,
                  socket->remote_addr->sin_port))
  {
    SOCK_DEBUGF ((socket, ", no route"));
    SOCK_ERR (EHOSTUNREACH);
    STAT (ipstats.ips_noroute++);
    return (-1);
  }
  socket->so_state &= ~SS_UNCONNECTED;
  socket->so_state |=  SS_ISCONNECTED;
  set_keepalive (socket);
  return (0);
}

/*
 *  SOCK_RAW "connect" is very simple.
 */
static int raw_connect (Socket *socket)
{
  socket->so_state |= SS_ISCONNECTED;

  /* Note: _arp_resolve() is done in ip_transmit()
   */
  return (0);
}

/*
 *  Handle SOCK_STREAM blocking connection.
 */
static int tcp_connect (Socket *socket)
{
  DWORD timeout;
  int   status;

  if (!_TCP_open (socket,
                  socket->remote_addr->sin_addr,
                  socket->local_addr->sin_port,
                  socket->remote_addr->sin_port))
  {
    SOCK_DEBUGF ((socket, ", no route"));
    SOCK_ERR (EHOSTUNREACH);
    STAT (ipstats.ips_noroute++);
    return (-1);
  }

  /* Don't let tcp_Retransmitter() kill this socket
   * before our `socket->timeout' expires
   */
  socket->tcp_sock->locflags |= LF_RCVTIMEO;

  /* We're here only when connect() is called the 1st time
   * (blocking or non-blocking socket).
   */
  socket->so_state |= SS_ISCONNECTING;

  if (socket->so_state & SS_NBIO)
  {
    /* if user calls getsockopt(SO_ERROR) before calling connect() again
     */
    socket->so_error = EALREADY;   
    SOCK_DEBUGF ((socket, ", EINPROGRESS"));
    SOCK_ERR (EINPROGRESS);
    return (-1);
  }

  /* Handle blocking stream socket connect.
   * maybe we should use select_s() instead ?
   */
  timeout = set_timeout (1000 * socket->timeout);
  status  = _ip_delay0 ((sock_type*)socket->tcp_sock,
                        socket->timeout, NULL, NULL);


  /* We got an ICMP_UNREACH from our peer
   */
  if (socket->so_state & SS_CONN_REFUSED)
  {
    SOCK_DEBUGF ((socket, ", ECONNREFUSED"));
    SOCK_ERR (ECONNREFUSED);
    return (-1);
  }

  if (chk_timeout(timeout))
  {
    SOCK_DEBUGF ((socket, ", ETIMEDOUT\n"));
    socket->so_state &= ~SS_ISCONNECTING;
    SOCK_ERR (ETIMEDOUT);
    return (-1);
  }

  if (status < 0)
  {
    SOCK_DEBUGF ((socket, ", ECONNRESET"));
    socket->so_state &= ~SS_ISCONNECTING;
    SOCK_ERR (ECONNRESET);
    return (-1);
  }

  socket->so_state &= ~SS_UNCONNECTED;
  socket->so_state &= ~SS_ISCONNECTING;
  socket->so_state |=  SS_ISCONNECTED;
  set_keepalive (socket);
  return (0);
}


/*
 *  Handle non-blocking SOCK_STREAM connection.
 *  Only called on 2nd (3rd etc) time a non-blocking
 *  connect() is called.
 */
static int nblk_connect (Socket *socket)
{
  if (socket->so_state & SS_ISCONNECTED)
  {
    SOCK_DEBUGF ((socket, ", connected!"));
    set_keepalive (socket);
    socket->so_error = 0;
    return (0);
  }

  if ((socket->so_state & (SS_ISDISCONNECTING | SS_CONN_REFUSED)) ||
      (socket->tcp_sock->state >= tcp_StateCLOSED))
  {
    SOCK_DEBUGF ((socket, ", ECONNREFUSED"));
    socket->so_error = ECONNREFUSED;
    SOCK_ERR (ECONNREFUSED);           /* could also be ECONNRESET */
    return (-1);
  }

  if (socket->so_state & SS_ISCONNECTING)
  {
    SOCK_DEBUGF ((socket, ", EALREADY"));
    socket->so_error = EALREADY;       /* should be redundant */
    SOCK_ERR (EALREADY);
    return (-1);
  }

  SOCK_FATAL (("%s (%d) Fatal: Unhandled non-block event\r\n",
              __FILE__, __LINE__));
  return (-1);
}

/*
 * Sets keepalive timer on DGRAM/STREAM socket
 */
static void set_keepalive (Socket *sock)
{
  if ((sock->so_options & SO_KEEPALIVE) && tcp_keepalive)
     sock->keepalive = set_timeout (1000 * tcp_keepalive);
}

#endif /* USE_BSD_FUNC */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -