int W32_CALL getsockname (int s, struct sockaddr *name, int *namelen) { Socket *socket = _socklist_find (s); int sa_len; SOCK_PROLOGUE (socket, "\ngetsockname:%d", s); sa_len = (socket->so_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in); if (!name || !namelen || (*namelen < sa_len)) { SOCK_DEBUGF ((", EINVAL")); SOCK_ERRNO (EINVAL); if (namelen) *namelen = 0; return (-1); } if (!socket->local_addr) { SOCK_DEBUGF ((", EINVAL")); SOCK_ERRNO (EINVAL); /* according to HP/UX manpage */ return (-1); } VERIFY_RW (name, *namelen); *namelen = sa_len; memcpy (name, socket->local_addr, sa_len); #if defined(USE_IPV6) if (socket->so_family == AF_INET6) { const struct sockaddr_in6 *la = (const struct sockaddr_in6*)socket->local_addr; SOCK_DEBUGF ((", %s (%d)", _inet6_ntoa(&la->sin6_addr), ntohs(la->sin6_port))); ARGSUSED (la); } else #endif { const struct sockaddr_in *la = socket->local_addr; SOCK_DEBUGF ((", %s (%d)", inet_ntoa(la->sin_addr), ntohs(la->sin_port))); ARGSUSED (la); } return (0); }
int W32_CALL getpeername (int s, struct sockaddr *name, int *namelen) { Socket *socket = _socklist_find (s); int sa_len; SOCK_PROLOGUE (socket, "\ngetpeername:%d", s); sa_len = (socket->so_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in); if (!name || !namelen || (*namelen < sa_len)) { SOCK_DEBUGF ((", EINVAL")); SOCK_ERRNO (EINVAL); if (namelen) *namelen = 0; return (-1); } if (!(socket->so_state & SS_ISCONNECTED)) { SOCK_DEBUGF ((", ENOTCONN")); SOCK_ERRNO (ENOTCONN); return (-1); } VERIFY_RW (name, *namelen); *namelen = sa_len; memcpy (name, socket->remote_addr, *namelen); #if defined(USE_IPV6) if (socket->so_family == AF_INET6) { const struct sockaddr_in6 *ra = (const struct sockaddr_in6*)socket->remote_addr; SOCK_DEBUGF ((", %s (%d)", _inet6_ntoa(&ra->sin6_addr), ntohs(ra->sin6_port))); ARGSUSED (ra); } else #endif { const struct sockaddr_in *ra = socket->remote_addr; SOCK_DEBUGF ((", %s (%d)", inet_ntoa(ra->sin_addr), ntohs(ra->sin_port))); ARGSUSED (ra); } return (0); }
/* * transmit() flags: * MSG_DONTROUTE (not supported) * MSG_EOR Close sending side after data sent * MSG_TRUNC (not supported) * MSG_CTRUNC (not supported) * MSG_OOB (not supported) * MSG_WAITALL Wait till room in tx-buffer (not supported) */ static int transmit (const char *func, int s, const void *buf, int len, int flags, const struct sockaddr *to, int tolen) { Socket *socket = _socklist_find (s); int rc; SOCK_DEBUGF ((socket, "\n%s:%d, len=%d", func, s, len)); if (!socket) { if (_sock_dos_fd(s)) { SOCK_DEBUGF ((NULL, ", ENOTSOCK")); SOCK_ERR (ENOTSOCK); return (-1); } SOCK_DEBUGF ((NULL, ", EBADF")); SOCK_ERR (EBADF); return (-1); } if (socket->so_type == SOCK_STREAM || /* TCP-socket or */ (socket->so_state & SS_ISCONNECTED)) /* "connected" udp/raw */ { /* Note: SOCK_RAW doesn't really need a local address/port, but * makes the code more similar for all socket-types. * Disadvantage is that SOCK_RAW ties up a local port and a bit * more memory. */ if (!socket->local_addr) { SOCK_DEBUGF ((socket, ", no local_addr")); SOCK_ERR (ENOTCONN); return (-1); } if (!socket->remote_addr) { SOCK_DEBUGF ((socket, ", no remote_addr")); SOCK_ERR (ENOTCONN); return (-1); } if (socket->so_state & SS_CONN_REFUSED) { if (socket->so_error == ECONNRESET) /* set in tcp_sockreset() */ { SOCK_DEBUGF ((socket, ", ECONNRESET")); SOCK_ERR (ECONNRESET); } else { SOCK_DEBUGF ((socket, ", ECONNREFUSED")); SOCK_ERR (ECONNREFUSED); } return (-1); } } /* connectionless protocol setup */ if (socket->so_type == SOCK_DGRAM || socket->so_type == SOCK_RAW) { if (!to || tolen < sizeof(*to)) { SOCK_DEBUGF ((socket, ", no to-addr")); SOCK_ERR (EINVAL); return (-1); } if (setup_udp_raw(socket,to,tolen) < 0) return (-1); } VERIFY_RW (buf, len); /* Setup SIGINT handler now. */ if (_sock_sig_setup() < 0) { SOCK_ERR (EINTR); return (-1); } switch (socket->so_type) { case SOCK_DGRAM: rc = udp_transmit (socket, buf, len); break; case SOCK_STREAM: rc = tcp_transmit (socket, buf, len, flags); break; case SOCK_RAW: rc = ip_transmit (socket, buf, len); break; default: SOCK_DEBUGF ((socket, ", EPROTONOSUPPORT")); SOCK_ERR (EPROTONOSUPPORT); rc = -1; } _sock_sig_restore(); if (rc >= 0 && (flags & MSG_EOR)) msg_eor_close (socket); return (rc); }
int accept (int s, struct sockaddr *addr, int *addrlen) { Socket *clone, *socket; volatile DWORD timeout; volatile int newsock = -1; volatile int que_idx; volatile int maxconn; socket = _socklist_find (s); SOCK_PROLOGUE (socket, "\naccept:%d", s); if (!socket->local_addr) { SOCK_DEBUGF ((socket, ", not bound")); SOCK_ERR (ENOTCONN); return (-1); } if (socket->so_type != SOCK_STREAM) { SOCK_DEBUGF ((socket, ", EOPNOTSUPP")); SOCK_ERR (EOPNOTSUPP); return (-1); } if (!(socket->so_options & SO_ACCEPTCONN)) /* listen() not called */ { SOCK_DEBUGF ((socket, ", not SO_ACCEPTCONN")); SOCK_ERR (EINVAL); return (-1); } if (!(socket->so_state & (SS_ISLISTENING | SS_ISCONNECTING))) { SOCK_DEBUGF ((socket, ", not listening")); SOCK_ERR (ENOTCONN); return (-1); } if (addr && addrlen) { if (*addrlen < sizeof(*addr)) { SOCK_DEBUGF ((socket, ", EFAULT")); SOCK_ERR (EFAULT); return (-1); } VERIFY_RW (addr, *addrlen); } /* Get max possible TCBs on listen-queue. * Some (or all) may be NULL until a SYN comes in. */ maxconn = socket->backlog; if (maxconn < 1 || maxconn > SOMAXCONN) { SOCK_FATAL (("%s(%d): Illegal socket backlog %d", __FILE__, __LINE__, maxconn)); SOCK_ERR (EINVAL); return (-1); } if (socket->timeout) timeout = set_timeout (1000 * socket->timeout); else timeout = 0UL; if (_sock_sig_setup() < 0) { SOCK_ERR (EINTR); goto accept_fail; } /* Loop over all queue-slots and accept first connected TCB */ for (que_idx = 0; ; que_idx = (++que_idx % maxconn)) { tcp_Socket *sk = socket->listen_queue [que_idx]; tcp_tick (NULL); SOCK_YIELD(); /* No SYNs received yet. This shouldn't happen if we called 'accept()' * after 'select_s()' said that socket was readable. (At least one * connection on the listen-queue). */ if (sk) { /* This could happen if 'accept()' was called too long after connection * was established and then closed by peer. This could also happen if * someone did a portscan on us. I.e. he sent 'SYN', we replied with * 'SYN+ACK' and he never sent an 'ACK'. Thus we timeout in * 'tcp_Retransmitter()' and abort the TCB. * * Queue slot is in any case ready for another 'SYN' to come and be * handled by '_sock_append()'. */ if (sk->state >= tcp_StateLASTACK && sk->ip_type == 0) { SOCK_DEBUGF ((socket, ", aborted TCB (idx %d)", que_idx)); listen_free (socket, que_idx); continue; } /* !!to-do: Should maybe loop over all maxconn TCBs and accept the * one with oldest 'syn_timestamp'. */ if (tcp_established(sk)) { SOCK_DEBUGF ((socket, ", connected! (idx %d)", que_idx)); break; } } /* We've polled all listen-queue slots and none are connected. * Return fail if socket is non-blocking. */ if (que_idx == maxconn-1 && (socket->so_state & SS_NBIO)) { SOCK_DEBUGF ((socket, ", would block")); SOCK_ERR (EWOULDBLOCK); goto accept_fail; } if (chk_timeout(timeout)) { SOCK_DEBUGF ((socket, ", ETIMEDOUT")); SOCK_ERR (ETIMEDOUT); goto accept_fail; } } /* We're here only when above 'tcp_established()' succeeded. * Now duplicate 'socket' into a new listening socket 'clone' * with handle 'newsock'. */ _sock_enter_scope(); newsock = dup_bind (socket, &clone, que_idx); if (newsock < 0) goto accept_fail; if (alloc_addr(socket, clone) < 0) { SOCK_DEL_FD (newsock); goto accept_fail; } /* Clone is connected, but *not* listening/accepting. * Note: other 'so_state' bits from parent is unchanged. * e.g. clone may be non-blocking. */ clone->so_state |= SS_ISCONNECTED; clone->so_state &= ~(SS_ISLISTENING | SS_ISCONNECTING); clone->so_options &= ~SO_ACCEPTCONN; /* Prevent a PUSH on first segment sent. */ sock_noflush ((sock_type*)clone->tcp_sock); SOCK_DEBUGF ((clone, "\nremote %s (%d)", inet_ntoa (clone->remote_addr->sin_addr), ntohs (clone->remote_addr->sin_port))); if (addr && addrlen) { struct sockaddr_in *sa = (struct sockaddr_in*)addr; sa->sin_family = AF_INET; sa->sin_port = clone->remote_addr->sin_port; sa->sin_addr = clone->remote_addr->sin_addr; memset (sa->sin_zero, 0, sizeof(sa->sin_zero)); *addrlen = sizeof(*sa); } _sock_leave_scope(); _sock_sig_restore(); return (newsock); accept_fail: _sock_leave_scope(); _sock_sig_restore(); return (-1); }