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 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; }