Exemplo n.º 1
0
/*
 *  Allocate and fill local/remote addresses for 'clone'.
 *  Take local address from 'socket', and remote address from
 *  TCB of clone.
 */
static int alloc_addr (Socket *socket, Socket *clone)
{
  struct in_addr peer;

  clone->local_addr  = SOCK_CALLOC (sizeof(*clone->local_addr));
  clone->remote_addr = SOCK_CALLOC (sizeof(*clone->remote_addr));

  if (!clone->local_addr || !clone->remote_addr)
  {
    SOCK_DEBUGF ((socket, ", ENOMEM"));
    SOCK_ERR (ENOMEM);
    return (-1);
  }

  peer.s_addr = htonl (clone->tcp_sock->hisaddr);
  clone->local_addr->sin_family  = AF_INET;
  clone->local_addr->sin_port    = socket->local_addr->sin_port;
  clone->local_addr->sin_addr    = socket->local_addr->sin_addr;

  clone->remote_addr->sin_family = AF_INET;
  clone->remote_addr->sin_port   = htons (clone->tcp_sock->hisport);
  clone->remote_addr->sin_addr   = peer;
  return (0);
}
Exemplo n.º 2
0
/*
 * 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 W32_CALL connect (int s, const struct sockaddr *servaddr, int addrlen)
{
  struct   sockaddr_in  *addr   = (struct sockaddr_in*) servaddr;
  struct   sockaddr_in6 *addr6  = (struct sockaddr_in6*) servaddr;
  struct   Socket       *socket = _socklist_find (s);
  volatile int rc, sa_len;
  BOOL     is_ip6;

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

  is_ip6 = (socket->so_family == AF_INET6);
  sa_len = is_ip6 ? sizeof(*addr6) : sizeof(*addr);

  if (_sock_chk_sockaddr(socket, servaddr, addrlen) < 0)
     return (-1);

  if (socket->so_type == SOCK_STREAM)
  {
    if (socket->so_state & SS_ISCONNECTED)
    {
      SOCK_DEBUGF ((", EISCONN"));
      SOCK_ERRNO (EISCONN);
      return (-1);
    }
    if (socket->so_options & SO_ACCEPTCONN)
    {
      SOCK_DEBUGF ((", EOPNOTSUPP (listen sock)"));
      SOCK_ERRNO (EOPNOTSUPP);
      return (-1);
    }
    if (!is_ip6 && IN_MULTICAST(ntohl(addr->sin_addr.s_addr)))
    {
      SOCK_DEBUGF ((", EINVAL (mcast)"));
      SOCK_ERRNO (EINVAL);
      return (-1);
    }
    else if (is_ip6 && IN6_IS_ADDR_MULTICAST(&addr6->sin6_addr))
    {
      SOCK_DEBUGF ((", EINVAL (mcast)"));
      SOCK_ERRNO (EINVAL);
      return (-1);
    }
  }

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

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

  socket->remote_addr = (struct sockaddr_in*) SOCK_CALLOC (sa_len);
  if (!socket->remote_addr)
  {
    SOCK_DEBUGF ((", ENOMEM (rem)"));
    SOCK_ERRNO (ENOMEM);
    return (-1);
  }

#if defined(USE_IPV6)
  if (is_ip6)
  {
    struct sockaddr_in6 *ra = (struct sockaddr_in6*)socket->remote_addr;

    ra->sin6_family = AF_INET6;
    ra->sin6_port   = addr6->sin6_port;
    memcpy (&ra->sin6_addr, &addr6->sin6_addr, sizeof(ra->sin6_addr));
  }
  else
#endif
  {
    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 ((", auto-binding"));

    socket->local_addr = (struct sockaddr_in*) SOCK_CALLOC (sa_len);
    if (!socket->local_addr)
    {
      free (socket->remote_addr);
      socket->remote_addr = NULL;
      SOCK_DEBUGF ((", ENOMEM (loc)"));
      SOCK_ERRNO (ENOMEM);
      return (-1);
    }

#if defined(USE_IPV6)
    if (is_ip6)
    {
      struct sockaddr_in6 *la = (struct sockaddr_in6*)socket->local_addr;

      la->sin6_family = AF_INET6;
      la->sin6_port   = htons (find_free_port(0,TRUE));
      memcpy (&la->sin6_addr, &in6addr_my_ip, sizeof(la->sin6_addr));
    }
    else
#endif
    {
      socket->local_addr->sin_family      = AF_INET;
      socket->local_addr->sin_port        = htons (find_free_port(0,TRUE));
      socket->local_addr->sin_addr.s_addr = htonl (my_ip_addr);
    }
  }

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


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

  /* Setup SIGINT handler now.
   */
  if (_sock_sig_setup() < 0)
  {
    SOCK_ERRNO (EINTR);
    SOCK_DEBUGF ((", EINTR"));
    _sock_crit_stop();
    return (-1);
  }

  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_ERRNO (EPROTONOSUPPORT);
         rc = -1;
         break;
  }

  _sock_sig_restore();
  _sock_crit_stop();
  return (rc);
}
Exemplo n.º 3
0
/*
 *  Called from tcp_fsm.c / tcp_listen_state() (via _tcp_syn_hook) to
 *  append a new connection to the listen-queue of socket 'sock'.
 *
 *  TCB on input ('orig') has received a SYN. Replace TCB on output
 *  with a cloned TCB that we append to the listen-queue and eventually
 *  is used by accept() to create a new socket.
 *
 *  TCB on input ('orig') must still be listening for further connections
 *  on the same port as specified in call to _TCP_listen().
 */
