mirror of
https://github.com/apache/nuttx.git
synced 2026-02-07 13:32:55 +08:00
dup2 and setsockopt can use the lock in conn to protect resources, the lock in accept is originally used to protect the connection status. however, only the send, recv, netpoll, and connect processes will check this flag. only when the interface returns will the corresponding conn structure be exposed to the caller, and then the above operations can be performed. Therefore, this net_lock is not necessary. Signed-off-by: zhanghongyu <zhanghongyu@xiaomi.com>
170 lines
5.7 KiB
C
170 lines
5.7 KiB
C
/****************************************************************************
|
|
* 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;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
return ret;
|
|
}
|