| /**************************************************************************** |
| * net/socket/accept.c |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. The |
| * ASF licenses this file to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance with the |
| * License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations |
| * under the License. |
| * |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Included Files |
| ****************************************************************************/ |
| |
| #include <nuttx/config.h> |
| |
| #include <sys/types.h> |
| #include <sys/socket.h> |
| |
| #include <unistd.h> |
| #include <errno.h> |
| #include <assert.h> |
| #include <debug.h> |
| #include <fcntl.h> |
| |
| #include <nuttx/cancelpt.h> |
| #include <nuttx/fs/fs.h> |
| #include <nuttx/kmalloc.h> |
| #include <arch/irq.h> |
| |
| #include "socket/socket.h" |
| |
| /**************************************************************************** |
| * Public Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: psock_accept |
| * |
| * Description: |
| * The psock_accept function is used with connection-based socket types |
| * (SOCK_STREAM, SOCK_SEQPACKET and SOCK_RDM). It extracts the first |
| * connection request on the queue of pending connections, creates a new |
| * connected socket with mostly the same properties as 'sockfd', and |
| * allocates a new socket descriptor for the socket, which is returned. The |
| * newly created socket is no longer in the listening state. The original |
| * socket 'sockfd' is unaffected by this call. Per file descriptor flags |
| * are not inherited across an psock_accept. |
| * |
| * The 'sockfd' argument is a socket descriptor that has been created with |
| * socket(), bound to a local address with bind(), and is listening for |
| * connections after a call to listen(). |
| * |
| * On return, the 'addr' structure is filled in with the address of the |
| * connecting entity. The 'addrlen' argument initially contains the size |
| * of the structure pointed to by 'addr'; on return it will contain the |
| * actual length of the address returned. |
| * |
| * If no pending connections are present on the queue, and the socket is |
| * not marked as non-blocking, psock_accept blocks the caller until a |
| * connection is present. If the socket is marked non-blocking and no |
| * pending connections are present on the queue, psock_accept returns |
| * EAGAIN. |
| * |
| * Input Parameters: |
| * psock Reference to the listening socket structure |
| * addr Receives the address of the connecting client |
| * addrlen Input: allocated size of 'addr', Return: returned size |
| * of 'addr' |
| * newsock Location to return the accepted socket information. |
| * flags The flags used for initialization |
| * |
| * Returned Value: |
| * Returns 0 (OK) on success. On failure, it returns a negated errno value |
| * to indicate the nature of the error. |
| * |
| * EAGAIN or EWOULDBLOCK |
| * The socket is marked non-blocking and no connections are present to |
| * be accepted. |
| * EOPNOTSUPP |
| * The referenced socket is not of type SOCK_STREAM. |
| * EINTR |
| * The system call was interrupted by a signal that was caught before |
| * a valid connection arrived. |
| * ECONNABORTED |
| * A connection has been aborted. |
| * EINVAL |
| * Socket is not listening for connections. |
| * EMFILE |
| * The per-process limit of open file descriptors has been reached. |
| * ENFILE |
| * The system maximum for file descriptors has been reached. |
| * EFAULT |
| * The addr parameter is not in a writable part of the user address space. |
| * ENOBUFS or ENOMEM |
| * Not enough free memory. |
| * EPROTO |
| * Protocol error. |
| * EPERM |
| * Firewall rules forbid connection. |
| * |
| ****************************************************************************/ |
| |
| int psock_accept(FAR struct socket *psock, FAR struct sockaddr *addr, |
| FAR socklen_t *addrlen, FAR struct socket *newsock, |
| int flags) |
| { |
| FAR struct socket_conn_s *conn; |
| int ret; |
| |
| DEBUGASSERT(psock != NULL && psock->s_conn != NULL && newsock != NULL); |
| |
| /* May sure that the socket has been opened with socket() */ |
| |
| if (psock == NULL || psock->s_conn == NULL) |
| { |
| nerr("ERROR: Socket invalid or not opened\n"); |
| return -EINVAL; |
| } |
| |
| /* Is the socket listening for a connection? */ |
| |
| conn = psock->s_conn; |
| if (!_SS_ISLISTENING(conn->s_flags)) |
| { |
| nerr("ERROR: Socket is not listening for a connection.\n"); |
| return -EINVAL; |
| } |
| |
| /* Let the address family's accept() method handle the operation */ |
| |
| DEBUGASSERT(psock->s_sockif != NULL); |
| if (psock->s_sockif->si_accept == NULL) |
| { |
| return -EOPNOTSUPP; |
| } |
| |
| net_lock(); |
| ret = psock->s_sockif->si_accept(psock, addr, addrlen, newsock, flags); |
| if (ret >= 0) |
| { |
| /* Mark the new socket as connected. */ |
| |
| conn = newsock->s_conn; |
| conn->s_flags |= _SF_CONNECTED; |
| conn->s_flags &= ~_SF_CLOSED; |
| if (flags & SOCK_NONBLOCK) |
| { |
| conn->s_flags |= _SF_NONBLOCK; |
| } |
| } |
| else |
| { |
| nerr("ERROR: si_accept failed: %d\n", ret); |
| } |
| |
| net_unlock(); |
| return ret; |
| } |