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; }
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 net_vfcntl(int sockfd, int cmd, va_list ap) { FAR struct socket *psock = sockfd_socket(sockfd); net_lock_t flags; int err = 0; int ret = 0; nvdbg("sockfd=%d cmd=%d\n", sockfd, cmd); /* Verify that the sockfd corresponds to valid, allocated socket */ if (!psock || psock->s_crefs <= 0) { err = EBADF; goto errout; } /* Interrupts must be disabled in order to perform operations on socket structures */ flags = net_lock(); switch (cmd) { case F_DUPFD: /* Return a new file descriptor which shall be the lowest numbered * available (that is, not already open) file descriptor greater than * or equal to the third argument, arg, taken as an integer of type * int. The new file descriptor shall refer to the same open file * description as the original file descriptor, and shall share any * locks. The FD_CLOEXEC flag associated with the new file descriptor * shall be cleared to keep the file open across calls to one of the * exec functions. */ { ret = net_dupsd(sockfd, va_arg(ap, int)); } break; case F_GETFD: /* Get the file descriptor flags defined in <fcntl.h> that are associated * with the file descriptor fd. File descriptor flags are associated * with a single file descriptor and do not affect other file descriptors * that refer to the same file. */ case F_SETFD: /* Set the file descriptor flags defined in <fcntl.h>, that are associated * with fd, to the third argument, arg, taken as type int. If the * FD_CLOEXEC flag in the third argument is 0, the file shall remain open * across the exec functions; otherwise, the file shall be closed upon * successful execution of one of the exec functions. */ err = ENOSYS; /* F_GETFD and F_SETFD not implemented */ break; case F_GETFL: /* Get the file status flags and file access modes, defined in * <fcntl.h>, for the file description associated with fd. The file * access modes can be extracted from the return value using the * mask O_ACCMODE, which is defined in <fcntl.h>. File status flags * and file access modes are associated with the file description * and do not affect other file descriptors that refer to the same * file with different open file descriptions. */ { /* This summarizes the behavior of all NuttX sockets */ ret = O_RDWR | O_SYNC | O_RSYNC; #if defined(CONFIG_NET_LOCAL) || defined(CONFIG_NET_TCP_READAHEAD) || \ defined(CONFIG_NET_UDP_READAHEAD) /* Unix domain sockets may be non-blocking. TCP/IP and UDP/IP * sockets may also be non-blocking if read-ahead is enabled */ if ((0 #ifdef CONFIG_NET_LOCAL || psock->s_domain == PF_LOCAL /* Unix domain stream or datagram */ #endif #ifdef CONFIG_NET_TCP_READAHEAD || psock->s_type == SOCK_STREAM /* IP or Unix domain stream */ #endif #ifdef CONFIG_NET_UDP_READAHEAD || psock->s_type == SOCK_DGRAM /* IP or Unix domain datagram */ #endif ) && _SS_ISNONBLOCK(psock->s_flags)) { ret |= O_NONBLOCK; } #endif /* CONFIG_NET_LOCAL || CONFIG_NET_TCP_READAHEAD || CONFIG_NET_UDP_READAHEAD */ } break; case F_SETFL: /* Set the file status flags, defined in <fcntl.h>, for the file description * associated with fd from the corresponding bits in the third argument, * arg, taken as type int. Bits corresponding to the file access mode and * the file creation flags, as defined in <fcntl.h>, that are set in arg shall * be ignored. If any bits in arg other than those mentioned here are changed * by the application, the result is unspecified. */ { #if defined(CONFIG_NET_LOCAL) || defined(CONFIG_NET_TCP_READAHEAD) || \ defined(CONFIG_NET_UDP_READAHEAD) /* Non-blocking is the only configurable option. And it applies * only Unix domain sockets and to read operations on TCP/IP * and UDP/IP sockets when read-ahead is enabled. */ int mode = va_arg(ap, int); #if defined(CONFIG_NET_LOCAL_STREAM) || defined(CONFIG_NET_TCP_READAHEAD) if (psock->s_type == SOCK_STREAM) /* IP or Unix domain stream */ { if ((mode & O_NONBLOCK) != 0) { psock->s_flags |= _SF_NONBLOCK; } else { psock->s_flags &= ~_SF_NONBLOCK; } } else #endif #if defined(CONFIG_NET_LOCAL_DGRAM) || defined(CONFIG_NET_UDP_READAHEAD) if (psock->s_type == SOCK_DGRAM) /* IP or Unix domain datagram */ { if ((mode & O_NONBLOCK) != 0) { psock->s_flags |= _SF_NONBLOCK; } else { psock->s_flags &= ~_SF_NONBLOCK; } } else #endif #endif /* CONFIG_NET_LOCAL || CONFIG_NET_TCP_READAHEAD || CONFIG_NET_UDP_READAHEAD */ { ndbg("ERROR: Non-blocking not supported for this socket\n"); } } break; case F_GETOWN: /* If fd refers to a socket, get the process or process group ID specified * to receive SIGURG signals when out-of-band data is available. Positive values * indicate a process ID; negative values, other than -1, indicate a process group * ID. If fd does not refer to a socket, the results are unspecified. */ case F_SETOWN: /* If fd refers to a socket, set the process or process group ID specified * to receive SIGURG signals when out-of-band data is available, using the value * of the third argument, arg, taken as type int. Positive values indicate a * process ID; negative values, other than -1, indicate a process group ID. If * fd does not refer to a socket, the results are unspecified. */ case F_GETLK: /* Get the first lock which blocks the lock description pointed to by the third * argument, arg, taken as a pointer to type struct flock, defined in <fcntl.h>. * The information retrieved shall overwrite the information passed to fcntl() in * the structure flock. If no lock is found that would prevent this lock from being * created, then the structure shall be left unchanged except for the lock type * which shall be set to F_UNLCK. */ case F_SETLK: /* Set or clear a file segment lock according to the lock description pointed to * by the third argument, arg, taken as a pointer to type struct flock, defined in * <fcntl.h>. F_SETLK can establish shared (or read) locks (F_RDLCK) or exclusive * (or write) locks (F_WRLCK), as well as to remove either type of lock (F_UNLCK). * F_RDLCK, F_WRLCK, and F_UNLCK are defined in <fcntl.h>. If a shared or exclusive * lock cannot be set, fcntl() shall return immediately with a return value of -1. */ case F_SETLKW: /* This command shall be equivalent to F_SETLK except that if a shared or exclusive * lock is blocked by other locks, the thread shall wait until the request can be * satisfied. If a signal that is to be caught is received while fcntl() is waiting * for a region, fcntl() shall be interrupted. Upon return from the signal handler, * fcntl() shall return -1 with errno set to [EINTR], and the lock operation shall * not be done. */ err = ENOSYS; /* F_GETOWN, F_SETOWN, F_GETLK, F_SETLK, F_SETLKW */ break; default: err = EINVAL; break; } net_unlock(flags); errout: if (err != 0) { set_errno(err); return ERROR; } return ret; }
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; }
int psock_local_connect(FAR struct socket *psock, FAR const struct sockaddr *addr) { FAR struct local_conn_s *client; FAR struct sockaddr_un *unaddr = (FAR struct sockaddr_un *)addr; FAR struct local_conn_s *conn; DEBUGASSERT(psock && psock->s_conn); client = (FAR struct local_conn_s *)psock->s_conn; if (client->lc_state == LOCAL_STATE_ACCEPT || client->lc_state == LOCAL_STATE_CONNECTED) { return -EISCONN; } /* Find the matching server connection */ net_lock(); for (conn = (FAR struct local_conn_s *)g_local_listeners.head; conn; conn = (FAR struct local_conn_s *)dq_next(&conn->lc_node)) { /* Anything in the listener list should be a stream socket in the * istening state */ DEBUGASSERT(conn->lc_state == LOCAL_STATE_LISTENING && conn->lc_proto == SOCK_STREAM); /* Handle according to the server connection type */ switch (conn->lc_type) { case LOCAL_TYPE_UNNAMED: /* A Unix socket that is not bound to any name */ case LOCAL_TYPE_ABSTRACT: /* lc_path is length zero */ { #warning Missing logic net_unlock(); return OK; } break; case LOCAL_TYPE_PATHNAME: /* lc_path holds a null terminated string */ { if (strncmp(conn->lc_path, unaddr->sun_path, UNIX_PATH_MAX-1) == 0) { int ret = OK; /* Bind the address and protocol */ client->lc_proto = conn->lc_proto; strncpy(client->lc_path, unaddr->sun_path, UNIX_PATH_MAX-1); client->lc_path[UNIX_PATH_MAX-1] = '\0'; client->lc_instance_id = local_generate_instance_id(); /* The client is now bound to an address */ client->lc_state = LOCAL_STATE_BOUND; /* We have to do more for the SOCK_STREAM family */ if (conn->lc_proto == SOCK_STREAM) { ret = local_stream_connect(client, conn, _SS_ISNONBLOCK(psock->s_flags)); } else { net_unlock(); } return ret; } } break; default: /* Bad, memory must be corrupted */ DEBUGPANIC(); /* PANIC if debug on, else fall through */ case LOCAL_TYPE_UNTYPED: /* Type is not determined until the socket is bound */ { net_unlock(); return -EINVAL; } } } net_unlock(); return -EADDRNOTAVAIL; }
int psock_local_accept(FAR struct socket *psock, FAR struct sockaddr *addr, FAR socklen_t *addrlen, FAR void **newconn) { FAR struct local_conn_s *server; FAR struct local_conn_s *client; FAR struct local_conn_s *conn; int ret; /* Some sanity checks */ DEBUGASSERT(psock && psock->s_conn); server = (FAR struct local_conn_s *)psock->s_conn; if (server->lc_proto != SOCK_STREAM || server->lc_state != LOCAL_STATE_LISTENING || server->lc_type != LOCAL_TYPE_PATHNAME) { return -EOPNOTSUPP; } /* Loop as necessary if we have to wait for a connection */ for (; ; ) { /* Are there pending connections. Remove the client from the * head of the waiting list. */ client = (FAR struct local_conn_s *) dq_remfirst(&server->u.server.lc_waiters); if (client) { /* Decrement the number of pending clients */ DEBUGASSERT(server->u.server.lc_pending > 0); server->u.server.lc_pending--; /* Create a new connection structure for the server side of the * connection. */ conn = local_alloc(); if (!conn) { ndbg("ERROR: Failed to allocate new connection structure\n"); ret = -ENOMEM; } else { /* Initialize the new connection structure */ conn->lc_crefs = 1; conn->lc_proto = SOCK_STREAM; conn->lc_type = LOCAL_TYPE_PATHNAME; conn->lc_state = LOCAL_STATE_CONNECTED; strncpy(conn->lc_path, client->lc_path, UNIX_PATH_MAX-1); conn->lc_path[UNIX_PATH_MAX-1] = '\0'; conn->lc_instance_id = client->lc_instance_id; /* Open the server-side write-only FIFO. This should not * block. */ ret = local_open_server_tx(conn, _SS_ISNONBLOCK(psock->s_flags)); if (ret < 0) { ndbg("ERROR: Failed to open write-only FIFOs for %s: %d\n", conn->lc_path, ret); } } /* Do we have a connection? Is the write-side FIFO opened? */ if (ret == OK) { DEBUGASSERT(conn->lc_outfd >= 0); /* Open the server-side read-only FIFO. This should not * block because the client side has already opening it * for writing. */ ret = local_open_server_rx(conn, _SS_ISNONBLOCK(psock->s_flags)); if (ret < 0) { ndbg("ERROR: Failed to open read-only FIFOs for %s: %d\n", conn->lc_path, ret); } } /* Do we have a connection? Are the FIFOs opened? */ if (ret == OK) { DEBUGASSERT(conn->lc_infd >= 0); /* Return the address family */ if (addr) { ret = local_getaddr(client, addr, addrlen); } } if (ret == OK) { /* Return the client connection structure */ *newconn = (FAR void *)conn; } /* Signal the client with the result of the connection */ client->u.client.lc_result = ret; sem_post(&client->lc_waitsem); return ret; } /* No.. then there should be no pending connections */ DEBUGASSERT(server->u.server.lc_pending == 0); /* Was the socket opened non-blocking? */ if (_SS_ISNONBLOCK(psock->s_flags)) { /* Yes.. return EAGAIN */ return -EAGAIN; } /* Otherwise, listen for a connection and try again. */ ret = local_waitlisten(server); if (ret < 0) { return ret; } } }
ssize_t psock_local_sendto(FAR struct socket *psock, FAR const void *buf, size_t len, int flags, FAR const struct sockaddr *to, socklen_t tolen) { FAR struct local_conn_s *conn = (FAR struct local_conn_s *)psock->s_conn; FAR struct sockaddr_un *unaddr = (FAR struct sockaddr_un *)to; ssize_t nsent; int ret; /* We keep packet sizes in a uint16_t, so there is a upper limit to the * 'len' that can be supported. */ DEBUGASSERT(buf && len <= UINT16_MAX); /* Verify that this is not a connected peer socket. It need not be * bound, however. If unbound, recvfrom will see this as a nameless * connection. */ if (conn->lc_state != LOCAL_STATE_UNBOUND && conn->lc_state != LOCAL_STATE_BOUND) { /* Either not bound to address or it is connected */ ndbg("ERROR: Connected state\n"); return -EISCONN; } /* The outgoing FIFO should not be open */ DEBUGASSERT(conn->lc_outfd < 0); /* At present, only standard pathname type address are support */ if (tolen < sizeof(sa_family_t) + 2) { /* EFAULT - An invalid user space address was specified for a parameter */ return -EFAULT; } /* Make sure that half duplex FIFO has been created. * REVISIT: Or should be just make sure that it already exists? */ ret = local_create_halfduplex(conn, unaddr->sun_path); if (ret < 0) { ndbg("ERROR: Failed to create FIFO for %s: %d\n", conn->lc_path, ret); return ret; } /* Open the sending side of the transfer */ ret = local_open_sender(conn, unaddr->sun_path, _SS_ISNONBLOCK(psock->s_flags)); if (ret < 0) { ndbg("ERROR: Failed to open FIFO for %s: %d\n", unaddr->sun_path, ret); nsent = ret; goto errout_with_halfduplex; } /* Send the packet */ nsent = local_send_packet(conn->lc_outfd, buf, len); if (nsent < 0) { ndbg("ERROR: Failed to send the packet: %d\n", ret); } else { /* local_send_packet returns 0 if all 'len' bytes were sent */ nsent = len; } /* Now we can close the write-only socket descriptor */ close(conn->lc_outfd); conn->lc_outfd = -1; errout_with_halfduplex: /* Release our reference to the half duplex FIFO*/ (void)local_release_halfduplex(conn); return nsent; }
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; }