int _sock_append (tcp_Socket **tcp)
{
  tcp_Socket *clone;
  tcp_Socket *orig = *tcp;
  Socket     *sock = NULL;   /* associated socket for '*tcp' */
  int         i;

  /* Lookup BSD-socket for Wattcp TCB
   */
  if (!_tcp_find_hook || (sock = (*_tcp_find_hook)(orig)) == NULL)
  {
    SOCK_DEBUGF ((NULL, "\n  sock_append: not found!?"));
    return (0);  /* i.e. could be a native Wattcp socket */
  }

  SOCK_DEBUGF ((sock, "\n  sock_append:%d", sock->fd));

  if (!(sock->so_options & SO_ACCEPTCONN))
  {
    SOCK_DEBUGF ((sock, ", not SO_ACCEPTCONN"));
    return (-1);  /* How could this happen? */
  }

  /* Find the first vacant slot for this clone
   */
  for (i = 0; i < sock->backlog; i++)
      if (!sock->listen_queue[i])
         break;

  if (i >= sock->backlog || i >= SOMAXCONN)
  {
    /* !!to-do: drop the oldest (or a random) slot in the listen-queue.
     */
    SOCK_DEBUGF ((sock, ", queue full (idx %d)", i));
    return (-1);
  }

  SOCK_DEBUGF ((sock, ", idx %d", i));

  clone = SOCK_CALLOC (sizeof(*clone));
  if (!clone)
  {
    SOCK_DEBUGF ((sock, ", ENOMEM"));
    return (-1);
  }

  /* Link in the semi-connected socket (SYN received, ACK will be sent)
   */
  sock->listen_queue[i]  = clone;
  sock->syn_timestamp[i] = set_timeout (0);

  /* Copy the TCB (except Tx-buffer) to clone
   */
  memcpy (clone, orig, sizeof(*clone) - sizeof(clone->data));
  clone->safetytcp = SAFETYTCP;

  /* Increase the TCP window (to 16kB)
   */
  sock_setbuf ((sock_type*)clone, calloc(DEFAULT_RCV_WIN,1), DEFAULT_RCV_WIN);

  /* Undo what tcp_handler() and tcp_listen_state() did to
   * this listening socket.
   */
  orig->hisport = 0;
  orig->hisaddr = 0;
  orig->myaddr  = 0;

  orig->seqnum  = INIT_SEQ();   /* set new ISS */
  orig->unhappy = FALSE;
  CLR_PEER_MAC_ADDR (orig);

#if defined(USE_DEBUG)          /* !!needs some work */
  orig->last_acknum[0] = orig->last_acknum[1] = 0;
  orig->last_seqnum[0] = orig->last_seqnum[1] = 0;
#endif

  clone->next  = _tcp_allsocs;
  _tcp_allsocs = clone;         /* prepend clone to TCB-list */
  *tcp = clone;                 /* clone is now the new TCB */
  return (0);
}