ssize_t psock_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, int flags, FAR struct sockaddr *from, FAR socklen_t *fromlen) { ssize_t ret; /* Verify that non-NULL pointers were passed */ #ifdef CONFIG_DEBUG_FEATURES if (!buf) { return -EINVAL; } #endif if (from != NULL && fromlen != NULL && *fromlen <= 0) { return -EINVAL; } /* Verify that the sockfd corresponds to valid, allocated socket */ if (psock == NULL || psock->s_crefs <= 0) { return -EBADF; } /* Set the socket state to receiving */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_RECV); /* Let logic specific to this address family handle the recvfrom() * operation. */ DEBUGASSERT(psock->s_sockif != NULL && psock->s_sockif->si_recvfrom != NULL); ret = psock->s_sockif->si_recvfrom(psock, buf, len, flags, from, fromlen); /* Set the socket state to idle */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); return ret; }
ssize_t psock_sendto(FAR struct socket *psock, FAR const void *buf, size_t len, int flags, FAR const struct sockaddr *to, socklen_t tolen) { #ifdef CONFIG_NET_UDP FAR struct uip_udp_conn *conn; #ifdef CONFIG_NET_IPv6 FAR const struct sockaddr_in6 *into = (const struct sockaddr_in6 *)to; #else FAR const struct sockaddr_in *into = (const struct sockaddr_in *)to; #endif struct sendto_s state; uip_lock_t save; int ret; #endif int err; /* If to is NULL or tolen is zero, then this function is same as send (for * connected socket types) */ if (!to || !tolen) { #ifdef CONFIG_NET_TCP return psock_send(psock, buf, len, flags); #else err = EINVAL; goto errout; #endif } /* Verify that a valid address has been provided */ #ifdef CONFIG_NET_IPv6 if (to->sa_family != AF_INET6 || tolen < sizeof(struct sockaddr_in6)) #else if (to->sa_family != AF_INET || tolen < sizeof(struct sockaddr_in)) #endif { err = EBADF; goto errout; } /* Verify that the psock corresponds to valid, allocated socket */ if (!psock || psock->s_crefs <= 0) { err = EBADF; goto errout; } /* If this is a connected socket, then return EISCONN */ if (psock->s_type != SOCK_DGRAM) { err = EISCONN; goto errout; } /* Perform the UDP sendto operation */ #ifdef CONFIG_NET_UDP /* Set the socket state to sending */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND); /* Initialize the state structure. This is done with interrupts * disabled because we don't want anything to happen until we * are ready. */ save = uip_lock(); memset(&state, 0, sizeof(struct sendto_s)); sem_init(&state.st_sem, 0, 0); state.st_buflen = len; state.st_buffer = buf; /* Set the initial time for calculating timeouts */ #ifdef CONFIG_NET_SENDTO_TIMEOUT state.st_sock = psock; state.st_time = clock_systimer(); #endif /* Setup the UDP socket */ conn = (struct uip_udp_conn *)psock->s_conn; ret = uip_udpconnect(conn, into); if (ret < 0) { uip_unlock(save); err = -ret; goto errout; } /* Set up the callback in the connection */ state.st_cb = uip_udpcallbackalloc(conn); if (state.st_cb) { state.st_cb->flags = UIP_POLL; state.st_cb->priv = (void*)&state; state.st_cb->event = sendto_interrupt; /* Notify the device driver of the availabilty of TX data */ netdev_txnotify(conn->ripaddr); /* Wait for either the receive to complete or for an error/timeout to occur. * NOTES: (1) uip_lockedwait will also terminate if a signal is received, (2) * interrupts may be disabled! They will be re-enabled while the task sleeps * and automatically re-enabled when the task restarts. */ uip_lockedwait(&state.st_sem); /* Make sure that no further interrupts are processed */ uip_udpcallbackfree(conn, state.st_cb); } uip_unlock(save); sem_destroy(&state.st_sem); /* Set the socket state to idle */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); /* Check for errors */ if (state.st_sndlen < 0) { err = -state.st_sndlen; goto errout; } /* Sucess */ return state.st_sndlen; #else err = ENOSYS; #endif errout: set_errno(err); return ERROR; }
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { FAR struct socket *psock = sockfd_socket(sockfd); FAR struct socket *pnewsock; FAR struct uip_conn *conn; struct accept_s state; #ifdef CONFIG_NET_IPv6 FAR struct sockaddr_in6 *inaddr = (struct sockaddr_in6 *)addr; #else FAR struct sockaddr_in *inaddr = (struct sockaddr_in *)addr; #endif uip_lock_t save; int newfd; int err; int ret; /* Verify that the sockfd corresponds to valid, allocated socket */ if (!psock || psock->s_crefs <= 0) { /* It is not a valid socket description. Distinguish between the cases * where sockfd is a just valid and when it is a valid file descriptor used * in the wrong context. */ #if CONFIG_NFILE_DESCRIPTORS > 0 if ((unsigned int)sockfd < CONFIG_NFILE_DESCRIPTORS) { err = ENOTSOCK; } else #endif { err = EBADF; } goto errout; } /* We have a socket descriptor, but it is a stream? */ if (psock->s_type != SOCK_STREAM) { err = EOPNOTSUPP; goto errout; } /* Is the socket listening for a connection? */ if (!_SS_ISLISTENING(psock->s_flags)) { err = EINVAL; goto errout; } /* Verify that a valid memory block has been provided to receive the * address */ if (addr) { #ifdef CONFIG_NET_IPv6 if (*addrlen < sizeof(struct sockaddr_in6)) #else if (*addrlen < sizeof(struct sockaddr_in)) #endif { err = EBADF; goto errout; } } /* Allocate a socket descriptor for the new connection now (so that it * cannot fail later) */ newfd = sockfd_allocate(0); if (newfd < 0) { err = ENFILE; goto errout; } pnewsock = sockfd_socket(newfd); if (!pnewsock) { err = ENFILE; goto errout_with_socket; } /* Check the backlog to see if there is a connection already pending for * this listener. */ save = uip_lock(); conn = (struct uip_conn *)psock->s_conn; #ifdef CONFIG_NET_TCPBACKLOG state.acpt_newconn = uip_backlogremove(conn); if (state.acpt_newconn) { /* Yes... get the address of the connected client */ nvdbg("Pending conn=%p\n", state.acpt_newconn); accept_tcpsender(state.acpt_newconn, inaddr); } /* In general, this uIP-based implementation will not support non-blocking * socket operations... except in a few cases: Here for TCP accept with backlog * enabled. If this socket is configured as non-blocking then return EAGAIN * if there is no pending connection in the backlog. */ else if (_SS_ISNONBLOCK(psock->s_flags)) { err = EAGAIN; goto errout_with_lock; } else #endif { /* Set the socket state to accepting */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_ACCEPT); /* Perform the TCP accept operation */ /* Initialize the state structure. This is done with interrupts * disabled because we don't want anything to happen until we * are ready. */ state.acpt_addr = inaddr; state.acpt_newconn = NULL; state.acpt_result = OK; sem_init(&state.acpt_sem, 0, 0); /* Set up the callback in the connection */ conn->accept_private = (void*)&state; conn->accept = accept_interrupt; /* Wait for the send to complete or an error to occur: NOTES: (1) * uip_lockedwait will also terminate if a signal is received, (2) interrupts * may be disabled! They will be re-enabled while the task sleeps and * automatically re-enabled when the task restarts. */ ret = uip_lockedwait(&state.acpt_sem); /* Make sure that no further interrupts are processed */ conn->accept_private = NULL; conn->accept = NULL; sem_destroy(&state. acpt_sem); /* Set the socket state to idle */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); /* Check for a errors. Errors are signaled by negative errno values * for the send length. */ if (state.acpt_result != 0) { err = state.acpt_result; goto errout_with_lock; } /* If uip_lockedwait failed, then we were probably reawakened by a signal. In * this case, uip_lockedwait will have set errno appropriately. */ if (ret < 0) { err = -ret; goto errout_with_lock; } } /* Initialize the socket structure and mark the socket as connected. * (The reference count on the new connection structure was set in the * interrupt handler). */ pnewsock->s_type = SOCK_STREAM; pnewsock->s_conn = state.acpt_newconn; pnewsock->s_flags |= _SF_CONNECTED; pnewsock->s_flags &= ~_SF_CLOSED; /* Begin monitoring for TCP connection events on the newly connected socket */ net_startmonitor(pnewsock); uip_unlock(save); return newfd; errout_with_lock: uip_unlock(save); errout_with_socket: sockfd_release(newfd); errout: errno = err; return ERROR; }
ssize_t psock_tcp_send(FAR struct socket *psock, FAR const void *buf, size_t len) { FAR struct tcp_conn_s *conn = (FAR struct tcp_conn_s *)psock->s_conn; struct send_s state; net_lock_t save; int err; int ret = OK; /* Verify that the sockfd corresponds to valid, allocated socket */ if (!psock || psock->s_crefs <= 0) { ndbg("ERROR: Invalid socket\n"); err = EBADF; goto errout; } /* If this is an un-connected socket, then return ENOTCONN */ if (psock->s_type != SOCK_STREAM || !_SS_ISCONNECTED(psock->s_flags)) { ndbg("ERROR: Not connected\n"); err = ENOTCONN; goto errout; } /* Make sure that we have the IP address mapping */ conn = (FAR struct tcp_conn_s *)psock->s_conn; DEBUGASSERT(conn); #if defined(CONFIG_NET_ARP_SEND) || defined(CONFIG_NET_ICMPv6_NEIGHBOR) #ifdef CONFIG_NET_ARP_SEND #ifdef CONFIG_NET_ICMPv6_NEIGHBOR if (psock->s_domain == PF_INET) #endif { /* Make sure that the IP address mapping is in the ARP table */ ret = arp_send(conn->u.ipv4.raddr); } #endif /* CONFIG_NET_ARP_SEND */ #ifdef CONFIG_NET_ICMPv6_NEIGHBOR #ifdef CONFIG_NET_ARP_SEND else #endif { /* Make sure that the IP address mapping is in the Neighbor Table */ ret = icmpv6_neighbor(conn->u.ipv6.raddr); } #endif /* CONFIG_NET_ICMPv6_NEIGHBOR */ /* Did we successfully get the address mapping? */ if (ret < 0) { ndbg("ERROR: Not reachable\n"); err = ENETUNREACH; goto errout; } #endif /* CONFIG_NET_ARP_SEND || CONFIG_NET_ICMPv6_NEIGHBOR */ /* Set the socket state to sending */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND); /* Perform the TCP send operation */ /* Initialize the state structure. This is done with interrupts * disabled because we don't want anything to happen until we * are ready. */ save = net_lock(); memset(&state, 0, sizeof(struct send_s)); (void)sem_init(&state.snd_sem, 0, 0); /* Doesn't really fail */ state.snd_sock = psock; /* Socket descriptor to use */ state.snd_buflen = len; /* Number of bytes to send */ state.snd_buffer = buf; /* Buffer to send from */ if (len > 0) { /* Allocate resources to receive a callback */ state.snd_cb = tcp_callback_alloc(conn); if (state.snd_cb) { /* Get the initial sequence number that will be used */ state.snd_isn = tcp_getsequence(conn->sndseq); /* There is no outstanding, unacknowledged data after this * initial sequence number. */ conn->unacked = 0; /* Set the initial time for calculating timeouts */ #ifdef CONFIG_NET_SOCKOPTS state.snd_time = clock_systimer(); #endif /* Set up the callback in the connection */ state.snd_cb->flags = (TCP_ACKDATA | TCP_REXMIT | TCP_POLL | TCP_DISCONN_EVENTS); state.snd_cb->priv = (FAR void *)&state; state.snd_cb->event = tcpsend_interrupt; /* Notify the device driver of the availability of TX data */ send_txnotify(psock, conn); /* Wait for the send to complete or an error to occur: NOTES: (1) * net_lockedwait will also terminate if a signal is received, (2) interrupts * may be disabled! They will be re-enabled while the task sleeps and * automatically re-enabled when the task restarts. */ ret = net_lockedwait(&state.snd_sem); /* Make sure that no further interrupts are processed */ tcp_callback_free(conn, state.snd_cb); } } sem_destroy(&state.snd_sem); net_unlock(save); /* Set the socket state to idle */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); /* Check for a errors. Errors are signalled by negative errno values * for the send length */ if (state.snd_sent < 0) { err = state.snd_sent; goto errout; } /* If net_lockedwait failed, then we were probably reawakened by a signal. In * this case, net_lockedwait will have set errno appropriately. */ if (ret < 0) { err = -ret; goto errout; } /* Return the number of bytes actually sent */ return state.snd_sent; errout: set_errno(err); return ERROR; }
ssize_t send(int sockfd, const void *buf, size_t len, int flags) { FAR struct socket *psock = sockfd_socket(sockfd); struct send_s state; uip_lock_t save; int err; int ret = OK; /* Verify that the sockfd corresponds to valid, allocated socket */ if (!psock || psock->s_crefs <= 0) { err = EBADF; goto errout; } /* If this is an un-connected socket, then return ENOTCONN */ if (psock->s_type != SOCK_STREAM || !_SS_ISCONNECTED(psock->s_flags)) { err = ENOTCONN; goto errout; } /* Set the socket state to sending */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND); /* Perform the TCP send operation */ /* Initialize the state structure. This is done with interrupts * disabled because we don't want anything to happen until we * are ready. */ save = uip_lock(); memset(&state, 0, sizeof(struct send_s)); (void)sem_init(&state. snd_sem, 0, 0); /* Doesn't really fail */ state.snd_sock = psock; /* Socket descriptor to use */ state.snd_buflen = len; /* Number of bytes to send */ state.snd_buffer = buf; /* Buffer to send from */ if (len > 0) { struct uip_conn *conn = (struct uip_conn*)psock->s_conn; /* Allocate resources to receive a callback */ state.snd_cb = uip_tcpcallbackalloc(conn); if (state.snd_cb) { /* Get the initial sequence number that will be used */ state.snd_isn = uip_tcpgetsequence(conn->sndseq); /* There is no outstanding, unacknowledged data after this * initial sequence number. */ conn->unacked = 0; /* Update the initial time for calculating timeouts */ #if defined(CONFIG_NET_SOCKOPTS) && !defined(CONFIG_DISABLE_CLOCK) state.snd_time = clock_systimer(); #endif /* Set up the callback in the connection */ state.snd_cb->flags = UIP_ACKDATA|UIP_REXMIT|UIP_POLL|UIP_CLOSE|UIP_ABORT|UIP_TIMEDOUT; state.snd_cb->priv = (void*)&state; state.snd_cb->event = send_interrupt; /* Notify the device driver of the availaibilty of TX data */ netdev_txnotify(&conn->ripaddr); /* Wait for the send to complete or an error to occur: NOTES: (1) * uip_lockedwait will also terminate if a signal is received, (2) interrupts * may be disabled! They will be re-enabled while the task sleeps and * automatically re-enabled when the task restarts. */ ret = uip_lockedwait(&state. snd_sem); /* Make sure that no further interrupts are processed */ uip_tcpcallbackfree(conn, state.snd_cb); } } sem_destroy(&state. snd_sem); uip_unlock(save); /* Set the socket state to idle */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); /* Check for a errors. Errors are signaled by negative errno values * for the send length */ if (state.snd_sent < 0) { err = state.snd_sent; goto errout; } /* If uip_lockedwait failed, then we were probably reawakened by a signal. In * this case, uip_lockedwait will have set errno appropriately. */ if (ret < 0) { err = -ret; goto errout; } /* Return the number of bytes actually sent */ return state.snd_sent; errout: *get_errno_ptr() = err; return ERROR; }
ssize_t psock_tcp_send(FAR struct socket *psock, FAR const void *buf, size_t len) { FAR struct tcp_conn_s *conn; net_lock_t save; ssize_t result = 0; int err; int ret = OK; if (!psock || psock->s_crefs <= 0) { ndbg("ERROR: Invalid socket\n"); err = EBADF; goto errout; } if (psock->s_type != SOCK_STREAM || !_SS_ISCONNECTED(psock->s_flags)) { ndbg("ERROR: Not connected\n"); err = ENOTCONN; goto errout; } /* Make sure that the IP address mapping is in the ARP table */ conn = (FAR struct tcp_conn_s *)psock->s_conn; #ifdef CONFIG_NET_ARP_SEND ret = arp_send(conn->ripaddr); if (ret < 0) { ndbg("ERROR: Not reachable\n"); err = ENETUNREACH; goto errout; } #endif /* Dump the incoming buffer */ BUF_DUMP("psock_tcp_send", buf, len); /* Set the socket state to sending */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND); save = net_lock(); if (len > 0) { /* Allocate resources to receive a callback */ if (!psock->s_sndcb) { psock->s_sndcb = tcp_callback_alloc(conn); } /* Test if the callback has been allocated */ if (!psock->s_sndcb) { /* A buffer allocation error occurred */ ndbg("ERROR: Failed to allocate callback\n"); result = -ENOMEM; } else { FAR struct tcp_wrbuffer_s *wrb; /* Set up the callback in the connection */ psock->s_sndcb->flags = (TCP_ACKDATA | TCP_REXMIT | TCP_POLL | TCP_CLOSE | TCP_ABORT | TCP_TIMEDOUT); psock->s_sndcb->priv = (void*)psock; psock->s_sndcb->event = psock_send_interrupt; /* Allocate an write buffer */ wrb = tcp_wrbuffer_alloc(); if (wrb) { /* Initialize the write buffer */ WRB_SEQNO(wrb) = (unsigned)-1; WRB_NRTX(wrb) = 0; WRB_COPYIN(wrb, (FAR uint8_t *)buf, len); /* Dump I/O buffer chain */ WRB_DUMP("I/O buffer chain", wrb, WRB_PKTLEN(wrb), 0); /* psock_send_interrupt() will send data in FIFO order from the * conn->write_q */ sq_addlast(&wrb->wb_node, &conn->write_q); nvdbg("Queued WRB=%p pktlen=%u write_q(%p,%p)\n", wrb, WRB_PKTLEN(wrb), conn->write_q.head, conn->write_q.tail); /* Notify the device driver of the availability of TX data */ #ifdef CONFIG_NET_MULTILINK netdev_txnotify(conn->lipaddr, conn->ripaddr); #else netdev_txnotify(conn->ripaddr); #endif result = len; } /* A buffer allocation error occurred */ else { ndbg("ERROR: Failed to allocate write buffer\n"); result = -ENOMEM; } } } net_unlock(save); /* Set the socket state to idle */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); /* Check for a errors. Errors are signaled by negative errno values * for the send length */ if (result < 0) { err = result; goto errout; } /* If net_lockedwait failed, then we were probably reawakened by a signal. * In this case, net_lockedwait will have set errno appropriately. */ if (ret < 0) { err = -ret; goto errout; } /* Return the number of bytes actually sent */ return result; errout: set_errno(err); return ERROR; }
ssize_t net_sendfile(int outfd, struct file *infile, off_t *offset, size_t count) { FAR struct socket *psock = sockfd_socket(outfd); FAR struct tcp_conn_s *conn; struct sendfile_s state; net_lock_t save; int err; /* Verify that the sockfd corresponds to valid, allocated socket */ if (!psock || psock->s_crefs <= 0) { ndbg("ERROR: Invalid socket\n"); err = EBADF; goto errout; } /* If this is an un-connected socket, then return ENOTCONN */ if (psock->s_type != SOCK_STREAM || !_SS_ISCONNECTED(psock->s_flags)) { ndbg("ERROR: Not connected\n"); err = ENOTCONN; goto errout; } /* Make sure that we have the IP address mapping */ conn = (FAR struct tcp_conn_s *)psock->s_conn; DEBUGASSERT(conn); #if defined(CONFIG_NET_ARP_SEND) || defined(CONFIG_NET_ICMPv6_NEIGHBOR) #ifdef CONFIG_NET_ARP_SEND #ifdef CONFIG_NET_ICMPv6_NEIGHBOR if (psock->s_domain == PF_INET) #endif { /* Make sure that the IP address mapping is in the ARP table */ ret = arp_send(conn->u.ipv4.raddr); } #endif /* CONFIG_NET_ARP_SEND */ #ifdef CONFIG_NET_ICMPv6_NEIGHBOR #ifdef CONFIG_NET_ARP_SEND else #endif { /* Make sure that the IP address mapping is in the Neighbor Table */ ret = icmpv6_neighbor(conn->u.ipv6.raddr); } #endif /* CONFIG_NET_ICMPv6_NEIGHBOR */ /* Did we successfully get the address mapping? */ if (ret < 0) { ndbg("ERROR: Not reachable\n"); err = ENETUNREACH; goto errout; } #endif /* CONFIG_NET_ARP_SEND || CONFIG_NET_ICMPv6_NEIGHBOR */ /* Set the socket state to sending */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND); /* Initialize the state structure. This is done with interrupts * disabled because we don't want anything to happen until we * are ready. */ save = net_lock(); memset(&state, 0, sizeof(struct sendfile_s)); sem_init(&state. snd_sem, 0, 0); /* Doesn't really fail */ state.snd_sock = psock; /* Socket descriptor to use */ state.snd_foffset = offset ? *offset : 0; /* Input file offset */ state.snd_flen = count; /* Number of bytes to send */ state.snd_file = infile; /* File to read from */ /* Allocate resources to receive a callback */ state.snd_datacb = tcp_callback_alloc(conn); if (state.snd_datacb == NULL) { nlldbg("Failed to allocate data callback\n"); err = ENOMEM; goto errout_locked; } state.snd_ackcb = tcp_callback_alloc(conn); if (state.snd_ackcb == NULL) { nlldbg("Failed to allocate ack callback\n"); err = ENOMEM; goto errout_datacb; } /* Get the initial sequence number that will be used */ state.snd_isn = tcp_getsequence(conn->sndseq); /* There is no outstanding, unacknowledged data after this * initial sequence number. */ conn->unacked = 0; #ifdef CONFIG_NET_SOCKOPTS /* Set the initial time for calculating timeouts */ state.snd_time = clock_systimer(); #endif /* Set up the ACK callback in the connection */ state.snd_ackcb->flags = (TCP_ACKDATA | TCP_REXMIT | TCP_DISCONN_EVENTS); state.snd_ackcb->priv = (FAR void *)&state; state.snd_ackcb->event = ack_interrupt; /* Perform the TCP send operation */ do { state.snd_datacb->flags = TCP_POLL; state.snd_datacb->priv = (FAR void *)&state; state.snd_datacb->event = sendfile_interrupt; /* Notify the device driver of the availability of TX data */ sendfile_txnotify(psock, conn); net_lockedwait(&state.snd_sem); } while (state.snd_sent >= 0 && state.snd_acked < state.snd_flen); /* Set the socket state to idle */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); tcp_callback_free(conn, state.snd_ackcb); errout_datacb: tcp_callback_free(conn, state.snd_datacb); errout_locked: sem_destroy(&state. snd_sem); net_unlock(save); errout: if (err) { set_errno(err); return ERROR; } else if (state.snd_sent < 0) { set_errno(-state.snd_sent); return ERROR; } else { return state.snd_sent; } }
ssize_t psock_tcp_send(FAR struct socket *psock, FAR const void *buf, size_t len) { FAR struct tcp_conn_s *conn; FAR struct tcp_wrbuffer_s *wrb; net_lock_t save; ssize_t result = 0; int errcode; int ret = OK; if (!psock || psock->s_crefs <= 0) { nerr("ERROR: Invalid socket\n"); errcode = EBADF; goto errout; } if (psock->s_type != SOCK_STREAM || !_SS_ISCONNECTED(psock->s_flags)) { nerr("ERROR: Not connected\n"); errcode = ENOTCONN; goto errout; } /* Make sure that we have the IP address mapping */ conn = (FAR struct tcp_conn_s *)psock->s_conn; DEBUGASSERT(conn); #if defined(CONFIG_NET_ARP_SEND) || defined(CONFIG_NET_ICMPv6_NEIGHBOR) #ifdef CONFIG_NET_ARP_SEND #ifdef CONFIG_NET_ICMPv6_NEIGHBOR if (psock->s_domain == PF_INET) #endif { /* Make sure that the IP address mapping is in the ARP table */ ret = arp_send(conn->u.ipv4.raddr); } #endif /* CONFIG_NET_ARP_SEND */ #ifdef CONFIG_NET_ICMPv6_NEIGHBOR #ifdef CONFIG_NET_ARP_SEND else #endif { /* Make sure that the IP address mapping is in the Neighbor Table */ ret = icmpv6_neighbor(conn->u.ipv6.raddr); } #endif /* CONFIG_NET_ICMPv6_NEIGHBOR */ /* Did we successfully get the address mapping? */ if (ret < 0) { nerr("ERROR: Not reachable\n"); errcode = ENETUNREACH; goto errout; } #endif /* CONFIG_NET_ARP_SEND || CONFIG_NET_ICMPv6_NEIGHBOR */ /* Dump the incoming buffer */ BUF_DUMP("psock_tcp_send", buf, len); /* Set the socket state to sending */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND); if (len > 0) { /* Allocate a write buffer. Careful, the network will be momentarily * unlocked here. */ save = net_lock(); wrb = tcp_wrbuffer_alloc(); if (!wrb) { /* A buffer allocation error occurred */ nerr("ERROR: Failed to allocate write buffer\n"); errcode = ENOMEM; goto errout_with_lock; } /* Allocate resources to receive a callback */ if (!psock->s_sndcb) { psock->s_sndcb = tcp_callback_alloc(conn); } /* Test if the callback has been allocated */ if (!psock->s_sndcb) { /* A buffer allocation error occurred */ nerr("ERROR: Failed to allocate callback\n"); errcode = ENOMEM; goto errout_with_wrb; } /* Set up the callback in the connection */ psock->s_sndcb->flags = (TCP_ACKDATA | TCP_REXMIT | TCP_POLL | TCP_DISCONN_EVENTS); psock->s_sndcb->priv = (FAR void *)psock; psock->s_sndcb->event = psock_send_interrupt; /* Initialize the write buffer */ WRB_SEQNO(wrb) = (unsigned)-1; WRB_NRTX(wrb) = 0; result = WRB_COPYIN(wrb, (FAR uint8_t *)buf, len); /* Dump I/O buffer chain */ WRB_DUMP("I/O buffer chain", wrb, WRB_PKTLEN(wrb), 0); /* psock_send_interrupt() will send data in FIFO order from the * conn->write_q */ sq_addlast(&wrb->wb_node, &conn->write_q); ninfo("Queued WRB=%p pktlen=%u write_q(%p,%p)\n", wrb, WRB_PKTLEN(wrb), conn->write_q.head, conn->write_q.tail); /* Notify the device driver of the availability of TX data */ send_txnotify(psock, conn); net_unlock(save); } /* Set the socket state to idle */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); /* Check for errors. Errors are signalled by negative errno values * for the send length */ if (result < 0) { errcode = result; goto errout; } /* If net_lockedwait failed, then we were probably reawakened by a signal. * In this case, net_lockedwait will have set errno appropriately. */ if (ret < 0) { errcode = -ret; goto errout; } /* Return the number of bytes actually sent */ return result; errout_with_wrb: tcp_wrbuffer_release(wrb); errout_with_lock: net_unlock(save); errout: set_errno(errcode); return ERROR; }
ssize_t psock_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, int flags,FAR struct sockaddr *from, FAR socklen_t *fromlen) { #if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_TCP) #ifdef CONFIG_NET_IPv6 FAR struct sockaddr_in6 *infrom = (struct sockaddr_in6 *)from; #else FAR struct sockaddr_in *infrom = (struct sockaddr_in *)from; #endif #endif ssize_t ret; int err; /* Verify that non-NULL pointers were passed */ #ifdef CONFIG_DEBUG if (!buf) { err = EINVAL; goto errout; } #endif /* Verify that the sockfd corresponds to valid, allocated socket */ if (!psock || psock->s_crefs <= 0) { err = EBADF; goto errout; } /* If a 'from' address has been provided, verify that it is large * enough to hold this address family. */ if (from) { #ifdef CONFIG_NET_IPv6 if (*fromlen < sizeof(struct sockaddr_in6)) #else if (*fromlen < sizeof(struct sockaddr_in)) #endif { err = EINVAL; goto errout; } } /* Set the socket state to receiving */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_RECV); /* Perform the TCP/IP or UDP recv() operation */ #if defined(CONFIG_NET_UDP) && defined(CONFIG_NET_TCP) if (psock->s_type == SOCK_STREAM) { ret = tcp_recvfrom(psock, buf, len, infrom); } else { ret = udp_recvfrom(psock, buf, len, infrom); } #elif defined(CONFIG_NET_TCP) ret = tcp_recvfrom(psock, buf, len, infrom); #elif defined(CONFIG_NET_UDP) ret = udp_recvfrom(psock, buf, len, infrom); #else ret = -ENOSYS; #endif /* Set the socket state to idle */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); /* Handle returned errors */ if (ret < 0) { err = -ret; goto errout; } /* Success return */ return ret; errout: errno = err; return ERROR; }
int psock_tcp_accept(FAR struct socket *psock, FAR struct sockaddr *addr, FAR socklen_t *addrlen, FAR void **newconn) { FAR struct tcp_conn_s *conn; struct accept_s state; int ret; DEBUGASSERT(psock && newconn); /* Check the backlog to see if there is a connection already pending for * this listener. */ conn = (FAR struct tcp_conn_s *)psock->s_conn; #ifdef CONFIG_NET_TCPBACKLOG state.acpt_newconn = tcp_backlogremove(conn); if (state.acpt_newconn) { /* Yes... get the address of the connected client */ ninfo("Pending conn=%p\n", state.acpt_newconn); accept_tcpsender(psock, state.acpt_newconn, addr, addrlen); } /* In general, this implementation will not support non-blocking socket * operations... except in a few cases: Here for TCP accept with * backlog enabled. If this socket is configured as non-blocking then * return EAGAIN if there is no pending connection in the backlog. */ else if (_SS_ISNONBLOCK(psock->s_flags)) { return -EAGAIN; } else #endif { /* Set the socket state to accepting */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_ACCEPT); /* Perform the TCP accept operation */ /* Initialize the state structure. This is done with the network * locked because we don't want anything to happen until we are * ready. */ state.acpt_sock = psock; state.acpt_addr = addr; state.acpt_addrlen = addrlen; state.acpt_newconn = NULL; state.acpt_result = OK; /* This semaphore is used for signaling and, hence, should not have * priority inheritance enabled. */ nxsem_init(&state.acpt_sem, 0, 0); nxsem_setprotocol(&state.acpt_sem, SEM_PRIO_NONE); /* Set up the callback in the connection */ conn->accept_private = (FAR void *)&state; conn->accept = accept_eventhandler; /* Wait for the send to complete or an error to occur: NOTES: * net_lockedwait will also terminate if a signal is received. */ ret = net_lockedwait(&state.acpt_sem); /* Make sure that no further events are processed */ conn->accept_private = NULL; conn->accept = NULL; nxsem_destroy(&state. acpt_sem); /* Set the socket state to idle */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); /* Check for a errors. Errors are signalled by negative errno values * for the send length. */ if (state.acpt_result != 0) { DEBUGASSERT(state.acpt_result > 0); return -state.acpt_result; } /* If net_lockedwait failed, then we were probably reawakened by a * signal. In this case, net_lockedwait will have returned negated * errno appropriately. */ if (ret < 0) { return ret; } } *newconn = (FAR void *)state.acpt_newconn; return OK; }
ssize_t ieee802154_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, int flags, FAR struct sockaddr *from, FAR socklen_t *fromlen) { FAR struct ieee802154_conn_s *conn = (FAR struct ieee802154_conn_s *)psock->s_conn; FAR struct radio_driver_s *radio; struct ieee802154_recvfrom_s state; ssize_t ret; /* If a 'from' address has been provided, verify that it is large * enough to hold this address family. */ if (from != NULL && *fromlen < sizeof(struct sockaddr_ieee802154_s)) { return -EINVAL; } if (psock->s_type != SOCK_DGRAM) { nerr("ERROR: Unsupported socket type: %d\n", psock->s_type); return -EPROTONOSUPPORT; } /* Perform the packet recvfrom() operation */ /* Initialize the state structure. This is done with the network * locked because we don't want anything to happen until we are ready. */ net_lock(); memset(&state, 0, sizeof(struct ieee802154_recvfrom_s)); state.ir_buflen = len; state.ir_buffer = buf; state.ir_sock = psock; state.ir_from = from; /* Get the device driver that will service this transfer */ radio = ieee802154_find_device(conn, &conn->laddr); if (radio == NULL) { ret = -ENODEV; goto errout_with_lock; } /* Before we wait for data, let's check if there are already frame(s) * waiting in the RX queue. */ ret = ieee802154_recvfrom_rxqueue(radio, &state); if (ret > 0) { /* Good newe! We have a frame and we are done. */ net_unlock(); return ret; } /* We will have to wait. This semaphore is used for signaling and, * hence, should not have priority inheritance enabled. */ (void)nxsem_init(&state.ir_sem, 0, 0); /* Doesn't really fail */ (void)nxsem_setprotocol(&state.ir_sem, SEM_PRIO_NONE); /* Set the socket state to receiving */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_RECV); /* Set up the callback in the connection */ state.ir_cb = ieee802154_callback_alloc(&radio->r_dev, conn); if (state.ir_cb) { state.ir_cb->flags = (IEEE802154_NEWDATA | IEEE802154_POLL); state.ir_cb->priv = (FAR void *)&state; state.ir_cb->event = ieee802154_recvfrom_eventhandler; /* Wait for either the receive to complete or for an error/timeout to * occur. NOTES: (1) net_lockedwait will also terminate if a signal * is received, (2) the network is locked! It will be un-locked while * the task sleeps and automatically re-locked when the task restarts. */ (void)net_lockedwait(&state.ir_sem); /* Make sure that no further events are processed */ ieee802154_callback_free(&radio->r_dev, conn, state.ir_cb); ret = state.ir_result; } else { ret = -EBUSY; } /* Set the socket state to idle */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); nxsem_destroy(&state.ir_sem); errout_with_lock: net_unlock(); return ret; }
ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf, size_t len, int flags, FAR const struct sockaddr *to, socklen_t tolen) { FAR struct udp_conn_s *conn; FAR struct net_driver_s *dev; struct sendto_s state; net_lock_t save; int ret; #if defined(CONFIG_NET_ARP_SEND) || defined(CONFIG_NET_ICMPv6_NEIGHBOR) #ifdef CONFIG_NET_ARP_SEND #ifdef CONFIG_NET_ICMPv6_NEIGHBOR if (psock->s_domain == PF_INET) #endif { FAR const struct sockaddr_in *into; /* Make sure that the IP address mapping is in the ARP table */ into = (FAR const struct sockaddr_in *)to; ret = arp_send(into->sin_addr.s_addr); } #endif /* CONFIG_NET_ARP_SEND */ #ifdef CONFIG_NET_ICMPv6_NEIGHBOR #ifdef CONFIG_NET_ARP_SEND else #endif { FAR const struct sockaddr_in6 *into; /* Make sure that the IP address mapping is in the Neighbor Table */ into = (FAR const struct sockaddr_in6 *)to; ret = icmpv6_neighbor(into->sin6_addr.s6_addr16); } #endif /* CONFIG_NET_ICMPv6_NEIGHBOR */ /* Did we successfully get the address mapping? */ if (ret < 0) { ndbg("ERROR: Peer not reachable\n"); return -ENETUNREACH; } #endif /* CONFIG_NET_ARP_SEND || CONFIG_NET_ICMPv6_NEIGHBOR */ /* Set the socket state to sending */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND); /* Initialize the state structure. This is done with interrupts * disabled because we don't want anything to happen until we * are ready. */ save = net_lock(); memset(&state, 0, sizeof(struct sendto_s)); sem_init(&state.st_sem, 0, 0); state.st_buflen = len; state.st_buffer = buf; #if defined(CONFIG_NET_SENDTO_TIMEOUT) || defined(NEED_IPDOMAIN_SUPPORT) /* Save the reference to the socket structure if it will be needed for * asynchronous processing. */ state.st_sock = psock; #endif #ifdef CONFIG_NET_SENDTO_TIMEOUT /* Set the initial time for calculating timeouts */ state.st_time = clock_systimer(); #endif /* Setup the UDP socket. udp_connect will set the remote address in the * connection structure. */ conn = (FAR struct udp_conn_s *)psock->s_conn; DEBUGASSERT(conn); ret = udp_connect(conn, to); if (ret < 0) { ndbg("ERROR: udp_connect failed: %d\n", ret); goto errout_with_lock; } /* Get the device that will handle the remote packet transfers. This * should never be NULL. */ dev = udp_find_raddr_device(conn); if (dev == NULL) { ndbg("ERROR: udp_find_raddr_device failed\n"); ret = -ENETUNREACH; goto errout_with_lock; } /* Set up the callback in the connection */ state.st_cb = udp_callback_alloc(dev, conn); if (state.st_cb) { state.st_cb->flags = (UDP_POLL | NETDEV_DOWN); state.st_cb->priv = (void*)&state; state.st_cb->event = sendto_interrupt; /* Notify the device driver of the availability of TX data */ netdev_txnotify_dev(dev); /* Wait for either the receive to complete or for an error/timeout to occur. * NOTES: (1) net_lockedwait will also terminate if a signal is received, (2) * interrupts may be disabled! They will be re-enabled while the task sleeps * and automatically re-enabled when the task restarts. */ net_lockedwait(&state.st_sem); /* Make sure that no further interrupts are processed */ udp_callback_free(dev, conn, state.st_cb); } /* The result of the sendto operation is the number of bytes transferred */ ret = state.st_sndlen; errout_with_lock: /* Release the semaphore */ sem_destroy(&state.st_sem); /* Set the socket state back to idle */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); /* Unlock the network and return the result of the sendto() operation */ net_unlock(save); return ret; }
ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len, int flags) { uip_lock_t save; size_t completed = 0; int err; int ret = OK; if (!psock || psock->s_crefs <= 0) { err = EBADF; goto errout; } if (psock->s_type != SOCK_STREAM || !_SS_ISCONNECTED(psock->s_flags)) { err = ENOTCONN; goto errout; } /* Set the socket state to sending */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND); save = uip_lock(); if (len > 0) { struct uip_conn *conn = (struct uip_conn*)psock->s_conn; if (!psock->s_sndcb) { psock->s_sndcb = uip_tcpcallbackalloc(conn); /* Set up the callback in the connection */ psock->s_sndcb->flags = (UIP_ACKDATA | UIP_REXMIT |UIP_POLL | \ UIP_CLOSE | UIP_ABORT | UIP_TIMEDOUT); psock->s_sndcb->priv = (void*)psock; psock->s_sndcb->event = send_interrupt; } /* Allocate resources to receive a callback */ while (completed < len) { FAR struct uip_wrbuffer_s *segment = uip_tcpwrbuffer_alloc(NULL); if (segment) { size_t cnt; segment->wb_seqno = (unsigned)-1; segment->wb_nrtx = 0; if (len - completed > CONFIG_NET_TCP_WRITE_BUFSIZE) { cnt = CONFIG_NET_TCP_WRITE_BUFSIZE; } else { cnt = len - completed; } segment->wb_nbytes = cnt; memcpy(segment->wb_buffer, (char*)buf + completed, cnt); completed += cnt; /* send_interrupt() will refer to all the write buffer by * conn->writebuff */ sq_addlast(&segment->wb_node, &conn->write_q); /* Notify the device driver of the availability of TX data */ netdev_txnotify(conn->ripaddr); } } } uip_unlock(save); /* Set the socket state to idle */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); /* Check for a errors. Errors are signaled by negative errno values * for the send length */ if (completed < 0) { err = completed; goto errout; } /* If uip_lockedwait failed, then we were probably reawakened by a signal. * In this case, uip_lockedwait will have set errno appropriately. */ if (ret < 0) { err = -ret; goto errout; } /* Return the number of bytes actually sent */ return completed; errout: set_errno(err); return ERROR; }
int psock_tcp_accept(FAR struct socket *psock, FAR struct sockaddr *addr, FAR socklen_t *addrlen, FAR void **newconn) { FAR struct tcp_conn_s *conn; struct accept_s state; int ret; DEBUGASSERT(psock && newconn); /* Check the backlog to see if there is a connection already pending for * this listener. */ conn = (FAR struct tcp_conn_s *)psock->s_conn; #ifdef CONFIG_NET_TCPBACKLOG state.acpt_newconn = tcp_backlogremove(conn); if (state.acpt_newconn) { /* Yes... get the address of the connected client */ nvdbg("Pending conn=%p\n", state.acpt_newconn); accept_tcpsender(psock, state.acpt_newconn, addr, addrlen); } /* In general, this uIP-based implementation will not support non-blocking * socket operations... except in a few cases: Here for TCP accept with * backlog enabled. If this socket is configured as non-blocking then * return EAGAIN if there is no pending connection in the backlog. */ else if (_SS_ISNONBLOCK(psock->s_flags)) { return -EAGAIN; } else #endif { /* Set the socket state to accepting */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_ACCEPT); /* Perform the TCP accept operation */ /* Initialize the state structure. This is done with interrupts * disabled because we don't want anything to happen until we * are ready. */ state.acpt_sock = psock; state.acpt_addr = addr; state.acpt_addrlen = addrlen; state.acpt_newconn = NULL; state.acpt_result = OK; sem_init(&state.acpt_sem, 0, 0); /* Set up the callback in the connection */ conn->accept_private = (FAR void *)&state; conn->accept = accept_interrupt; /* Wait for the send to complete or an error to occur: NOTES: (1) * net_lockedwait will also terminate if a signal is received, (2) * interrupts may be disabled! They will be re-enabled while the * task sleeps and automatically re-enabled when the task restarts. */ ret = net_lockedwait(&state.acpt_sem); if (ret < 0) { /* The value returned by net_lockedwait() the same as the value * returned by sem_wait(): Zero (OK) is returned on success; -1 * (ERROR) is returned on a failure with the errno value set * appropriately. * * We have to preserve the errno value here because it may be * altered by intervening operations. */ ret = -get_errno(); DEBUGASSERT(ret < 0); } /* Make sure that no further interrupts are processed */ conn->accept_private = NULL; conn->accept = NULL; sem_destroy(&state. acpt_sem); /* Set the socket state to idle */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); /* Check for a errors. Errors are signalled by negative errno values * for the send length. */ if (state.acpt_result != 0) { DEBUGASSERT(state.acpt_result > 0); return -state.acpt_result; } /* If net_lockedwait failed, then we were probably reawakened by a * signal. In this case, logic above will have set 'ret' to the * errno value returned by net_lockedwait(). */ if (ret < 0) { return ret; } } *newconn = (FAR void *)state.acpt_newconn; return OK; }