ssize_t psock_udp_send(FAR struct socket *psock, FAR const void *buf, size_t len) { FAR struct udp_conn_s *conn; union { struct sockaddr addr; #ifdef CONFIG_NET_IPv4 struct sockaddr_in addr4; #endif #ifdef CONFIG_NET_IPv6 struct sockaddr_in6 addr6; #endif } to; socklen_t tolen; DEBUGASSERT(psock != NULL && psock->s_crefs > 0); DEBUGASSERT(psock->s_type != SOCK_DGRAM); conn = (FAR struct udp_conn_s *)psock->s_conn; DEBUGASSERT(conn); /* Was the UDP socket connected via connect()? */ if (!_SS_ISCONNECTED(psock->s_flags)) { /* No, then it is not legal to call send() with this socket. */ return -ENOTCONN; } /* Yes, then let psock_sendto to the work */ #ifdef CONFIG_NET_IPv4 #ifdef CONFIG_NET_IPv6 if (conn->domain == PF_INET) #endif { tolen = sizeof(struct sockaddr_in); to.addr4.sin_family = AF_INET; to.addr4.sin_port = conn->rport; net_ipv4addr_copy(to.addr4.sin_addr.s_addr, conn->u.ipv4.raddr); } #endif /* CONFIG_NET_IPv4 */ #ifdef CONFIG_NET_IPv6 #ifdef CONFIG_NET_IPv4 else #endif { tolen = sizeof(struct sockaddr_in6); to.addr6.sin6_family = AF_INET6; to.addr6.sin6_port = conn->rport; net_ipv6addr_copy(to.addr6.sin6_addr.s6_addr, conn->u.ipv6.raddr); } #endif /* CONFIG_NET_IPv6 */ return psock_udp_sendto(psock, buf, len, 0, &to.addr, tolen); }
static inline void netclose_disconnect(FAR struct socket *psock) { struct tcp_close_s state; uip_lock_t flags; /* Interrupts are disabled here to avoid race conditions */ flags = uip_lock(); /* Is the TCP socket in a connected state? */ if (_SS_ISCONNECTED(psock->s_flags)) { struct uip_conn *conn = (struct uip_conn*)psock->s_conn; /* Check for the case where the host beat us and disconnected first */ if (conn->tcpstateflags == UIP_ESTABLISHED) { /* Set up to receive TCP data event callbacks */ state.cl_cb = uip_tcpcallbackalloc(conn); if (state.cl_cb) { state.cl_psock = psock; sem_init(&state.cl_sem, 0, 0); state.cl_cb->flags = UIP_NEWDATA|UIP_POLL|UIP_CLOSE|UIP_ABORT; state.cl_cb->priv = (void*)&state; state.cl_cb->event = netclose_interrupt; /* Notify the device driver of the availaibilty of TX data */ netdev_txnotify(&conn->ripaddr); /* Wait for the disconnect event */ (void)uip_lockedwait(&state.cl_sem); /* We are now disconnected */ sem_destroy(&state.cl_sem); uip_tcpcallbackfree(conn, state.cl_cb); } } } uip_unlock(flags); }
int psock_tcp_cansend(FAR struct socket *psock) { if (!psock || psock->s_crefs <= 0) { nerr("ERROR: Invalid socket\n"); return -EBADF; } if (psock->s_type != SOCK_STREAM || !_SS_ISCONNECTED(psock->s_flags)) { nerr("ERROR: Not connected\n"); return -ENOTCONN; } if (tcp_wrbuffer_test()) { return -EWOULDBLOCK; } return OK; }
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; }
int tcp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds) { FAR struct tcp_conn_s *conn = psock->s_conn; FAR struct tcp_poll_s *info; FAR struct devif_callback_s *cb; net_lock_t flags; int ret; /* Sanity check */ #ifdef CONFIG_DEBUG if (!conn || !fds) { return -EINVAL; } #endif /* Allocate a container to hold the poll information */ info = (FAR struct tcp_poll_s *)kmm_malloc(sizeof(struct tcp_poll_s)); if (!info) { return -ENOMEM; } /* Some of the following must be atomic */ flags = net_lock(); /* Allocate a TCP/IP callback structure */ cb = tcp_callback_alloc(conn); if (!cb) { ret = -EBUSY; goto errout_with_lock; } /* Initialize the poll info container */ info->psock = psock; info->fds = fds; info->cb = cb; /* Initialize the callback structure. Save the reference to the info * structure as callback private data so that it will be available during * callback processing. */ cb->flags = (TCP_NEWDATA | TCP_BACKLOG | TCP_POLL | TCP_CLOSE | TCP_ABORT | TCP_TIMEDOUT); cb->priv = (FAR void *)info; cb->event = tcp_poll_interrupt; /* Save the reference in the poll info structure as fds private as well * for use durring poll teardown as well. */ fds->priv = (FAR void *)info; #ifdef CONFIG_NET_TCPBACKLOG /* Check for read data or backlogged connection availability now */ if (!IOB_QEMPTY(&conn->readahead) || tcp_backlogavailable(conn)) #else /* Check for read data availability now */ if (!IOB_QEMPTY(&conn->readahead)) #endif { /* Normal data may be read without blocking. */ fds->revents |= (POLLRDNORM & fds->events); } /* Check for a loss of connection events. We need to be careful here. * There are four possibilities: * * 1) The socket is connected and we are waiting for data availability * events. * * __SS_ISCONNECTED(f) == true * __SS_ISLISTENING(f) == false * __SS_ISCLOSED(f) == false * * Action: Wait for data availability events * * 2) This is a listener socket that was never connected and we are * waiting for connection events. * * __SS_ISCONNECTED(f) == false * __SS_ISLISTENING(f) == true * __SS_ISCLOSED(f) == false * * Action: Wait for connection events * * 3) This socket was previously connected, but the peer has gracefully * closed the connection. * * __SS_ISCONNECTED(f) == false * __SS_ISLISTENING(f) == false * __SS_ISCLOSED(f) == true * * Action: Return with POLLHUP|POLLERR events * * 4) This socket was previously connected, but we lost the connection * due to some exceptional event. * * __SS_ISCONNECTED(f) == false * __SS_ISLISTENING(f) == false * __SS_ISCLOSED(f) == false * * Action: Return with POLLHUP|POLLERR events */ if (!_SS_ISCONNECTED(psock->s_flags) && !_SS_ISLISTENING(psock->s_flags)) { /* We were previously connected but lost the connection either due * to a graceful shutdown by the remote peer or because of some * exceptional event. */ fds->revents |= (POLLERR | POLLHUP); } /* Check if any requested events are already in effect */ if (fds->revents != 0) { /* Yes.. then signal the poll logic */ sem_post(fds->sem); } net_unlock(flags); return OK; errout_with_lock: kmm_free(info); net_unlock(flags); return ret; }
static inline int net_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds) { FAR struct uip_conn *conn = psock->s_conn; FAR struct net_poll_s *info; FAR struct uip_callback_s *cb; uip_lock_t flags; int ret; /* Sanity check */ #ifdef CONFIG_DEBUG if (!conn || !fds) { return -EINVAL; } #endif /* Allocate a container to hold the poll information */ info = (FAR struct net_poll_s *)kmalloc(sizeof(struct net_poll_s)); if (!info) { return -ENOMEM; } /* Some of the following must be atomic */ flags = uip_lock(); /* Allocate a TCP/IP callback structure */ cb = uip_tcpcallbackalloc(conn); if (!cb) { ret = -EBUSY; goto errout_with_lock; } /* Initialize the poll info container */ info->psock = psock; info->fds = fds; info->cb = cb; /* Initialize the callback structure. Save the reference to the info * structure as callback private data so that it will be available during * callback processing. */ cb->flags = (UIP_NEWDATA|UIP_BACKLOG|UIP_POLL|UIP_CLOSE|UIP_ABORT|UIP_TIMEDOUT); cb->priv = (FAR void *)info; cb->event = poll_interrupt; /* Save the reference in the poll info structure as fds private as well * for use durring poll teardown as well. */ fds->priv = (FAR void *)info; #ifdef CONFIG_NET_TCPBACKLOG /* Check for read data or backlogged connection availability now */ if (!sq_empty(&conn->readahead) || uip_backlogavailable(conn)) #else /* Check for read data availability now */ if (!sq_empty(&conn->readahead)) #endif { fds->revents |= (POLLOUT & fds->events); } /* Check for a loss of connection events */ if (!_SS_ISCONNECTED(psock->s_flags)) { fds->revents |= (POLLERR | POLLHUP); } /* Check if any requested events are already in effect */ if (fds->revents != 0) { /* Yes.. then signal the poll logic */ sem_post(fds->sem); } uip_unlock(flags); return OK; errout_with_lock: kfree(info); uip_unlock(flags); return ret; }
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; }
static ssize_t tcp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, FAR struct sockaddr_in *infrom ) #endif { struct recvfrom_s state; uip_lock_t save; int ret; /* 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(); recvfrom_init(psock, buf, len, infrom, &state); /* Handle any any TCP data already buffered in a read-ahead buffer. NOTE * that there may be read-ahead data to be retrieved even after the * socket has been disconnected. */ #if CONFIG_NET_NTCP_READAHEAD_BUFFERS > 0 recvfrom_readahead(&state); /* The default return value is the number of bytes that we just copied into * the user buffer. We will return this if the socket has become disconnected * or if the user request was completely satisfied with data from the readahead * buffers. */ ret = state.rf_recvlen; #else /* Otherwise, the default return value of zero is used (only for the case * where len == state.rf_buflen is zero). */ ret = 0; #endif /* Verify that the SOCK_STREAM has been and still is connected */ if (!_SS_ISCONNECTED(psock->s_flags)) { /* Was any data transferred from the readahead buffer after we were * disconnected? If so, then return the number of bytes received. We * will wait to return end disconnection indications the next time that * recvfrom() is called. * * If no data was received (i.e., ret == 0 -- it will not be negative) * and the connection was gracefully closed by the remote peer, then return * success. If rf_recvlen is zero, the caller of recvfrom() will get an * end-of-file indication. */ #if CONFIG_NET_NTCP_READAHEAD_BUFFERS > 0 if (ret <= 0 && !_SS_ISCLOSED(psock->s_flags)) #else if (!_SS_ISCLOSED(psock->s_flags)) #endif { /* Nothing was previously received from the readahead buffers. * The SOCK_STREAM must be (re-)connected in order to receive any * additional data. */ ret = -ENOTCONN; } } /* In general, this uIP-based implementation will not support non-blocking * socket operations... except in a few cases: Here for TCP receive with read-ahead * enabled. If this socket is configured as non-blocking then return EAGAIN * if no data was obtained from the read-ahead buffers. */ else #if CONFIG_NET_NTCP_READAHEAD_BUFFERS > 0 if (_SS_ISNONBLOCK(psock->s_flags)) { /* Return the number of bytes read from the read-ahead buffer if * something was received (already in 'ret'); EAGAIN if not. */ if (ret <= 0) { /* Nothing was received */ ret = -EAGAIN; } } /* It is okay to block if we need to. If there is space to receive anything * more, then we will wait to receive the data. Otherwise return the number * of bytes read from the read-ahead buffer (already in 'ret'). */ else #endif /* We get here when we we decide that we need to setup the wait for incoming * TCP/IP data. Just a few more conditions to check: * * 1) Make sure thet there is buffer space to receive additional data * (state.rf_buflen > 0). This could be zero, for example, if read-ahead * buffering was enabled and we filled the user buffer with data from * the read-ahead buffers. Aand * 2) if read-ahead buffering is enabled (CONFIG_NET_NTCP_READAHEAD_BUFFERS > 0) * and delay logic is disabled (CONFIG_NET_TCP_RECVDELAY == 0), then we * not want to wait if we already obtained some data from the read-ahead * buffer. In that case, return now with what we have (don't want for more * because there may be no timeout). */ #if CONFIG_NET_TCP_RECVDELAY == 0 && CONFIG_NET_NTCP_READAHEAD_BUFFERS > 0 if (state.rf_recvlen == 0 && state.rf_buflen > 0) #else if (state.rf_buflen > 0) #endif { struct uip_conn *conn = (struct uip_conn *)psock->s_conn; /* Set up the callback in the connection */ state.rf_cb = uip_tcpcallbackalloc(conn); if (state.rf_cb) { state.rf_cb->flags = UIP_NEWDATA|UIP_POLL|UIP_CLOSE|UIP_ABORT|UIP_TIMEDOUT; state.rf_cb->priv = (void*)&state; state.rf_cb->event = recvfrom_tcpinterrupt; /* 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. */ ret = uip_lockedwait(&state.rf_sem); /* Make sure that no further interrupts are processed */ uip_tcpcallbackfree(conn, state.rf_cb); ret = recvfrom_result(ret, &state); } else { ret = -EBUSY; } } uip_unlock(save); recvfrom_uninit(&state); return (ssize_t)ret; }
int psock_connect(FAR struct socket *psock, FAR const struct sockaddr *addr, socklen_t addrlen) { #if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_UDP) #ifdef CONFIG_NET_IPv6 FAR const struct sockaddr_in6 *inaddr = (const struct sockaddr_in6 *)addr; #else FAR const struct sockaddr_in *inaddr = (const struct sockaddr_in *)addr; #endif int ret; #endif int err; /* Verify that the psock corresponds to valid, allocated socket */ if (!psock || psock->s_crefs <= 0) { err = EBADF; goto errout; } /* Verify that a valid address has been provided */ #ifdef CONFIG_NET_IPv6 if (addr->sa_family != AF_INET6 || addrlen < sizeof(struct sockaddr_in6)) #else if (addr->sa_family != AF_INET || addrlen < sizeof(struct sockaddr_in)) #endif { err = EBADF; goto errout; } /* Perform the connection depending on the protocol type */ switch (psock->s_type) { #ifdef CONFIG_NET_TCP case SOCK_STREAM: { /* Verify that the socket is not already connected */ if (_SS_ISCONNECTED(psock->s_flags)) { err = EISCONN; goto errout; } /* Its not ... connect it */ ret = tcp_connect(psock, inaddr); if (ret < 0) { err = -ret; goto errout; } } break; #endif #ifdef CONFIG_NET_UDP case SOCK_DGRAM: { ret = uip_udpconnect(psock->s_conn, inaddr); if (ret < 0) { err = -ret; goto errout; } } break; #endif default: err = EBADF; goto errout; } return OK; errout: errno = err; return ERROR; }
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; }