/* * 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); }
/* * 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); }
/* * 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); }