mirror of
https://github.com/apache/nuttx.git
synced 2025-01-13 13:18:50 +08:00
Merge remote-tracking branch 'origin/master' into composite
This commit is contained in:
commit
1674cb8c8e
43 changed files with 10609 additions and 5133 deletions
|
@ -466,6 +466,10 @@ config SAMDL_HAVE_TC7
|
|||
bool
|
||||
default n
|
||||
|
||||
config SAMDL_HAVE_USB
|
||||
bool
|
||||
default n
|
||||
|
||||
config SAMDL_AC
|
||||
bool "Analog Comparator"
|
||||
default n
|
||||
|
@ -737,3 +741,25 @@ config SAMDL_I2C_REGDEBUG
|
|||
Enable very low-level register access debug. Depends on DEBUG_I2C.
|
||||
|
||||
endif # SAMDL_HAVE_I2C
|
||||
|
||||
if SAMDL_HAVE_USB
|
||||
|
||||
config SAMDL_USB_ENABLE_PPEP
|
||||
bool "Enable Ping-Pong Endpoints"
|
||||
default n
|
||||
---help---
|
||||
To maximize throughput, an endpoint can be configured for ping-pong
|
||||
operation. When this is done the input and output endpoint with the same
|
||||
address are used in the same direction. The CPU or DMA Controller can
|
||||
then read/write one data buffer while the USB module writes/reads from
|
||||
the other buffer. This gives double buffered communication.
|
||||
|
||||
config SAMDL_USB_REGDEBUG
|
||||
bool "USB register-Level Debug"
|
||||
default n
|
||||
depends on DEBUG_USB_INFO
|
||||
---help---
|
||||
Enable very low-level register access debug. Depends on
|
||||
CONFIG_DEBUG_USB_INFO.
|
||||
|
||||
endif # SAMDL_HAVE_USB
|
||||
|
|
|
@ -98,3 +98,7 @@ endif
|
|||
ifeq ($(CONFIG_SAMDL_HAVE_I2C),y)
|
||||
CHIP_CSRCS += sam_i2c_master.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SAMDL_USB),y)
|
||||
CHIP_CSRCS += sam_usb.c
|
||||
endif
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
*
|
||||
********************************************************************************************/
|
||||
|
||||
|
||||
#ifndef __ARCH_ARM_SRC_SAMDL_CHIP_SAML_USB_H
|
||||
#define __ARCH_ARM_SRC_SAMDL_CHIP_SAML_USB_H
|
||||
|
||||
|
@ -53,6 +54,29 @@
|
|||
/********************************************************************************************
|
||||
* Pre-processor Definitions
|
||||
********************************************************************************************/
|
||||
|
||||
/* Capabilities and characteristics of endpoints ********************************************/
|
||||
|
||||
/* EP EP BANKS EP SIZE EP TYPE
|
||||
* --- --------- --------- ---------
|
||||
* 0 2 64/1023 Control/Bulk/Iso/Interrupt
|
||||
* 1 2 64/1023 Control/Bulk/Iso/Interrupt
|
||||
* 2 2 64/1023 Control/Bulk/Iso/Interrupt
|
||||
* 3 2 64/1023 Control/Bulk/Iso/Interrupt
|
||||
* 4 2 64/1023 Control/Bulk/Iso/Interrupt
|
||||
* 5 2 64/1023 Control/Bulk/Iso/Interrupt
|
||||
* 6 2 64/1023 Control/Bulk/Iso/Interrupt
|
||||
* 7 2 64/1023 Control/Bulk/Iso/Interrupt
|
||||
*/
|
||||
|
||||
#define SAM_USB_NENDPOINTS (8)
|
||||
#define SAM_USB_MAXPACKETSIZE(ep) (64)
|
||||
#define SAM_USB_NBANKS(ep) (2)
|
||||
#define SAM_USB_CONTROL(ep) (true)
|
||||
#define SAM_USB_BULK(ep) (true)
|
||||
#define SAM_USB_ISOCHRONOUS(ep) (true)
|
||||
#define SAM_USB_INTERRUPT(ep) (true)
|
||||
|
||||
/* USB register offsets ********************************************************************/
|
||||
|
||||
/* Common USB Device/Host Register Offsets */
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -101,7 +101,7 @@
|
|||
# define USART4_ASSIGNED 1
|
||||
#elif defined(CONFIG_USART5_SERIAL_CONSOLE)
|
||||
# define CONSOLE_DEV g_usart5port /* USART5 is console */
|
||||
# define TTYS5_DEV g_usart5port /* USART5 is ttyS0 */
|
||||
# define TTYS0_DEV g_usart5port /* USART5 is ttyS0 */
|
||||
#else
|
||||
# undef CONSOLE_DEV /* No console */
|
||||
# if defined(SAMDL_HAVE_USART0)
|
||||
|
|
|
@ -1261,7 +1261,12 @@ static void spi_recvblock(struct spi_dev_s *dev, void *buffer, size_t nwords)
|
|||
|
||||
static void spi_wait_synchronization(struct sam_spidev_s *priv)
|
||||
{
|
||||
|
||||
#if defined(CONFIG_ARCH_FAMILY_SAMD20)
|
||||
while ((spi_getreg16(priv, SAM_SPI_STATUS_OFFSET) & SPI_STATUS_SYNCBUSY) != 0);
|
||||
#elif defined(CONFIG_ARCH_FAMILY_SAMD21) || defined(CONFIG_ARCH_FAMILY_SAML21)
|
||||
while ((spi_getreg16(priv, SAM_SPI_SYNCBUSY_OFFSET) & SPI_SYNCBUSY_ALL) != 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
4056
arch/arm/src/samdl/sam_usb.c
Normal file
4056
arch/arm/src/samdl/sam_usb.c
Normal file
File diff suppressed because it is too large
Load diff
99
arch/arm/src/samdl/sam_usb.h
Normal file
99
arch/arm/src/samdl/sam_usb.h
Normal file
|
@ -0,0 +1,99 @@
|
|||
/******************************************************************************
|
||||
* arch/arm/src/samdl/sam_usb.h
|
||||
*
|
||||
* Copyright (C) 2015 Filament - www.filament.com
|
||||
* Copyright (C) 2015 Offcode Ltd. All rights reserved.
|
||||
* Author: Janne Rosberg <janne@offcode.fi>
|
||||
*
|
||||
* This driver is derived from the SAM34 UDP driver:
|
||||
* Copyright (C) 2014 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __ARCH_ARM_SRC_SAMDL_SAM_USB_H
|
||||
#define __ARCH_ARM_SRC_SAMDL_SAM_USB_H
|
||||
|
||||
/*****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <nuttx/usb/usbdev.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "chip.h"
|
||||
#include "chip/saml_usb.h"
|
||||
|
||||
/*****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
* Name: sam_usb_suspend
|
||||
*
|
||||
* Description:
|
||||
* Board logic must provide the sam_usb_suspend logic if the USB driver is
|
||||
* used. This function is called whenever the USB enters or leaves
|
||||
* suspend mode.
|
||||
*
|
||||
* When 'resume' is false, this function call provides an opportunity to
|
||||
* perform board-specific power-saving actions so that less power is consumed
|
||||
* while the USB is suspended.
|
||||
*
|
||||
* XXX:
|
||||
* Certain power-saving operations are performed by the UDP driver when it
|
||||
* enters suspend mode: The USB device peripheral clocks are be switched off.
|
||||
* MCK and UDPCK are switched off and the USB transceiver is disabled.
|
||||
*
|
||||
* When 'resume' is true, normal clocking and operations must all be restored.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
void sam_udp_suspend(FAR struct usbdev_s *dev, bool resume);
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
#endif /* __ARCH_ARM_SRC_SAMDL_SAM_USB_H */
|
|
@ -301,7 +301,7 @@ static inline void sam_xosc_config(void)
|
|||
|
||||
/* Configure the XOSC clock */
|
||||
|
||||
regval = BOARD_XOSC_STARTUPTIME
|
||||
regval = BOARD_XOSC_STARTUPTIME;
|
||||
|
||||
#ifdef BOARD_XOSC_ISCRYSTAL
|
||||
/* XOSC is a crystal */
|
||||
|
@ -383,7 +383,7 @@ static inline void sam_xosc32k_config(void)
|
|||
|
||||
/* Configure XOSC32K */
|
||||
|
||||
regval = BOARD_XOSC32K_STARTUPTIME
|
||||
regval = BOARD_XOSC32K_STARTUPTIME;
|
||||
|
||||
#ifdef BOARD_XOSC32K_ISCRYSTAL
|
||||
regval |= SYSCTRL_XOSC32K_XTALEN;
|
||||
|
|
|
@ -480,6 +480,19 @@
|
|||
|
||||
#define BOARD_SERCOM5_FREQUENCY BOARD_GCLK0_FREQUENCY
|
||||
|
||||
/* USB definitions ******************************************************************/
|
||||
/* This is the source clock generator for the GCLK_USB clock
|
||||
*/
|
||||
|
||||
#define BOARD_USB_GCLKGEN 0
|
||||
#define BOARD_USB_FREQUENCY BOARD_GCLK0_FREQUENCY
|
||||
|
||||
/* default USB Pad calibration (not used yet by USB driver) */
|
||||
|
||||
#define BOARD_USB_PADCAL_P 29
|
||||
#define BOARD_USB_PADCAL_N 5
|
||||
#define BOARD_USB_PADCAL_TRIM 3
|
||||
|
||||
/* LED definitions ******************************************************************/
|
||||
/* There are three LEDs on board the SAMD21 Xplained Pro board: The EDBG
|
||||
* controls two of the LEDs, a power LED and a status LED. There is only
|
||||
|
|
|
@ -604,6 +604,19 @@
|
|||
|
||||
#define BOARD_SERCOM5_FREQUENCY BOARD_GCLK0_FREQUENCY
|
||||
|
||||
/* USB definitions ******************************************************************/
|
||||
/* This is the source clock generator for the GCLK_USB clock
|
||||
*/
|
||||
|
||||
#define BOARD_USB_GCLKGEN 0
|
||||
#define BOARD_USB_FREQUENCY BOARD_GCLK0_FREQUENCY
|
||||
|
||||
/* default USB Pad calibration (not used yet by USB driver) */
|
||||
|
||||
#define BOARD_USB_PADCAL_P 29
|
||||
#define BOARD_USB_PADCAL_N 5
|
||||
#define BOARD_USB_PADCAL_TRIM 3
|
||||
|
||||
/* LED definitions ******************************************************************/
|
||||
/* There are three LEDs on board the SAML21 Xplained Pro board: The EDBG
|
||||
* controls two of the LEDs, a power LED and a status LED. There is only
|
||||
|
|
|
@ -64,6 +64,11 @@
|
|||
# define __SOCKFD_OFFSET 0
|
||||
#endif
|
||||
|
||||
/* Capabilities of a socket */
|
||||
|
||||
#define SOCKCAP_NONBLOCKING (1 << 0) /* Bit 0: Socket supports non-blocking
|
||||
* operation. */
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
@ -94,11 +99,44 @@ typedef uint16_t sockopt_t;
|
|||
|
||||
typedef uint16_t socktimeo_t;
|
||||
|
||||
/* This type defines the type of the socket capabilities set */
|
||||
|
||||
typedef uint8_t sockcaps_t;
|
||||
|
||||
/* This callbacks are socket operations that may be performed on a socket of
|
||||
* a given address family.
|
||||
*/
|
||||
|
||||
struct socket; /* Forward reference */
|
||||
|
||||
struct sock_intf_s
|
||||
{
|
||||
CODE int (*si_setup)(FAR struct socket *psock, int protocol);
|
||||
CODE sockcaps_t (*si_sockcaps)(FAR struct socket *psock);
|
||||
CODE void (*si_addref)(FAR struct socket *psock);
|
||||
CODE int (*si_bind)(FAR struct socket *psock,
|
||||
FAR const struct sockaddr *addr, socklen_t addrlen);
|
||||
CODE int (*si_listen)(FAR struct socket *psock, int backlog);
|
||||
CODE int (*si_connect)(FAR struct socket *psock,
|
||||
FAR const struct sockaddr *addr, socklen_t addrlen);
|
||||
CODE int (*si_accept)(FAR struct socket *psock, FAR struct sockaddr *addr,
|
||||
FAR socklen_t *addrlen, FAR struct socket *newsock);
|
||||
CODE ssize_t (*si_send)(FAR struct socket *psock, FAR const void *buf,
|
||||
size_t len, int flags);
|
||||
CODE ssize_t (*si_sendto)(FAR struct socket *psock, FAR const void *buf,
|
||||
size_t len, int flags, FAR const struct sockaddr *to,
|
||||
socklen_t tolen);
|
||||
CODE ssize_t (*si_recvfrom)(FAR struct socket *psock, FAR void *buf,
|
||||
size_t len, int flags, FAR struct sockaddr *from,
|
||||
FAR socklen_t *fromlen);
|
||||
CODE int (*si_close)(FAR struct socket *psock);
|
||||
};
|
||||
|
||||
/* This is the internal representation of a socket reference by a file
|
||||
* descriptor.
|
||||
*/
|
||||
|
||||
struct devif_callback_s; /* Forward reference */
|
||||
struct devif_callback_s; /* Forward reference */
|
||||
|
||||
struct socket
|
||||
{
|
||||
|
@ -120,6 +158,10 @@ struct socket
|
|||
|
||||
FAR void *s_conn; /* Connection: struct tcp_conn_s or udp_conn_s */
|
||||
|
||||
/* Socket interface */
|
||||
|
||||
FAR const struct sock_intf_s *s_sockif;
|
||||
|
||||
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
|
||||
/* Callback instance for TCP send */
|
||||
|
||||
|
|
|
@ -209,9 +209,8 @@ static void copy_base62(FAR char *dest, int len)
|
|||
* that full path.
|
||||
*
|
||||
* Returned Value:
|
||||
*
|
||||
* Upon successful completion, mkstemp() returns an open file descriptor.
|
||||
* Otherwise, -1 is returned if no suitable file could be created.
|
||||
* Upon successful completion, mkstemp() returns an open file descriptor.
|
||||
* Otherwise, -1 is returned if no suitable file could be created.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
@ -284,6 +283,8 @@ int mkstemp(FAR char *path_template)
|
|||
|
||||
return fd;
|
||||
}
|
||||
|
||||
retries--;
|
||||
}
|
||||
|
||||
/* We could not find an unique filename */
|
||||
|
|
|
@ -224,6 +224,7 @@ void icmpv6_input(FAR struct net_driver_s *dev)
|
|||
case ICMPV6_ROUTER_ADVERTISE:
|
||||
{
|
||||
FAR struct icmpv6_router_advertise_s *adv;
|
||||
FAR uint8_t *options;
|
||||
uint16_t pktlen;
|
||||
uint16_t optlen;
|
||||
int ndx;
|
||||
|
@ -241,14 +242,17 @@ void icmpv6_input(FAR struct net_driver_s *dev)
|
|||
optlen = ICMPv6_RADV_OPTLEN(pktlen);
|
||||
|
||||
/* We need to have a valid router advertisement with a Prefix and
|
||||
* with the "A" bit set in the flags.
|
||||
* with the "A" bit set in the flags. Options immediately follow
|
||||
* the ICMPv6 router advertisement.
|
||||
*/
|
||||
|
||||
adv = ICMPv6RADVERTISE;
|
||||
adv = ICMPv6RADVERTISE;
|
||||
options = (FAR uint8_t *)adv + sizeof(struct icmpv6_router_advertise_s);
|
||||
|
||||
for (ndx = 0; ndx + sizeof(struct icmpv6_prefixinfo_s) <= optlen; )
|
||||
{
|
||||
FAR struct icmpv6_prefixinfo_s *opt =
|
||||
(FAR struct icmpv6_prefixinfo_s *)&adv->options[ndx];
|
||||
(FAR struct icmpv6_prefixinfo_s *)&options[ndx];
|
||||
|
||||
/* Is this the sought for prefix? Is it the correct size? Is
|
||||
* the "A" flag set?
|
||||
|
|
|
@ -39,6 +39,7 @@ ifeq ($(CONFIG_NET_LOCAL),y)
|
|||
|
||||
NET_CSRCS += local_conn.c local_release.c local_bind.c local_fifo.c
|
||||
NET_CSRCS += local_recvfrom.c local_sendpacket.c local_recvutils.c
|
||||
NET_CSRCS += local_sockif.c
|
||||
|
||||
ifeq ($(CONFIG_NET_LOCAL_STREAM),y)
|
||||
NET_CSRCS += local_connect.c local_listen.c local_accept.c local_send.c
|
||||
|
|
|
@ -51,6 +51,8 @@
|
|||
#include <stdint.h>
|
||||
#include <poll.h>
|
||||
|
||||
#include <nuttx/net/net.h>
|
||||
|
||||
#ifdef CONFIG_NET_LOCAL
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -77,6 +79,7 @@
|
|||
/****************************************************************************
|
||||
* Public Type Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Local, Unix domain socket types */
|
||||
|
||||
enum local_type_e
|
||||
|
@ -204,6 +207,10 @@ extern "C"
|
|||
# define EXTERN extern
|
||||
#endif
|
||||
|
||||
/* The local socket interface */
|
||||
|
||||
EXTERN const struct sock_intf_s g_local_sockif;
|
||||
|
||||
#ifdef CONFIG_NET_LOCAL_STREAM
|
||||
/* A list of all SOCK_STREAM listener connections */
|
||||
|
||||
|
@ -302,26 +309,31 @@ int local_release(FAR struct local_conn_s *conn);
|
|||
* Name: local_listen
|
||||
*
|
||||
* Description:
|
||||
* Listen for a new connection of a SOCK_STREAM Unix domain socket.
|
||||
* To accept connections, a socket is first created with psock_socket(), a
|
||||
* willingness to accept incoming connections and a queue limit for
|
||||
* incoming connections are specified with psock_listen(), and then the
|
||||
* connections are accepted with psock_accept(). For the case of local
|
||||
* Unix sockets, psock_listen() calls this function. The psock_listen()
|
||||
* call applies only to sockets of type SOCK_STREAM or SOCK_SEQPACKET.
|
||||
*
|
||||
* This function is called as part of the implementation of listen();
|
||||
*
|
||||
* Input Parameters:
|
||||
* server - A reference to the server-side local connection structure
|
||||
* backlog - Maximum number of pending connections.
|
||||
* Parameters:
|
||||
* psock Reference to an internal, boound socket structure.
|
||||
* backlog The maximum length the queue of pending connections may grow.
|
||||
* If a connection request arrives with the queue full, the client
|
||||
* may receive an error with an indication of ECONNREFUSED or,
|
||||
* if the underlying protocol supports retransmission, the request
|
||||
* may be ignored so that retries succeed.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; a negated errno value on failure.
|
||||
*
|
||||
* Assumptions:
|
||||
* The network is NOT locked
|
||||
* On success, zero is returned. On error, a negated errno value is
|
||||
* returned. See list() for the set of appropriate error values.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int local_listen(FAR struct local_conn_s *server, int backlog);
|
||||
int local_listen(FAR struct socket *psock, int backlog);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: psock_local_accept
|
||||
* Name: local_accept
|
||||
*
|
||||
* Description:
|
||||
* This function implements accept() for Unix domain sockets. See the
|
||||
|
@ -343,8 +355,8 @@ int local_listen(FAR struct local_conn_s *server, int backlog);
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
int psock_local_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
|
||||
FAR socklen_t *addrlen, FAR void **newconn);
|
||||
int local_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
|
||||
FAR socklen_t *addrlen, FAR void **newconn);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: psock_local_send
|
||||
|
@ -421,7 +433,7 @@ ssize_t psock_local_sendto(FAR struct socket *psock, FAR const void *buf,
|
|||
int local_send_packet(int fd, FAR const uint8_t *buf, size_t len);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: psock_recvfrom
|
||||
* Name: local_recvfrom
|
||||
*
|
||||
* Description:
|
||||
* recvfrom() receives messages from a local socket, and may be used to
|
||||
|
@ -448,9 +460,9 @@ int local_send_packet(int fd, FAR const uint8_t *buf, size_t len);
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
ssize_t psock_local_recvfrom(FAR struct socket *psock, FAR void *buf,
|
||||
size_t len, int flags, FAR struct sockaddr *from,
|
||||
FAR socklen_t *fromlen);
|
||||
ssize_t local_recvfrom(FAR struct socket *psock, FAR void *buf,
|
||||
size_t len, int flags, FAR struct sockaddr *from,
|
||||
FAR socklen_t *fromlen);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: local_fifo_read
|
||||
|
|
|
@ -88,7 +88,7 @@ static int local_waitlisten(FAR struct local_conn_s *server)
|
|||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: psock_local_accept
|
||||
* Name: local_accept
|
||||
*
|
||||
* Description:
|
||||
* This function implements accept() for Unix domain sockets. See the
|
||||
|
@ -110,8 +110,8 @@ static int local_waitlisten(FAR struct local_conn_s *server)
|
|||
*
|
||||
****************************************************************************/
|
||||
|
||||
int psock_local_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
|
||||
FAR socklen_t *addrlen, FAR void **newconn)
|
||||
int local_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
|
||||
FAR socklen_t *addrlen, FAR void **newconn)
|
||||
|
||||
{
|
||||
FAR struct local_conn_s *server;
|
||||
|
@ -122,6 +122,18 @@ int psock_local_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
|
|||
/* Some sanity checks */
|
||||
|
||||
DEBUGASSERT(psock && psock->s_conn);
|
||||
|
||||
/* Is the socket a stream? */
|
||||
|
||||
if (psock->s_domain != PF_LOCAL || psock->s_type != SOCK_STREAM)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* Verify that a valid memory block has been provided to receive the
|
||||
* address
|
||||
*/
|
||||
|
||||
server = (FAR struct local_conn_s *)psock->s_conn;
|
||||
|
||||
if (server->lc_proto != SOCK_STREAM ||
|
||||
|
@ -213,7 +225,7 @@ int psock_local_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
|
|||
|
||||
/* Return the address family */
|
||||
|
||||
if (addr)
|
||||
if (addr != NULL)
|
||||
{
|
||||
ret = local_getaddr(client, addr, addrlen);
|
||||
}
|
||||
|
|
|
@ -66,29 +66,46 @@ dq_queue_t g_local_listeners;
|
|||
* Name: local_listen
|
||||
*
|
||||
* Description:
|
||||
* Listen for a new connection of a SOCK_STREAM Unix domain socket.
|
||||
* To accept connections, a socket is first created with psock_socket(), a
|
||||
* willingness to accept incoming connections and a queue limit for
|
||||
* incoming connections are specified with psock_listen(), and then the
|
||||
* connections are accepted with psock_accept(). For the case of local
|
||||
* Unix sockets, psock_listen() calls this function. The psock_listen()
|
||||
* call applies only to sockets of type SOCK_STREAM or SOCK_SEQPACKET.
|
||||
*
|
||||
* This function is called as part of the implementation of listen();
|
||||
*
|
||||
* Input Parameters:
|
||||
* server - A reference to the server-side local connection structure
|
||||
* backlog - Maximum number of pending connections.
|
||||
* Parameters:
|
||||
* psock Reference to an internal, boound socket structure.
|
||||
* backlog The maximum length the queue of pending connections may grow.
|
||||
* If a connection request arrives with the queue full, the client
|
||||
* may receive an error with an indication of ECONNREFUSED or,
|
||||
* if the underlying protocol supports retransmission, the request
|
||||
* may be ignored so that retries succeed.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; a negated errno value on failure.
|
||||
*
|
||||
* Assumptions:
|
||||
* The network is NOT locked
|
||||
* On success, zero is returned. On error, a negated errno value is
|
||||
* returned. See list() for the set of appropriate error values.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int local_listen(FAR struct local_conn_s *server, int backlog)
|
||||
int local_listen(FAR struct socket *psock, int backlog)
|
||||
{
|
||||
FAR struct local_conn_s *server;
|
||||
|
||||
/* Verify that the sockfd corresponds to a connected SOCK_STREAM in this
|
||||
* address family.
|
||||
*/
|
||||
|
||||
if (psock->s_domain != PF_LOCAL || psock->s_type != SOCK_STREAM)
|
||||
{
|
||||
nerr("ERROR: Unsupported socket family=%d or socket type=%d\n",
|
||||
psocl->s_domain, psock->s_type);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
server = (FAR struct local_conn_s *)psock->s_conn;
|
||||
|
||||
/* Some sanity checks */
|
||||
|
||||
DEBUGASSERT(server);
|
||||
|
||||
if (server->lc_proto != SOCK_STREAM ||
|
||||
server->lc_state == LOCAL_STATE_UNBOUND ||
|
||||
server->lc_type != LOCAL_TYPE_PATHNAME)
|
||||
|
|
|
@ -387,11 +387,11 @@ errout_with_halfduplex:
|
|||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: psock_local_recvfrom
|
||||
* Name: local_recvfrom
|
||||
*
|
||||
* Description:
|
||||
* psock_local_recvfrom() receives messages from a local socket and may be
|
||||
* used to receive data on a socket whether or not it is connection-oriented.
|
||||
* local_recvfrom() receives messages from a local socket and may be used
|
||||
* to receive data on a socket whether or not it is connection-oriented.
|
||||
*
|
||||
* If from is not NULL, and the underlying protocol provides the source
|
||||
* address, this source address is filled in. The argument fromlen
|
||||
|
@ -409,14 +409,15 @@ errout_with_halfduplex:
|
|||
* Returned Value:
|
||||
* On success, returns the number of characters received. If no data is
|
||||
* available to be received and the peer has performed an orderly shutdown,
|
||||
* recv() will return 0. Otherwise, on errors, -1 is returned, and errno
|
||||
* is set appropriately (see receive from for the complete list).
|
||||
* recv() will return 0. Otherwise, on errors, a negated errno value is
|
||||
* returned (see recv_from() for the complete list of appropriate error
|
||||
* values).
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
ssize_t psock_local_recvfrom(FAR struct socket *psock, FAR void *buf,
|
||||
size_t len, int flags, FAR struct sockaddr *from,
|
||||
FAR socklen_t *fromlen)
|
||||
ssize_t local_recvfrom(FAR struct socket *psock, FAR void *buf,
|
||||
size_t len, int flags, FAR struct sockaddr *from,
|
||||
FAR socklen_t *fromlen)
|
||||
{
|
||||
DEBUGASSERT(psock && psock->s_conn && buf);
|
||||
|
||||
|
|
574
net/local/local_sockif.c
Normal file
574
net/local/local_sockif.c
Normal file
|
@ -0,0 +1,574 @@
|
|||
/****************************************************************************
|
||||
* net/local/local_sockif.c
|
||||
*
|
||||
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <nuttx/net/net.h>
|
||||
|
||||
#include "local/local.h"
|
||||
|
||||
#ifdef CONFIG_NET_LOCAL
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static int local_setup(FAR struct socket *psock, int protocol);
|
||||
static sockcaps_t local_sockcaps(FAR struct socket *psock);
|
||||
static void local_addref(FAR struct socket *psock);
|
||||
static int local_bind(FAR struct socket *psock,
|
||||
FAR const struct sockaddr *addr, socklen_t addrlen);
|
||||
static int local_connect(FAR struct socket *psock,
|
||||
FAR const struct sockaddr *addr, socklen_t addrlen);
|
||||
static int local_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
|
||||
FAR socklen_t *addrlen, FAR struct socket *newsock);
|
||||
static ssize_t local_send(FAR struct socket *psock, FAR const void *buf,
|
||||
size_t len, int flags);
|
||||
static ssize_t local_sendto(FAR struct socket *psock, FAR const void *buf,
|
||||
size_t len, int flags, FAR const struct sockaddr *to,
|
||||
socklen_t tolen);
|
||||
static int local_close(FAR struct socket *psock);
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
const struct sock_intf_s g_local_sockif =
|
||||
{
|
||||
local_setup, /* si_setup */
|
||||
local_sockcaps, /* si_sockcaps */
|
||||
local_addref, /* si_addref */
|
||||
local_bind, /* si_bind */
|
||||
local_listen, /* si_listen */
|
||||
local_connect, /* si_connect */
|
||||
local_accept, /* si_accept */
|
||||
local_send, /* si_send */
|
||||
local_sendto, /* si_sendto */
|
||||
local_recvfrom, /* si_recvfrom */
|
||||
local_close /* si_close */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: local_sockif_alloc
|
||||
*
|
||||
* Description:
|
||||
* Allocate and attach a local, Unix domain connection structure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int local_sockif_alloc(FAR struct socket *psock)
|
||||
{
|
||||
/* Allocate the local connection structure */
|
||||
|
||||
FAR struct local_conn_s *conn = local_alloc();
|
||||
if (conn == NULL)
|
||||
{
|
||||
/* Failed to reserve a connection structure */
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Set the reference count on the connection structure. This reference
|
||||
* count will be incremented only if the socket is dup'ed
|
||||
*/
|
||||
|
||||
DEBUGASSERT(conn->lc_crefs == 0);
|
||||
conn->lc_crefs = 1;
|
||||
|
||||
/* Save the pre-allocated connection in the socket structure */
|
||||
|
||||
psock->s_conn = conn;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: local_setup
|
||||
*
|
||||
* Description:
|
||||
* Called for socket() to verify that the provided socket type and
|
||||
* protocol are usable by this address family. Perform any family-
|
||||
* specific socket fields.
|
||||
*
|
||||
* Parameters:
|
||||
* psock A pointer to a user allocated socket structure to be initialized.
|
||||
* protocol (see sys/socket.h)
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) is returned on success. Otherwise, a negater errno value is
|
||||
* returned.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int local_setup(FAR struct socket *psock, int protocol)
|
||||
{
|
||||
/* Allocate the appropriate connection structure. This reserves the
|
||||
* the connection structure is is unallocated at this point. It will
|
||||
* not actually be initialized until the socket is connected.
|
||||
*
|
||||
* Only SOCK_STREAM and SOCK_DGRAM and possible SOCK_RAW are supported.
|
||||
*/
|
||||
|
||||
switch (psock->s_type)
|
||||
{
|
||||
#ifdef CONFIG_NET_TCP
|
||||
case SOCK_STREAM:
|
||||
if (protocol != 0 && protocol != IPPROTO_TCP)
|
||||
{
|
||||
return -EPROTONOSUPPORT;
|
||||
}
|
||||
|
||||
/* Allocate and attach the local connection structure */
|
||||
|
||||
return local_sockif_alloc(psock);
|
||||
#endif /* CONFIG_NET_TCP */
|
||||
|
||||
#ifdef CONFIG_NET_UDP
|
||||
case SOCK_DGRAM:
|
||||
if (protocol != 0 && protocol != IPPROTO_UDP)
|
||||
{
|
||||
return -EPROTONOSUPPORT;
|
||||
}
|
||||
|
||||
/* Allocate and attach the local connection structure */
|
||||
|
||||
return local_sockif_alloc(psock);
|
||||
#endif /* CONFIG_NET_UDP */
|
||||
|
||||
default:
|
||||
return -EPROTONOSUPPORT;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: local_sockcaps
|
||||
*
|
||||
* Description:
|
||||
* Return the bit encoded capabilities of this socket.
|
||||
*
|
||||
* Parameters:
|
||||
* psock - Socket structure of the socket whose capabilities are being
|
||||
* queried.
|
||||
*
|
||||
* Returned Value:
|
||||
* The set of socket cababilities is returned.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static sockcaps_t local_sockcaps(FAR struct socket *psock)
|
||||
{
|
||||
return SOCKCAP_NONBLOCKING;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: local_addref
|
||||
*
|
||||
* Description:
|
||||
* Increment the refernce count on the underlying connection structure.
|
||||
*
|
||||
* Parameters:
|
||||
* psock - Socket structure of the socket whose reference count will be
|
||||
* incremented.
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void local_addref(FAR struct socket *psock)
|
||||
{
|
||||
FAR struct local_conn_s *conn;
|
||||
|
||||
DEBUGASSERT(psock != NULL && psock->s_conn != NULL &&
|
||||
psock->s_domain == PF_LOCAL);
|
||||
|
||||
conn = psock->s_conn;
|
||||
DEBUGASSERT(conn->lc_crefs > 0 && conn->lc_crefs < 255);
|
||||
conn->lc_crefs++;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: local_bind
|
||||
*
|
||||
* Description:
|
||||
* local_bind() gives the socket 'psock' the local address 'addr'. 'addr'
|
||||
* is 'addrlen' bytes long. Traditionally, this is called "assigning a
|
||||
* name to a socket." When a socket is created with socket(), it exists
|
||||
* in a name space (address family) but has no name assigned.
|
||||
*
|
||||
* Parameters:
|
||||
* psock Socket structure of the socket to bind
|
||||
* addr Socket local address
|
||||
* addrlen Length of 'addr'
|
||||
*
|
||||
* Returned Value:
|
||||
* 0 on success; A negated errno value is returned on failure. See
|
||||
* bind() for a list a appropriate error values.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int local_bind(FAR struct socket *psock,
|
||||
FAR const struct sockaddr *addr, socklen_t addrlen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Verify that a valid address has been provided */
|
||||
|
||||
if (addr->sa_family != AF_LOCAL || addrlen < sizeof(sa_family_t))
|
||||
{
|
||||
nerr("ERROR: Invalid address length: %d < %d\n",
|
||||
addrlen, sizeof(sa_family_t));
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
/* Perform the binding depending on the protocol type */
|
||||
|
||||
switch (psock->s_type)
|
||||
{
|
||||
/* Bind a local TCP/IP stream or datagram socket */
|
||||
|
||||
#if defined(ONFIG_NET_TCP) || defined(CONFIG_NET_UDP)
|
||||
#ifdef CONFIG_NET_TCP
|
||||
case SOCK_STREAM:
|
||||
#endif
|
||||
#ifdef CONFIG_NET_UDP
|
||||
case SOCK_DGRAM:
|
||||
#endif
|
||||
{
|
||||
/* Bind the Unix domain connection structure */
|
||||
|
||||
ret psock_local_bind(psock, addr, addrlen);
|
||||
|
||||
/* Mark the socket bound */
|
||||
|
||||
if (ret >= 0)
|
||||
{
|
||||
psock->s_flags |= _SF_BOUND;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_NET_TCP || CONFIG_NET_UDP*/
|
||||
|
||||
default:
|
||||
ret = -EBADF;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: local_connect
|
||||
*
|
||||
* Description:
|
||||
* local_connect() connects the local socket referred to by the structure
|
||||
* 'psock' to the address specified by 'addr'. The addrlen argument
|
||||
* specifies the size of 'addr'. The format of the address in 'addr' is
|
||||
* determined by the address space of the socket 'psock'.
|
||||
*
|
||||
* If the socket 'psock' is of type SOCK_DGRAM then 'addr' is the address
|
||||
* to which datagrams are sent by default, and the only address from which
|
||||
* datagrams are received. If the socket is of type SOCK_STREAM or
|
||||
* SOCK_SEQPACKET, this call attempts to make a connection to the socket
|
||||
* that is bound to the address specified by 'addr'.
|
||||
*
|
||||
* Generally, connection-based protocol sockets may successfully
|
||||
* local_connect() only once; connectionless protocol sockets may use
|
||||
* local_connect() multiple times to change their association.
|
||||
* Connectionless sockets may dissolve the association by connecting to
|
||||
* an address with the sa_family member of sockaddr set to AF_UNSPEC.
|
||||
*
|
||||
* Parameters:
|
||||
* psock Pointer to a socket structure initialized by psock_socket()
|
||||
* addr Server address (form depends on type of socket)
|
||||
* addrlen Length of actual 'addr'
|
||||
*
|
||||
* Returned Value:
|
||||
* 0 on success; a negated errno value on failue. See connect() for the
|
||||
* list of appropriate errno values to be returned.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int local_connect(FAR struct socket *psock,
|
||||
FAR const struct sockaddr *addr, socklen_t addrlen)
|
||||
{
|
||||
/* Verify that a valid address has been provided */
|
||||
|
||||
if (addr->sa_family != AF_LOCAL || addrlen < sizeof(sa_family_t))
|
||||
{
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
/* 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))
|
||||
{
|
||||
return -EISCONN;
|
||||
}
|
||||
|
||||
/* It's not... Connect to the local Unix domain server */
|
||||
|
||||
return psock_local_connect(psock, addr);
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_NET_TCP */
|
||||
|
||||
#ifdef CONFIG_NET_UDP
|
||||
case SOCK_DGRAM:
|
||||
{
|
||||
/* Perform the datagram connection logic */
|
||||
|
||||
return psock_local_connect(psock, addr);
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_NET_UDP */
|
||||
|
||||
default:
|
||||
return -EBADF;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: local_send
|
||||
*
|
||||
* Description:
|
||||
* Implements the send() operation for the case of the local, Unix socket.
|
||||
*
|
||||
* Parameters:
|
||||
* psock An instance of the internal socket structure.
|
||||
* buf Data to send
|
||||
* len Length of data to send
|
||||
* flags Send flags
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, returns the number of characters sent. On error, a negated
|
||||
* errno value is returned (see send() for the list of appropriate error
|
||||
* values.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static ssize_t local_send(FAR struct socket *psock, FAR const void *buf,
|
||||
size_t len, int flags)
|
||||
{
|
||||
ssize_t ret;
|
||||
|
||||
switch (psock->s_type)
|
||||
{
|
||||
#ifdef CONFIG_NET_TCP
|
||||
case SOCK_STREAM:
|
||||
{
|
||||
/* Local TCP packet send */
|
||||
|
||||
ret = psock_local_send(psock, buf, len, flags);
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_NET_TCP */
|
||||
|
||||
#ifdef CONFIG_NET_UDP
|
||||
case SOCK_DGRAM:
|
||||
{
|
||||
/* Local UDP packet send */
|
||||
#warning Missing logic
|
||||
ret = -ENOSYS;
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_NET_UDP */
|
||||
|
||||
default:
|
||||
{
|
||||
/* EDESTADDRREQ. Signifies that the socket is not connection-mode
|
||||
* and no peer address is set.
|
||||
*/
|
||||
|
||||
ret = -EDESTADDRREQ;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: local_sendto
|
||||
*
|
||||
* Description:
|
||||
* Implements the sendto() operation for the case of the local, Unix socket.
|
||||
*
|
||||
* Parameters:
|
||||
* psock A pointer to a NuttX-specific, internal socket structure
|
||||
* buf Data to send
|
||||
* len Length of data to send
|
||||
* flags Send flags
|
||||
* to Address of recipient
|
||||
* tolen The length of the address structure
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, returns the number of characters sent. On error, a negated
|
||||
* errno value is returned (see send_to() for the list of appropriate error
|
||||
* values.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
ssize_t local_sendto(FAR struct socket *psock, FAR const void *buf,
|
||||
size_t len, int flags, FAR const struct sockaddr *to,
|
||||
socklen_t tolen)
|
||||
{
|
||||
ssize_t nsent;
|
||||
|
||||
/* Verify that a valid address has been provided */
|
||||
|
||||
if (to->sa_family != AF_LOCAL || tolen < sizeof(sa_family_t))
|
||||
{
|
||||
nerr("ERROR: Unrecognized address family: %d\n",
|
||||
to->sa_family);
|
||||
return -EAFNOSUPPORT;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET_UDP
|
||||
/* If this is a connected socket, then return EISCONN */
|
||||
|
||||
if (psock->s_type != SOCK_DGRAM)
|
||||
{
|
||||
nerr("ERROR: Connected socket\n");
|
||||
return -EISCONN;
|
||||
}
|
||||
|
||||
/* Now handle the local UDP sendto() operation */
|
||||
|
||||
nsent = psock_local_sendto(psock, buf, len, flags, to, tolen);
|
||||
#else
|
||||
nsent = -EISCONN;
|
||||
#endif /* CONFIG_NET_LOCAL_DGRAM */
|
||||
|
||||
return nsent;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: local_close
|
||||
*
|
||||
* Description:
|
||||
* Performs the close operation on a local, Unix socket instance
|
||||
*
|
||||
* Parameters:
|
||||
* psock Socket instance
|
||||
*
|
||||
* Returned Value:
|
||||
* 0 on success; a negated errno value is returned on any failure.
|
||||
*
|
||||
* Assumptions:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int local_close(FAR struct socket *psock)
|
||||
{
|
||||
/* Perform some pre-close operations for the local address type */
|
||||
|
||||
switch (psock->s_type)
|
||||
{
|
||||
#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_UDP)
|
||||
#ifdef CONFIG_NET_TCP
|
||||
case SOCK_STREAM:
|
||||
#endif
|
||||
#ifdef CONFIG_NET_UDP
|
||||
case SOCK_DGRAM:
|
||||
#endif
|
||||
{
|
||||
FAR struct local_conn_s *conn = psock->s_conn;
|
||||
|
||||
/* Is this the last reference to the connection structure (there
|
||||
* could be more if the socket was dup'ed).
|
||||
*/
|
||||
|
||||
if (conn->lc_crefs <= 1)
|
||||
{
|
||||
conn->lc_crefs = 0;
|
||||
local_release(conn);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No.. Just decrement the reference count */
|
||||
|
||||
conn->lc_crefs--;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
#endif /* CONFIG_NET_TCP || CONFIG_NET_UDP*/
|
||||
|
||||
default:
|
||||
return -EBADF;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name:
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* Returned Value:
|
||||
*
|
||||
* Assumptions:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#endif /* CONFIG_NET_LOCAL */
|
|
@ -39,7 +39,9 @@ ifeq ($(CONFIG_NET_PKT),y)
|
|||
|
||||
# Socket layer
|
||||
|
||||
SOCK_CSRCS += pkt_sockif.c
|
||||
SOCK_CSRCS += pkt_send.c
|
||||
SOCK_CSRCS += pkt_recvfrom.c
|
||||
|
||||
# Transport layer
|
||||
|
||||
|
|
|
@ -91,12 +91,17 @@ extern "C"
|
|||
# define EXTERN extern
|
||||
#endif
|
||||
|
||||
/* The packet socket interface */
|
||||
|
||||
EXTERN const struct sock_intf_s g_pkt_sockif;
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
struct net_driver_s; /* Forward reference */
|
||||
struct eth_hdr_s; /* Forward reference */
|
||||
struct socket; /* Forward reference */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pkt_initialize()
|
||||
|
@ -197,6 +202,41 @@ uint16_t pkt_callback(FAR struct net_driver_s *dev,
|
|||
|
||||
/* pkt_input() is prototyped in include/nuttx/net/pkt.h */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pkt_recvfrom
|
||||
*
|
||||
* Description:
|
||||
* Implements the socket recvfrom interface for the case of the AF_INET
|
||||
* and AF_INET6 address families. pkt_recvfrom() receives messages from
|
||||
* a socket, and may be used to receive data on a socket whether or not it
|
||||
* is connection-oriented.
|
||||
*
|
||||
* If 'from' is not NULL, and the underlying protocol provides the source
|
||||
* address, this source address is filled in. The argument 'fromlen' is
|
||||
* initialized to the size of the buffer associated with from, and
|
||||
* modified on return to indicate the actual size of the address stored
|
||||
* there.
|
||||
*
|
||||
* Parameters:
|
||||
* psock A pointer to a NuttX-specific, internal socket structure
|
||||
* buf Buffer to receive data
|
||||
* len Length of buffer
|
||||
* flags Receive flags
|
||||
* from Address of source (may be NULL)
|
||||
* fromlen The length of the address structure
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, returns the number of characters received. If no data is
|
||||
* available to be received and the peer has performed an orderly shutdown,
|
||||
* recv() will return 0. Otherwise, on errors, a negated errno value is
|
||||
* returned (see recvfrom() for the list of appropriate error values).
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
ssize_t pkt_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
|
||||
int flags, FAR struct sockaddr *from,
|
||||
FAR socklen_t *fromlen);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pkt_find_device
|
||||
*
|
||||
|
|
485
net/pkt/pkt_recvfrom.c
Normal file
485
net/pkt/pkt_recvfrom.c
Normal file
|
@ -0,0 +1,485 @@
|
|||
/****************************************************************************
|
||||
* net/socket/pkt_recvfrom.c
|
||||
*
|
||||
* Copyright (C) 2007-2009, 2011-2017 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#ifdef CONFIG_NET
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <arch/irq.h>
|
||||
|
||||
#include <nuttx/clock.h>
|
||||
#include <nuttx/semaphore.h>
|
||||
#include <nuttx/net/net.h>
|
||||
#include <nuttx/net/netdev.h>
|
||||
|
||||
#include "netdev/netdev.h"
|
||||
#include "devif/devif.h"
|
||||
#include "pkt/pkt.h"
|
||||
#include "socket/socket.h"
|
||||
#include <netpacket/packet.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
struct pkt_recvfrom_s
|
||||
{
|
||||
FAR struct devif_callback_s *pr_cb; /* Reference to callback instance */
|
||||
sem_t pr_sem; /* Semaphore signals recv completion */
|
||||
size_t pr_buflen; /* Length of receive buffer */
|
||||
uint8_t *pr_buffer; /* Pointer to receive buffer */
|
||||
ssize_t pr_recvlen; /* The received length */
|
||||
int pr_result; /* Success:OK, failure:negated errno */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pkt_add_recvlen
|
||||
*
|
||||
* Description:
|
||||
* Update information about space available for new data and update size
|
||||
* of data in buffer, This logic accounts for the case where
|
||||
* recvfrom_udpreadahead() sets state.pr_recvlen == -1 .
|
||||
*
|
||||
* Parameters:
|
||||
* pstate recvfrom state structure
|
||||
* recvlen size of new data appended to buffer
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline void pkt_add_recvlen(FAR struct pkt_recvfrom_s *pstate,
|
||||
size_t recvlen)
|
||||
{
|
||||
if (pstate->pr_recvlen < 0)
|
||||
{
|
||||
pstate->pr_recvlen = 0;
|
||||
}
|
||||
|
||||
pstate->pr_recvlen += recvlen;
|
||||
pstate->pr_buffer += recvlen;
|
||||
pstate->pr_buflen -= recvlen;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pkt_recvfrom_newdata
|
||||
*
|
||||
* Description:
|
||||
* Copy the read data from the packet
|
||||
*
|
||||
* Parameters:
|
||||
* dev The structure of the network driver that caused the interrupt
|
||||
* pstate recvfrom state structure
|
||||
*
|
||||
* Returned Value:
|
||||
* None.
|
||||
*
|
||||
* Assumptions:
|
||||
* The network is locked.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void pkt_recvfrom_newdata(FAR struct net_driver_s *dev,
|
||||
FAR struct pkt_recvfrom_s *pstate)
|
||||
{
|
||||
size_t recvlen;
|
||||
|
||||
if (dev->d_len > pstate->pr_buflen)
|
||||
{
|
||||
recvlen = pstate->pr_buflen;
|
||||
}
|
||||
else
|
||||
{
|
||||
recvlen = dev->d_len;
|
||||
}
|
||||
|
||||
/* Copy the new packet data into the user buffer */
|
||||
|
||||
memcpy(pstate->pr_buffer, dev->d_buf, recvlen);
|
||||
ninfo("Received %d bytes (of %d)\n", (int)recvlen, (int)dev->d_len);
|
||||
|
||||
/* Update the accumulated size of the data read */
|
||||
|
||||
pkt_add_recvlen(pstate, recvlen);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pkt_recvfrom_sender
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* Returned Values:
|
||||
*
|
||||
* Assumptions:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline void pkt_recvfrom_sender(FAR struct net_driver_s *dev,
|
||||
FAR struct pkt_recvfrom_s *pstate)
|
||||
{
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pkt_recvfrom_interrupt
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* Returned Values:
|
||||
*
|
||||
* Assumptions:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static uint16_t pkt_recvfrom_interrupt(FAR struct net_driver_s *dev,
|
||||
FAR void *pvconn, FAR void *pvpriv,
|
||||
uint16_t flags)
|
||||
{
|
||||
struct pkt_recvfrom_s *pstate = (struct pkt_recvfrom_s *)pvpriv;
|
||||
|
||||
ninfo("flags: %04x\n", flags);
|
||||
|
||||
/* 'priv' might be null in some race conditions (?) */
|
||||
|
||||
if (pstate)
|
||||
{
|
||||
/* If a new packet is available, then complete the read action. */
|
||||
|
||||
if ((flags & PKT_NEWDATA) != 0)
|
||||
{
|
||||
/* Copy the packet */
|
||||
|
||||
pkt_recvfrom_newdata(dev, pstate);
|
||||
|
||||
/* We are finished. */
|
||||
|
||||
ninfo("PKT done\n");
|
||||
|
||||
/* Don't allow any further call backs. */
|
||||
|
||||
pstate->pr_cb->flags = 0;
|
||||
pstate->pr_cb->priv = NULL;
|
||||
pstate->pr_cb->event = NULL;
|
||||
#if 0
|
||||
/* Save the sender's address in the caller's 'from' location */
|
||||
|
||||
pkt_recvfrom_sender(dev, pstate);
|
||||
#endif
|
||||
/* indicate that the data has been consumed */
|
||||
|
||||
flags &= ~PKT_NEWDATA;
|
||||
|
||||
/* Wake up the waiting thread, returning the number of bytes
|
||||
* actually read.
|
||||
*/
|
||||
|
||||
sem_post(&pstate->pr_sem);
|
||||
}
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pkt_recvfrom_initialize
|
||||
*
|
||||
* Description:
|
||||
* Initialize the state structure
|
||||
*
|
||||
* Parameters:
|
||||
* psock Pointer to the socket structure for the socket
|
||||
* buf Buffer to receive data
|
||||
* len Length of buffer
|
||||
* pstate A pointer to the state structure to be initialized
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
* Assumptions:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void pkt_recvfrom_initialize(FAR struct socket *psock, FAR void *buf,
|
||||
size_t len, FAR struct sockaddr *infrom,
|
||||
FAR socklen_t *fromlen,
|
||||
FAR struct pkt_recvfrom_s *pstate)
|
||||
{
|
||||
/* Initialize the state structure. */
|
||||
|
||||
memset(pstate, 0, sizeof(struct pkt_recvfrom_s));
|
||||
|
||||
/* This semaphore is used for signaling and, hence, should not have
|
||||
* priority inheritance enabled.
|
||||
*/
|
||||
|
||||
(void)sem_init(&pstate->pr_sem, 0, 0); /* Doesn't really fail */
|
||||
(void)sem_setprotocol(&pstate->pr_sem, SEM_PRIO_NONE);
|
||||
|
||||
pstate->pr_buflen = len;
|
||||
pstate->pr_buffer = buf;
|
||||
}
|
||||
|
||||
/* The only un-initialization that has to be performed is destroying the
|
||||
* semaphore.
|
||||
*/
|
||||
|
||||
#define pkt_recvfrom_uninitialize(s) sem_destroy(&(s)->pr_sem)
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pkt_recvfrom_result
|
||||
*
|
||||
* Description:
|
||||
* Evaluate the result of the recv operations
|
||||
*
|
||||
* Parameters:
|
||||
* result The result of the net_lockedwait operation (may indicate EINTR)
|
||||
* pstate A pointer to the state structure to be initialized
|
||||
*
|
||||
* Returned Value:
|
||||
* The result of the recv operation with errno set appropriately
|
||||
*
|
||||
* Assumptions:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static ssize_t pkt_recvfrom_result(int result, struct pkt_recvfrom_s *pstate)
|
||||
{
|
||||
int save_errno = get_errno(); /* In case something we do changes it */
|
||||
|
||||
/* Check for a error/timeout detected by the interrupt handler. Errors are
|
||||
* signaled by negative errno values for the rcv length
|
||||
*/
|
||||
|
||||
if (pstate->pr_result < 0)
|
||||
{
|
||||
/* This might return EAGAIN on a timeout or ENOTCONN on loss of
|
||||
* connection (TCP only)
|
||||
*/
|
||||
|
||||
return pstate->pr_result;
|
||||
}
|
||||
|
||||
/* If net_lockedwait failed, then we were probably reawakened by a signal. In
|
||||
* this case, net_lockedwait will have set errno appropriately.
|
||||
*/
|
||||
|
||||
if (result < 0)
|
||||
{
|
||||
return -save_errno;
|
||||
}
|
||||
|
||||
return pstate->pr_recvlen;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pkt_recvfrom_rxnotify
|
||||
*
|
||||
* Description:
|
||||
* Notify the appropriate device driver that we are ready to receive a
|
||||
* packet (PKT)
|
||||
*
|
||||
* Parameters:
|
||||
* conn - The PKT connection structure
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if 0 /* Not implemented */
|
||||
static void pkt_recvfrom_rxnotify(FAR struct pkt_conn_s *conn)
|
||||
{
|
||||
# warning Missing logic
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pkt_recvfrom
|
||||
*
|
||||
* Description:
|
||||
* Implements the socket recvfrom interface for the case of the AF_INET
|
||||
* and AF_INET6 address families. pkt_recvfrom() receives messages from
|
||||
* a socket, and may be used to receive data on a socket whether or not it
|
||||
* is connection-oriented.
|
||||
*
|
||||
* If 'from' is not NULL, and the underlying protocol provides the source
|
||||
* address, this source address is filled in. The argument 'fromlen' is
|
||||
* initialized to the size of the buffer associated with from, and
|
||||
* modified on return to indicate the actual size of the address stored
|
||||
* there.
|
||||
*
|
||||
* Parameters:
|
||||
* psock A pointer to a NuttX-specific, internal socket structure
|
||||
* buf Buffer to receive data
|
||||
* len Length of buffer
|
||||
* flags Receive flags
|
||||
* from Address of source (may be NULL)
|
||||
* fromlen The length of the address structure
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, returns the number of characters received. If no data is
|
||||
* available to be received and the peer has performed an orderly shutdown,
|
||||
* recv() will return 0. Otherwise, on errors, a negated errno value is
|
||||
* returned (see recvfrom() for the list of appropriate error values).
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
ssize_t pkt_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
|
||||
int flags, FAR struct sockaddr *from,
|
||||
FAR socklen_t *fromlen)
|
||||
{
|
||||
FAR struct pkt_conn_s *conn = (FAR struct pkt_conn_s *)psock->s_conn;
|
||||
FAR struct net_driver_s *dev;
|
||||
struct pkt_recvfrom_s state;
|
||||
ssize_t ret;
|
||||
|
||||
/* If a 'from' address has been provided, verify that it is large
|
||||
* enough to hold this address family.
|
||||
*/
|
||||
|
||||
if (from != NULL && *fromlen < sizeof(sa_family_t))
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (psock->s_type != SOCK_RAW)
|
||||
{
|
||||
nerr("ERROR: Unsupported socket type: %d\n", psock->s_type);
|
||||
ret = -ENOSYS;
|
||||
}
|
||||
|
||||
/* Perform the packet recvfrom() operation */
|
||||
|
||||
/* Initialize the state structure. This is done with interrupts
|
||||
* disabled because we don't want anything to happen until we
|
||||
* are ready.
|
||||
*/
|
||||
|
||||
net_lock();
|
||||
pkt_recvfrom_initialize(psock, buf, len, from, fromlen, &state);
|
||||
|
||||
/* Get the device driver that will service this transfer */
|
||||
|
||||
dev = pkt_find_device(conn);
|
||||
if (dev == NULL)
|
||||
{
|
||||
ret = -ENODEV;
|
||||
goto errout_with_state;
|
||||
}
|
||||
|
||||
/* TODO pkt_recvfrom_initialize() expects from to be of type sockaddr_in, but
|
||||
* in our case is sockaddr_ll
|
||||
*/
|
||||
|
||||
#if 0
|
||||
ret = pkt_connect(conn, NULL);
|
||||
if (ret < 0)
|
||||
{
|
||||
goto errout_with_state;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set the socket state to receiving */
|
||||
|
||||
psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_RECV);
|
||||
|
||||
/* Set up the callback in the connection */
|
||||
|
||||
state.pr_cb = pkt_callback_alloc(dev, conn);
|
||||
if (state.pr_cb)
|
||||
{
|
||||
state.pr_cb->flags = (PKT_NEWDATA | PKT_POLL);
|
||||
state.pr_cb->priv = (FAR void *)&state;
|
||||
state.pr_cb->event = pkt_recvfrom_interrupt;
|
||||
|
||||
/* Notify the device driver of the receive call */
|
||||
|
||||
#if 0 /* Not implemented */
|
||||
pkt_recvfrom_rxnotify(conn);
|
||||
#endif
|
||||
|
||||
/* Wait for either the receive to complete or for an error/timeout to occur.
|
||||
* NOTES: (1) net_lockedwait will also terminate if a signal is received, (2)
|
||||
* interrupts are disabled! They will be re-enabled while the task sleeps
|
||||
* and automatically re-enabled when the task restarts.
|
||||
*/
|
||||
|
||||
ret = net_lockedwait(&state.pr_sem);
|
||||
|
||||
/* Make sure that no further interrupts are processed */
|
||||
|
||||
pkt_callback_free(dev, conn, state.pr_cb);
|
||||
ret = pkt_recvfrom_result(ret, &state);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = -EBUSY;
|
||||
}
|
||||
|
||||
/* Set the socket state to idle */
|
||||
|
||||
psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE);
|
||||
|
||||
errout_with_state:
|
||||
net_unlock();
|
||||
pkt_recvfrom_uninitialize(&state);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NET */
|
551
net/pkt/pkt_sockif.c
Normal file
551
net/pkt/pkt_sockif.c
Normal file
|
@ -0,0 +1,551 @@
|
|||
/****************************************************************************
|
||||
* net/socket/pkt_sockif.c
|
||||
*
|
||||
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/net/net.h>
|
||||
|
||||
#include "pkt/pkt.h"
|
||||
|
||||
#ifdef CONFIG_NET_PKT
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static int pkt_setup(FAR struct socket *psock, int protocol);
|
||||
static sockcaps_t pkt_sockcaps(FAR struct socket *psock);
|
||||
static void pkt_addref(FAR struct socket *psock);
|
||||
static int pkt_bind(FAR struct socket *psock,
|
||||
FAR const struct sockaddr *addr, socklen_t addrlen);
|
||||
static int pkt_listen(FAR struct socket *psock, int backlog);
|
||||
static int pkt_connect(FAR struct socket *psock,
|
||||
FAR const struct sockaddr *addr, socklen_t addrlen);
|
||||
static int pkt_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
|
||||
FAR socklen_t *addrlen, FAR struct socket *newsock);
|
||||
static ssize_t pkt_send(FAR struct socket *psock, FAR const void *buf,
|
||||
size_t len, int flags);
|
||||
static ssize_t pkt_sendto(FAR struct socket *psock, FAR const void *buf,
|
||||
size_t len, int flags, FAR const struct sockaddr *to,
|
||||
socklen_t tolen);
|
||||
static int pkt_close(FAR struct socket *psock);
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
const struct sock_intf_s g_pkt_sockif =
|
||||
{
|
||||
pkt_setup, /* si_setup */
|
||||
pkt_sockcaps, /* si_sockcaps */
|
||||
pkt_addref, /* si_addref */
|
||||
pkt_bind, /* si_bind */
|
||||
pkt_listen, /* si_listen */
|
||||
pkt_connect, /* si_connect */
|
||||
pkt_accept, /* si_accept */
|
||||
pkt_send, /* si_send */
|
||||
pkt_sendto, /* si_sendto */
|
||||
pkt_recvfrom, /* si_recvfrom */
|
||||
pkt_close /* si_close */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pkt_sockif_alloc
|
||||
*
|
||||
* Description:
|
||||
* Allocate and attach a raw packet connection structure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int pkt_sockif_alloc(FAR struct socket *psock)
|
||||
{
|
||||
/* Allocate the packet socket connection structure and save in the new
|
||||
* socket instance.
|
||||
*/
|
||||
|
||||
FAR struct pkt_conn_s *conn = pkt_alloc();
|
||||
if (conn == NULL)
|
||||
{
|
||||
/* Failed to reserve a connection structure */
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Set the reference count on the connection structure. This reference
|
||||
* count will be incremented only if the socket is dup'ed
|
||||
*/
|
||||
|
||||
DEBUGASSERT(conn->crefs == 0);
|
||||
conn->crefs = 1;
|
||||
|
||||
/* Save the pre-allocated connection in the socket structure */
|
||||
|
||||
psock->s_conn = conn;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pkt_setup
|
||||
*
|
||||
* Description:
|
||||
* Called for socket() to verify that the provided socket type and
|
||||
* protocol are usable by this address family. Perform any family-
|
||||
* specific socket fields.
|
||||
*
|
||||
* Parameters:
|
||||
* psock A pointer to a user allocated socket structure to be
|
||||
* initialized.
|
||||
* protocol (see sys/socket.h)
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) is returned on success. Otherwise, a negater errno value is
|
||||
* returned.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int pkt_setup(FAR struct socket *psock, int protocol)
|
||||
{
|
||||
/* Allocate the appropriate connection structure. This reserves the
|
||||
* the connection structure is is unallocated at this point. It will
|
||||
* not actually be initialized until the socket is connected.
|
||||
*
|
||||
* Only SOCK_RAW is supported.
|
||||
*/
|
||||
|
||||
if (psock->s_type == SOCK_RAW)
|
||||
{
|
||||
return pkt_sockif_alloc(psock);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -EPROTONOSUPPORT;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pkt_sockcaps
|
||||
*
|
||||
* Description:
|
||||
* Return the bit encoded capabilities of this socket.
|
||||
*
|
||||
* Parameters:
|
||||
* psock - Socket structure of the socket whose capabilities are being
|
||||
* queried.
|
||||
*
|
||||
* Returned Value:
|
||||
* The set of socket cababilities is returned.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static sockcaps_t pkt_sockcaps(FAR struct socket *psock)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pkt_addref
|
||||
*
|
||||
* Description:
|
||||
* Increment the refernce count on the underlying connection structure.
|
||||
*
|
||||
* Parameters:
|
||||
* psock - Socket structure of the socket whose reference count will be
|
||||
* incremented.
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void pkt_addref(FAR struct socket *psock)
|
||||
{
|
||||
FAR struct pkt_conn_s *conn;
|
||||
|
||||
DEBUGASSERT(psock != NULL && psock->s_conn != NULL &&
|
||||
psock->s_type == SOCK_RAW);
|
||||
|
||||
conn = psock->s_conn;
|
||||
DEBUGASSERT(conn->crefs > 0 && conn->crefs < 255);
|
||||
conn->crefs++;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pkt_connect
|
||||
*
|
||||
* Description:
|
||||
* pkt_connect() connects the local socket referred to by the structure
|
||||
* 'psock' to the address specified by 'addr'. The addrlen argument
|
||||
* specifies the size of 'addr'. The format of the address in 'addr' is
|
||||
* determined by the address space of the socket 'psock'.
|
||||
*
|
||||
* If the socket 'psock' is of type SOCK_DGRAM then 'addr' is the address
|
||||
* to which datagrams are sent by default, and the only address from which
|
||||
* datagrams are received. If the socket is of type SOCK_STREAM or
|
||||
* SOCK_SEQPACKET, this call attempts to make a connection to the socket
|
||||
* that is bound to the address specified by 'addr'.
|
||||
*
|
||||
* Generally, connection-based protocol sockets may successfully
|
||||
* pkt_connect() only once; connectionless protocol sockets may use
|
||||
* pkt_connect() multiple times to change their association.
|
||||
* Connectionless sockets may dissolve the association by connecting to
|
||||
* an address with the sa_family member of sockaddr set to AF_UNSPEC.
|
||||
*
|
||||
* Parameters:
|
||||
* psock Pointer to a socket structure initialized by psock_socket()
|
||||
* addr Server address (form depends on type of socket)
|
||||
* addrlen Length of actual 'addr'
|
||||
*
|
||||
* Returned Value:
|
||||
* 0 on success; a negated errno value on failue. See connect() for the
|
||||
* list of appropriate errno values to be returned.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int pkt_connect(FAR struct socket *psock,
|
||||
FAR const struct sockaddr *addr, socklen_t addrlen)
|
||||
{
|
||||
return -EAFNOSUPPORT;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pkt_accept
|
||||
*
|
||||
* Description:
|
||||
* The pkt_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 pkt_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, pkt_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, pkt_accept returns
|
||||
* EAGAIN.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Returned Value:
|
||||
* Returns 0 (OK) on success. On failure, it returns a negated errno
|
||||
* value. See accept() for a desrciption of the approriate error value.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int pkt_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
|
||||
FAR socklen_t *addrlen, FAR struct socket *newsock)
|
||||
{
|
||||
return -EAFNOSUPPORT;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pkt_bind
|
||||
*
|
||||
* Description:
|
||||
* pkt_bind() gives the socket 'psock' the local address 'addr'. 'addr'
|
||||
* is 'addrlen' bytes long. Traditionally, this is called "assigning a
|
||||
* name to a socket." When a socket is created with socket(), it exists
|
||||
* in a name space (address family) but has no name assigned.
|
||||
*
|
||||
* Parameters:
|
||||
* psock Socket structure of the socket to bind
|
||||
* addr Socket local address
|
||||
* addrlen Length of 'addr'
|
||||
*
|
||||
* Returned Value:
|
||||
* 0 on success; A negated errno value is returned on failure. See
|
||||
* bind() for a list a appropriate error values.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int pkt_bind(FAR struct socket *psock, FAR const struct sockaddr *addr,
|
||||
socklen_t addrlen)
|
||||
{
|
||||
#if 0
|
||||
char hwaddr[6] = /* our MAC for debugging */
|
||||
{
|
||||
0x00, 0xa1, 0xb1, 0xc1, 0xd1, 0xe1
|
||||
};
|
||||
#endif
|
||||
char hwaddr[6] = /* MAC from ifconfig */
|
||||
{
|
||||
0x00, 0xe0, 0xde, 0xad, 0xbe, 0xef
|
||||
};
|
||||
int ifindex;
|
||||
|
||||
/* Verify that a valid address has been provided */
|
||||
|
||||
if (addr->sa_family != AF_PACKET || addrlen < sizeof(struct sockaddr_ll)
|
||||
{
|
||||
nerr("ERROR: Invalid address length: %d < %d\n",
|
||||
addrlen, sizeof(struct sockaddr_ll);
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
/* Bind a raw socket to an network device. */
|
||||
|
||||
if (psock->s_type == SOCK_RAW)
|
||||
{
|
||||
FAR struct pkt_conn_s *conn = (FAR struct pkt_conn_s *)psock->s_conn;
|
||||
|
||||
/* Look at the addr and identify network interface */
|
||||
|
||||
ifindex = addr->sll_ifindex;
|
||||
|
||||
#if 0
|
||||
/* Get the MAC address of that interface */
|
||||
|
||||
memcpy(hwaddr, g_netdevices->d_mac.ether, 6);
|
||||
#endif
|
||||
|
||||
/* Put ifindex and mac address into connection */
|
||||
|
||||
conn->ifindex = ifindex;
|
||||
memcpy(conn->lmac, hwaddr, 6);
|
||||
|
||||
/* Mark the socket bound */
|
||||
|
||||
psock->s_flags |= _SF_BOUND;
|
||||
return OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -EBADF;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pkt_listen
|
||||
*
|
||||
* Description:
|
||||
* To accept connections, a socket is first created with psock_socket(), a
|
||||
* willingness to accept incoming connections and a queue limit for
|
||||
* incoming connections are specified with psock_listen(), and then the
|
||||
* connections are accepted with psock_accept(). For the case of raw
|
||||
* packet sockets, psock_listen() calls this function. The psock_listen()
|
||||
* call applies only to sockets of type SOCK_STREAM or SOCK_SEQPACKET.
|
||||
*
|
||||
* Parameters:
|
||||
* psock Reference to an internal, boound socket structure.
|
||||
* backlog The maximum length the queue of pending connections may grow.
|
||||
* If a connection request arrives with the queue full, the client
|
||||
* may receive an error with an indication of ECONNREFUSED or,
|
||||
* if the underlying protocol supports retransmission, the request
|
||||
* may be ignored so that retries succeed.
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, zero is returned. On error, a negated errno value is
|
||||
* returned. See list() for the set of appropriate error values.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int pkt_listen(FAR struct socket *psock, int backlog)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pkt_send
|
||||
*
|
||||
* Description:
|
||||
* Socket send() method for the raw packet socket.
|
||||
*
|
||||
* Parameters:
|
||||
* psock An instance of the internal socket structure.
|
||||
* buf Data to send
|
||||
* len Length of data to send
|
||||
* flags Send flags
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, returns the number of characters sent. On error, a negated
|
||||
* errno value is returned (see send() for the list of appropriate error
|
||||
* values.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static ssize_t pkt_send(FAR struct socket *psock, FAR const void *buf,
|
||||
size_t len, int flags)
|
||||
{
|
||||
ssize_t ret;
|
||||
|
||||
/* Only SOCK_RAW is supported */
|
||||
|
||||
if (psock->s_type == SOCK_RAW)
|
||||
{
|
||||
/* Raw packet send */
|
||||
|
||||
ret = psock_pkt_send(psock, buf, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* EDESTADDRREQ. Signifies that the socket is not connection-mode and no peer
|
||||
* address is set.
|
||||
*/
|
||||
|
||||
ret = -EDESTADDRREQ;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pkt_sendto
|
||||
*
|
||||
* Description:
|
||||
* Implements the sendto() operation for the case of the raw packet socket.
|
||||
*
|
||||
* Parameters:
|
||||
* psock A pointer to a NuttX-specific, internal socket structure
|
||||
* buf Data to send
|
||||
* len Length of data to send
|
||||
* flags Send flags
|
||||
* to Address of recipient
|
||||
* tolen The length of the address structure
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, returns the number of characters sent. On error, a negated
|
||||
* errno value is returned (see send_to() for the list of appropriate error
|
||||
* values.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static ssize_t pkt_sendto(FAR struct socket *psock, FAR const void *buf,
|
||||
size_t len, int flags, FAR const struct sockaddr *to,
|
||||
socklen_t tolen)
|
||||
{
|
||||
nerr("ERROR: sendto() not supported for raw packet sockets\n");
|
||||
return -EAFNOSUPPORT;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pkt_close
|
||||
*
|
||||
* Description:
|
||||
* Performs the close operation on a raw packet socket instance
|
||||
*
|
||||
* Parameters:
|
||||
* psock Socket instance
|
||||
*
|
||||
* Returned Value:
|
||||
* 0 on success; a negated errno value is returned on any failure.
|
||||
*
|
||||
* Assumptions:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int pkt_close(FAR struct socket *psock)
|
||||
{
|
||||
/* Perform some pre-close operations for the raw packet address type */
|
||||
|
||||
switch (psock->s_type)
|
||||
{
|
||||
case SOCK_RAW:
|
||||
{
|
||||
FAR struct pkt_conn_s *conn = psock->s_conn;
|
||||
|
||||
/* Is this the last reference to the connection structure (there
|
||||
* could be more if the socket was dup'ed).
|
||||
*/
|
||||
|
||||
if (conn->crefs <= 1)
|
||||
{
|
||||
/* Yes... free the connection structure */
|
||||
|
||||
conn->crefs = 0; /* No more references on the connection */
|
||||
pkt_free(psock->s_conn); /* Free network resources */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No.. Just decrement the reference count */
|
||||
|
||||
conn->crefs--;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
default:
|
||||
return -EBADF;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name:
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* Returned Value:
|
||||
*
|
||||
* Assumptions:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#endif /* CONFIG_NET_PKT */
|
|
@ -1,7 +1,7 @@
|
|||
############################################################################
|
||||
# net/socket/Make.defs
|
||||
#
|
||||
# Copyright (C) 2014-2015 Gregory Nutt. All rights reserved.
|
||||
# Copyright (C) 2014-2015, 2017 Gregory Nutt. All rights reserved.
|
||||
# Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
|
@ -39,6 +39,16 @@ SOCK_CSRCS += bind.c connect.c getsockname.c recv.c recvfrom.c send.c
|
|||
SOCK_CSRCS += sendto.c socket.c net_sockets.c net_close.c net_dupsd.c
|
||||
SOCK_CSRCS += net_dupsd2.c net_clone.c net_poll.c net_vfcntl.c
|
||||
|
||||
# Socket address families
|
||||
|
||||
SOCK_CSRCS += net_sockif.c
|
||||
|
||||
ifeq ($(CONFIG_NET_IPv4),y)
|
||||
SOCK_CSRCS += inet_sockif.c inet_recvfrom.c inet_connect.c inet_close.c
|
||||
else ifeq ($(CONFIG_NET_IPv6),y)
|
||||
SOCK_CSRCS += inet_sockif.c inet_recvfrom.c inet_connect.c inet_close.c
|
||||
endif
|
||||
|
||||
# TCP/IP support
|
||||
|
||||
ifeq ($(CONFIG_NET_TCP),y)
|
||||
|
|
|
@ -38,8 +38,6 @@
|
|||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#if defined(CONFIG_NET) && CONFIG_NSOCKET_DESCRIPTORS > 0 && \
|
||||
(defined(CONFIG_NET_TCP) || defined(CONFIG_NET_LOCAL_STREAM))
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
@ -56,6 +54,8 @@
|
|||
#include "socket/socket.h"
|
||||
#include "usrsock/usrsock.h"
|
||||
|
||||
#if defined(CONFIG_NET) && CONFIG_NSOCKET_DESCRIPTORS > 0
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
@ -115,8 +115,7 @@
|
|||
* 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.
|
||||
* The addr parameter is not in a writable part of the user address space.
|
||||
* ENOBUFS or ENOMEM
|
||||
* Not enough free memory.
|
||||
* EPROTO
|
||||
|
@ -130,29 +129,20 @@ int psock_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
|
|||
FAR socklen_t *addrlen, FAR struct socket *newsock)
|
||||
{
|
||||
int errcode;
|
||||
#if defined(NET_TCP_HAVE_STACK) || defined(CONFIG_NET_LOCAL_STREAM)
|
||||
int ret;
|
||||
#endif
|
||||
|
||||
DEBUGASSERT(psock != NULL);
|
||||
DEBUGASSERT(psock != NULL && psock->s_conn != NULL && newsock != NULL);
|
||||
|
||||
/* Treat as a cancellation point */
|
||||
|
||||
(void)enter_cancellation_point();
|
||||
|
||||
/* Is the socket a stream? */
|
||||
/* May sure that the socket has been opened with socket() */
|
||||
|
||||
if (psock->s_type != SOCK_STREAM)
|
||||
if (psock == NULL || psock->s_conn == NULL)
|
||||
{
|
||||
#ifdef CONFIG_NET_USRSOCK
|
||||
if (psock->s_type == SOCK_USRSOCK_TYPE)
|
||||
{
|
||||
#warning "Missing logic"
|
||||
}
|
||||
#endif
|
||||
|
||||
errcode = EOPNOTSUPP;
|
||||
goto errout;
|
||||
nerr("ERROR: Socket invalid or not opened\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Is the socket listening for a connection? */
|
||||
|
@ -163,127 +153,16 @@ int psock_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
|
|||
goto errout;
|
||||
}
|
||||
|
||||
/* Verify that a valid memory block has been provided to receive the
|
||||
* address
|
||||
*/
|
||||
/* Let the address family's accept() method handle the operation */
|
||||
|
||||
if (addr)
|
||||
DEBUGASSERT(psock->s_sockif != NULL && psock->s_sockif->si_accept != NULL);
|
||||
ret = psock->s_sockif->si_accept(psock, addr, addrlen, newsock);
|
||||
if (ret < 0)
|
||||
{
|
||||
/* If an address is provided, then the length must also be provided. */
|
||||
|
||||
DEBUGASSERT(addrlen);
|
||||
|
||||
/* A valid length depends on the address domain */
|
||||
|
||||
switch (psock->s_domain)
|
||||
{
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
case PF_INET:
|
||||
{
|
||||
if (*addrlen < sizeof(struct sockaddr_in))
|
||||
{
|
||||
errcode = EBADF;
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_NET_IPv4 */
|
||||
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
case PF_INET6:
|
||||
{
|
||||
if (*addrlen < sizeof(struct sockaddr_in6))
|
||||
{
|
||||
errcode = EBADF;
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_NET_IPv6 */
|
||||
|
||||
#ifdef CONFIG_NET_LOCAL_STREAM
|
||||
case PF_LOCAL:
|
||||
{
|
||||
if (*addrlen < sizeof(sa_family_t))
|
||||
{
|
||||
errcode = EBADF;
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_NET_IPv6 */
|
||||
|
||||
default:
|
||||
DEBUGPANIC();
|
||||
errcode = EINVAL;
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize the socket structure. */
|
||||
|
||||
newsock->s_domain = psock->s_domain;
|
||||
newsock->s_type = SOCK_STREAM;
|
||||
|
||||
/* Perform the correct accept operation for this address domain */
|
||||
|
||||
#ifdef CONFIG_NET_LOCAL_STREAM
|
||||
#ifdef CONFIG_NET_TCP
|
||||
if (psock->s_domain == PF_LOCAL)
|
||||
#endif
|
||||
{
|
||||
/* Perform the local accept operation (with the network unlocked) */
|
||||
|
||||
ret = psock_local_accept(psock, addr, addrlen, &newsock->s_conn);
|
||||
if (ret < 0)
|
||||
{
|
||||
errcode = -ret;
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_NET_LOCAL_STREAM */
|
||||
|
||||
#ifdef CONFIG_NET_TCP
|
||||
#ifdef CONFIG_NET_LOCAL_STREAM
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#ifdef NET_TCP_HAVE_STACK
|
||||
/* Perform the local accept operation (with the network locked) */
|
||||
|
||||
net_lock();
|
||||
ret = psock_tcp_accept(psock, addr, addrlen, &newsock->s_conn);
|
||||
if (ret < 0)
|
||||
{
|
||||
net_unlock();
|
||||
errcode = -ret;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* Begin monitoring for TCP connection events on the newly connected
|
||||
* socket
|
||||
*/
|
||||
|
||||
ret = net_startmonitor(newsock);
|
||||
if (ret < 0)
|
||||
{
|
||||
/* net_startmonitor() can only fail on certain race conditions
|
||||
* where the connection was lost just before this function was
|
||||
* called. Undo everything we have done and return a failure.
|
||||
*/
|
||||
|
||||
net_unlock();
|
||||
errcode = -ret;
|
||||
goto errout_after_accept;
|
||||
}
|
||||
|
||||
net_unlock();
|
||||
#else
|
||||
errcode = EOPNOTSUPP;
|
||||
nerr("ERROR: si_accept failed: %d\n", ret);
|
||||
errcode = -ret;
|
||||
goto errout;
|
||||
#endif /* NET_TCP_HAVE_STACK */
|
||||
}
|
||||
#endif /* CONFIG_NET_TCP */
|
||||
|
||||
/* Mark the new socket as connected. */
|
||||
|
||||
|
@ -293,11 +172,6 @@ int psock_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
|
|||
leave_cancellation_point();
|
||||
return OK;
|
||||
|
||||
#ifdef NET_TCP_HAVE_STACK
|
||||
errout_after_accept:
|
||||
psock_close(newsock);
|
||||
#endif
|
||||
|
||||
errout:
|
||||
set_errno(errcode);
|
||||
leave_cancellation_point();
|
||||
|
@ -447,4 +321,4 @@ errout:
|
|||
return ERROR;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NET && CONFIG_NSOCKET_DESCRIPTORS && (CONFIG_NET_TCP || CONFIG_NET_LOCAL_STREAM) */
|
||||
#endif /* CONFIG_NET && CONFIG_NSOCKET_DESCRIPTORS */
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/****************************************************************************
|
||||
* net/socket/bind.c
|
||||
*
|
||||
* Copyright (C) 2007-2009, 2012, 2014-2016 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 2007-2009, 2012, 2014-2017 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -38,85 +38,23 @@
|
|||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#ifdef CONFIG_NET
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <debug.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef CONFIG_NET_PKT
|
||||
# include <netpacket/packet.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/net/net.h>
|
||||
#include <nuttx/net/udp.h>
|
||||
|
||||
#include "socket/socket.h"
|
||||
#include "netdev/netdev.h"
|
||||
#include "tcp/tcp.h"
|
||||
#include "udp/udp.h"
|
||||
#include "pkt/pkt.h"
|
||||
#include "local/local.h"
|
||||
#include "usrsock/usrsock.h"
|
||||
|
||||
#ifdef CONFIG_NET
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pkt_bind
|
||||
*
|
||||
* Description:
|
||||
* Bind a raw socket to an network device.
|
||||
*
|
||||
* Parameters:
|
||||
* conn AF_PACKET connection structure
|
||||
* addr Peer address information
|
||||
*
|
||||
* Returned Value:
|
||||
* 0 on success; -1 on error with errno set appropriately
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET_PKT
|
||||
static int pkt_bind(FAR struct pkt_conn_s *conn,
|
||||
FAR const struct sockaddr_ll *addr)
|
||||
{
|
||||
int ifindex;
|
||||
#if 0
|
||||
char hwaddr[6] = /* our MAC for debugging */
|
||||
{
|
||||
0x00, 0xa1, 0xb1, 0xc1, 0xd1, 0xe1
|
||||
};
|
||||
#endif
|
||||
char hwaddr[6] = /* MAC from ifconfig */
|
||||
{
|
||||
0x00, 0xe0, 0xde, 0xad, 0xbe, 0xef
|
||||
};
|
||||
|
||||
/* Look at the addr and identify network interface */
|
||||
|
||||
ifindex = addr->sll_ifindex;
|
||||
|
||||
#if 0
|
||||
/* Get the MAC address of that interface */
|
||||
|
||||
memcpy(hwaddr, g_netdevices->d_mac.ether, 6);
|
||||
#endif
|
||||
|
||||
/* Put ifindex and mac address into connection */
|
||||
|
||||
conn->ifindex = ifindex;
|
||||
memcpy(conn->lmac, hwaddr, 6);
|
||||
|
||||
return OK;
|
||||
}
|
||||
#endif /* CONFIG_NET_PKT */
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
@ -157,7 +95,6 @@ int psock_bind(FAR struct socket *psock, const struct sockaddr *addr,
|
|||
#ifdef CONFIG_NET_PKT
|
||||
FAR const struct sockaddr_ll *lladdr = (const struct sockaddr_ll *)addr;
|
||||
#endif
|
||||
socklen_t minlen;
|
||||
int errcode;
|
||||
int ret = OK;
|
||||
|
||||
|
@ -169,165 +106,10 @@ int psock_bind(FAR struct socket *psock, const struct sockaddr *addr,
|
|||
goto errout;
|
||||
}
|
||||
|
||||
/* Verify that a valid address has been provided */
|
||||
/* Let the address family's connect() method handle the operation */
|
||||
|
||||
switch (addr->sa_family)
|
||||
{
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
case AF_INET:
|
||||
minlen = sizeof(struct sockaddr_in);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
case AF_INET6:
|
||||
minlen = sizeof(struct sockaddr_in6);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_LOCAL
|
||||
case AF_LOCAL:
|
||||
minlen = sizeof(sa_family_t);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_PKT
|
||||
case AF_PACKET:
|
||||
minlen = sizeof(struct sockaddr_ll);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
nerr("ERROR: Unrecognized address family: %d\n", addr->sa_family);
|
||||
errcode = EAFNOSUPPORT;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (addrlen < minlen)
|
||||
{
|
||||
nerr("ERROR: Invalid address length: %d < %d\n", addrlen, minlen);
|
||||
errcode = EBADF;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* Perform the binding depending on the protocol type */
|
||||
|
||||
switch (psock->s_type)
|
||||
{
|
||||
#ifdef CONFIG_NET_USRSOCK
|
||||
case SOCK_USRSOCK_TYPE:
|
||||
{
|
||||
FAR struct usrsock_conn_s *conn = psock->s_conn;
|
||||
|
||||
DEBUGASSERT(conn);
|
||||
|
||||
/* Perform the usrsock bind operation */
|
||||
|
||||
ret = usrsock_bind(conn, addr, addrlen);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_PKT
|
||||
case SOCK_RAW:
|
||||
ret = pkt_bind(psock->s_conn, lladdr);
|
||||
break;
|
||||
#endif
|
||||
|
||||
/* Bind a stream socket which may either be TCP/IP or a local, Unix
|
||||
* domain socket.
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_LOCAL_STREAM)
|
||||
case SOCK_STREAM:
|
||||
{
|
||||
#ifdef CONFIG_NET_LOCAL_STREAM
|
||||
#ifdef CONFIG_NET_TCP
|
||||
/* Is this a Unix domain socket? */
|
||||
|
||||
if (psock->s_domain == PF_LOCAL)
|
||||
#endif
|
||||
{
|
||||
/* Bind the Unix domain connection structure */
|
||||
|
||||
ret = psock_local_bind(psock, addr, addrlen);
|
||||
}
|
||||
#endif /* CONFIG_NET_LOCAL_STREAM */
|
||||
|
||||
#ifdef CONFIG_NET_TCP
|
||||
#ifdef CONFIG_NET_LOCAL_STREAM
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#ifdef NET_TCP_HAVE_STACK
|
||||
/* Bind the TCP/IP connection structure */
|
||||
|
||||
ret = tcp_bind(psock->s_conn, addr);
|
||||
#else
|
||||
ret = -ENOSYS;
|
||||
#endif
|
||||
}
|
||||
#endif /* CONFIG_NET_TCP */
|
||||
|
||||
/* Mark the socket bound */
|
||||
|
||||
if (ret >= 0)
|
||||
{
|
||||
psock->s_flags |= _SF_BOUND;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_NET_TCP || CONFIG_NET_LOCAL_STREAM */
|
||||
|
||||
/* Bind a datagram socket which may either be TCP/IP or a local, Unix
|
||||
* domain socket.
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_LOCAL_DGRAM)
|
||||
case SOCK_DGRAM:
|
||||
{
|
||||
#ifdef CONFIG_NET_LOCAL_DGRAM
|
||||
#ifdef CONFIG_NET_UDP
|
||||
/* Is this a Unix domain socket? */
|
||||
|
||||
if (psock->s_domain == PF_LOCAL)
|
||||
#endif
|
||||
{
|
||||
/* Bind the Unix domain connection structure */
|
||||
|
||||
ret = psock_local_bind(psock, addr, addrlen);
|
||||
}
|
||||
#endif /* CONFIG_NET_LOCAL_DGRAM */
|
||||
|
||||
#ifdef CONFIG_NET_UDP
|
||||
#ifdef CONFIG_NET_LOCAL_DGRAM
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#ifdef NET_UDP_HAVE_STACK
|
||||
/* Bind the UDPP/IP connection structure */
|
||||
|
||||
ret = udp_bind(psock->s_conn, addr);
|
||||
#else
|
||||
ret = -ENOSYS;
|
||||
#endif
|
||||
}
|
||||
#endif /* CONFIG_NET_UDP */
|
||||
|
||||
/* Mark the socket bound */
|
||||
|
||||
if (ret >= 0)
|
||||
{
|
||||
psock->s_flags |= _SF_BOUND;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_NET_UDP || CONFIG_NET_LOCAL_DGRAM */
|
||||
|
||||
default:
|
||||
errcode = EBADF;
|
||||
goto errout;
|
||||
}
|
||||
DEBUGASSERT(psock->s_sockif != NULL && psock->s_sockif->si_bind != NULL);
|
||||
ret = psock->s_sockif->si_bind(psock, addr, addrlen);
|
||||
|
||||
/* Was the bind successful */
|
||||
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#ifdef CONFIG_NET
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
@ -48,398 +47,17 @@
|
|||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <arch/irq.h>
|
||||
|
||||
#include <nuttx/semaphore.h>
|
||||
#include <nuttx/cancelpt.h>
|
||||
#include <nuttx/net/net.h>
|
||||
#include <nuttx/net/netdev.h>
|
||||
#include <nuttx/net/udp.h>
|
||||
#include <nuttx/net/tcp.h>
|
||||
|
||||
#include "devif/devif.h"
|
||||
#include "tcp/tcp.h"
|
||||
#include "udp/udp.h"
|
||||
#include "local/local.h"
|
||||
#include "socket/socket.h"
|
||||
#include "usrsock/usrsock.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef NET_TCP_HAVE_STACK
|
||||
struct tcp_connect_s
|
||||
{
|
||||
FAR struct tcp_conn_s *tc_conn; /* Reference to TCP connection structure */
|
||||
FAR struct devif_callback_s *tc_cb; /* Reference to callback instance */
|
||||
FAR struct socket *tc_psock; /* The socket being connected */
|
||||
sem_t tc_sem; /* Semaphore signals recv completion */
|
||||
int tc_result; /* OK on success, otherwise a negated errno. */
|
||||
};
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef NET_TCP_HAVE_STACK
|
||||
static inline int psock_setup_callbacks(FAR struct socket *psock,
|
||||
FAR struct tcp_connect_s *pstate);
|
||||
static void psock_teardown_callbacks(FAR struct tcp_connect_s *pstate,
|
||||
int status);
|
||||
static uint16_t psock_connect_interrupt(FAR struct net_driver_s *dev,
|
||||
FAR void *pvconn, FAR void *pvpriv,
|
||||
uint16_t flags);
|
||||
static inline int psock_tcp_connect(FAR struct socket *psock,
|
||||
FAR const struct sockaddr *addr);
|
||||
#endif /* NET_TCP_HAVE_STACK */
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
/****************************************************************************
|
||||
* Name: psock_setup_callbacks
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef NET_TCP_HAVE_STACK
|
||||
static inline int psock_setup_callbacks(FAR struct socket *psock,
|
||||
FAR struct tcp_connect_s *pstate)
|
||||
{
|
||||
FAR struct tcp_conn_s *conn = psock->s_conn;
|
||||
int ret = -EBUSY;
|
||||
|
||||
/* Initialize the TCP state structure */
|
||||
|
||||
/* This semaphore is used for signaling and, hence, should not have
|
||||
* priority inheritance enabled.
|
||||
*/
|
||||
|
||||
(void)sem_init(&pstate->tc_sem, 0, 0); /* Doesn't really fail */
|
||||
(void)sem_setprotocol(&pstate->tc_sem, SEM_PRIO_NONE);
|
||||
|
||||
pstate->tc_conn = conn;
|
||||
pstate->tc_psock = psock;
|
||||
pstate->tc_result = -EAGAIN;
|
||||
|
||||
/* Set up the callbacks in the connection */
|
||||
|
||||
pstate->tc_cb = tcp_callback_alloc(conn);
|
||||
if (pstate->tc_cb)
|
||||
{
|
||||
/* Set up the connection "interrupt" handler */
|
||||
|
||||
pstate->tc_cb->flags = (TCP_NEWDATA | TCP_CLOSE | TCP_ABORT |
|
||||
TCP_TIMEDOUT | TCP_CONNECTED | NETDEV_DOWN);
|
||||
pstate->tc_cb->priv = (FAR void *)pstate;
|
||||
pstate->tc_cb->event = psock_connect_interrupt;
|
||||
ret = OK;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* NET_TCP_HAVE_STACK */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: psock_teardown_callbacks
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef NET_TCP_HAVE_STACK
|
||||
static void psock_teardown_callbacks(FAR struct tcp_connect_s *pstate,
|
||||
int status)
|
||||
{
|
||||
FAR struct tcp_conn_s *conn = pstate->tc_conn;
|
||||
|
||||
/* Make sure that no further interrupts are processed */
|
||||
|
||||
tcp_callback_free(conn, pstate->tc_cb);
|
||||
pstate->tc_cb = NULL;
|
||||
|
||||
/* If we successfully connected, we will continue to monitor the connection
|
||||
* state via callbacks.
|
||||
*/
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
/* Failed to connect. Stop the connection event monitor */
|
||||
|
||||
net_stopmonitor(conn);
|
||||
}
|
||||
}
|
||||
#endif /* NET_TCP_HAVE_STACK */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: psock_connect_interrupt
|
||||
*
|
||||
* Description:
|
||||
* This function is called from the interrupt level to perform the actual
|
||||
* connection operation via by the lower, device interfacing layer.
|
||||
*
|
||||
* Parameters:
|
||||
* dev The structure of the network driver that caused the interrupt
|
||||
* pvconn The connection structure associated with the socket
|
||||
* flags Set of events describing why the callback was invoked
|
||||
*
|
||||
* Returned Value:
|
||||
* The new flags setting
|
||||
*
|
||||
* Assumptions:
|
||||
* Running at the interrupt level
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef NET_TCP_HAVE_STACK
|
||||
static uint16_t psock_connect_interrupt(FAR struct net_driver_s *dev,
|
||||
FAR void *pvconn, FAR void *pvpriv,
|
||||
uint16_t flags)
|
||||
{
|
||||
struct tcp_connect_s *pstate = (struct tcp_connect_s *)pvpriv;
|
||||
|
||||
ninfo("flags: %04x\n", flags);
|
||||
|
||||
/* 'priv' might be null in some race conditions (?) */
|
||||
|
||||
if (pstate)
|
||||
{
|
||||
/* The following errors should be detected here (someday)
|
||||
*
|
||||
* ECONNREFUSED
|
||||
* No one listening on the remote address.
|
||||
* ENETUNREACH
|
||||
* Network is unreachable.
|
||||
* ETIMEDOUT
|
||||
* Timeout while attempting connection. The server may be too busy
|
||||
* to accept new connections.
|
||||
*/
|
||||
|
||||
/* TCP_CLOSE: The remote host has closed the connection
|
||||
* TCP_ABORT: The remote host has aborted the connection
|
||||
*/
|
||||
|
||||
if ((flags & (TCP_CLOSE | TCP_ABORT)) != 0)
|
||||
{
|
||||
/* Indicate that remote host refused the connection */
|
||||
|
||||
pstate->tc_result = -ECONNREFUSED;
|
||||
}
|
||||
|
||||
/* TCP_TIMEDOUT: Connection aborted due to too many retransmissions. */
|
||||
|
||||
else if ((flags & TCP_TIMEDOUT) != 0)
|
||||
{
|
||||
/* Indicate that the connection timedout?) */
|
||||
|
||||
pstate->tc_result = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
else if ((flags & NETDEV_DOWN) != 0)
|
||||
{
|
||||
/* The network device went down. Indicate that the remote host
|
||||
* is unreachable.
|
||||
*/
|
||||
|
||||
pstate->tc_result = -ENETUNREACH;
|
||||
}
|
||||
|
||||
/* TCP_CONNECTED: The socket is successfully connected */
|
||||
|
||||
else if ((flags & TCP_CONNECTED) != 0)
|
||||
{
|
||||
FAR struct socket *psock = pstate->tc_psock;
|
||||
DEBUGASSERT(psock);
|
||||
|
||||
/* Mark the connection bound and connected. NOTE this is
|
||||
* is done here (vs. later) in order to avoid any race condition
|
||||
* in the socket state. It is known to connected here and now,
|
||||
* but not necessarily at any time later.
|
||||
*/
|
||||
|
||||
psock->s_flags |= (_SF_BOUND | _SF_CONNECTED);
|
||||
|
||||
/* Indicate that the socket is no longer connected */
|
||||
|
||||
pstate->tc_result = OK;
|
||||
}
|
||||
|
||||
/* Otherwise, it is not an event of importance to us at the moment */
|
||||
|
||||
else
|
||||
{
|
||||
/* Drop data received in this state */
|
||||
|
||||
dev->d_len = 0;
|
||||
return flags & ~TCP_NEWDATA;
|
||||
}
|
||||
|
||||
ninfo("Resuming: %d\n", pstate->tc_result);
|
||||
|
||||
/* Stop further callbacks */
|
||||
|
||||
psock_teardown_callbacks(pstate, pstate->tc_result);
|
||||
|
||||
#ifdef CONFIG_NET_MULTILINK
|
||||
/* When we set up the connection structure, we did not know the size
|
||||
* of the initial MSS. Now that the connection is associated with a
|
||||
* network device, we now know the size of link layer header and can
|
||||
* determine the correct initial MSS.
|
||||
*/
|
||||
|
||||
DEBUGASSERT(pstate->tc_conn);
|
||||
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
if (pstate->tc_conn->domain == PF_INET)
|
||||
#endif
|
||||
{
|
||||
pstate->tc_conn->mss = TCP_IPv4_INITIAL_MSS(dev);
|
||||
}
|
||||
#endif /* CONFIG_NET_IPv4 */
|
||||
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
else
|
||||
#endif
|
||||
{
|
||||
pstate->tc_conn->mss = TCP_IPv6_INITIAL_MSS(dev);
|
||||
}
|
||||
#endif /* CONFIG_NET_IPv6 */
|
||||
|
||||
#ifdef CONFIG_NETDEV_MULTINIC
|
||||
/* We now have to filter all outgoing transfers so that they use only
|
||||
* the MSS of this device.
|
||||
*/
|
||||
|
||||
DEBUGASSERT(pstate->tc_conn->dev == NULL ||
|
||||
pstate->tc_conn->dev == dev);
|
||||
pstate->tc_conn->dev = dev;
|
||||
|
||||
#endif /* CONFIG_NETDEV_MULTINIC */
|
||||
#endif /* CONFIG_NET_MULTILINK */
|
||||
|
||||
/* Wake up the waiting thread */
|
||||
|
||||
sem_post(&pstate->tc_sem);
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
#endif /* NET_TCP_HAVE_STACK */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: psock_tcp_connect
|
||||
*
|
||||
* Description:
|
||||
* Perform a TCP connection
|
||||
*
|
||||
* Parameters:
|
||||
* psock - A reference to the socket structure of the socket to be connected
|
||||
* addr - The address of the remote server to connect to
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
* Assumptions:
|
||||
* Running at the interrupt level
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef NET_TCP_HAVE_STACK
|
||||
static inline int psock_tcp_connect(FAR struct socket *psock,
|
||||
FAR const struct sockaddr *addr)
|
||||
{
|
||||
struct tcp_connect_s state;
|
||||
int ret = OK;
|
||||
|
||||
/* Interrupts must be disabled through all of the following because
|
||||
* we cannot allow the network callback to occur until we are completely
|
||||
* setup.
|
||||
*/
|
||||
|
||||
net_lock();
|
||||
|
||||
/* Get the connection reference from the socket */
|
||||
|
||||
if (!psock->s_conn) /* Should always be non-NULL */
|
||||
{
|
||||
ret = -EINVAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Perform the TCP connection operation */
|
||||
|
||||
ret = tcp_connect(psock->s_conn, addr);
|
||||
}
|
||||
|
||||
if (ret >= 0)
|
||||
{
|
||||
/* Set up the callbacks in the connection */
|
||||
|
||||
ret = psock_setup_callbacks(psock, &state);
|
||||
if (ret >= 0)
|
||||
{
|
||||
/* Wait for either the connect to complete or for an error/timeout
|
||||
* 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-disabled
|
||||
* when the task restarts.
|
||||
*/
|
||||
|
||||
ret = net_lockedwait(&state.tc_sem);
|
||||
|
||||
/* Uninitialize the state structure */
|
||||
|
||||
(void)sem_destroy(&state.tc_sem);
|
||||
|
||||
/* If net_lockedwait failed, recover the negated error (probably -EINTR) */
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
ret = -get_errno();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If the wait succeeded, then get the new error value from
|
||||
* the state structure
|
||||
*/
|
||||
|
||||
ret = state.tc_result;
|
||||
}
|
||||
|
||||
/* Make sure that no further interrupts are processed */
|
||||
|
||||
psock_teardown_callbacks(&state, ret);
|
||||
}
|
||||
|
||||
/* Check if the socket was successfully connected. */
|
||||
|
||||
if (ret >= 0)
|
||||
{
|
||||
/* Yes... Now that we are connected, we need to set up to monitor
|
||||
* the state of the connection up the connection event monitor.
|
||||
*/
|
||||
|
||||
ret = net_startmonitor(psock);
|
||||
if (ret < 0)
|
||||
{
|
||||
/* net_startmonitor() can only fail on certain race
|
||||
* conditions where the connection was lost just before
|
||||
* this function was called. That is not expected to
|
||||
* happen in this context, but just in case...
|
||||
*/
|
||||
|
||||
net_lostconnection(psock, TCP_ABORT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
net_unlock();
|
||||
return ret;
|
||||
}
|
||||
#endif /* NET_TCP_HAVE_STACK */
|
||||
#ifdef CONFIG_NET
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: psock_connect
|
||||
*
|
||||
|
@ -512,12 +130,8 @@ static inline int psock_tcp_connect(FAR struct socket *psock,
|
|||
int psock_connect(FAR struct socket *psock, FAR const struct sockaddr *addr,
|
||||
socklen_t addrlen)
|
||||
{
|
||||
FAR const struct sockaddr_in *inaddr = (FAR const struct sockaddr_in *)addr;
|
||||
#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_UDP) || \
|
||||
defined(CONFIG_NET_LOCAL) || defined(CONFIG_NET_USRSOCK)
|
||||
int ret;
|
||||
#endif
|
||||
int errcode;
|
||||
int ret;
|
||||
|
||||
/* Treat as a cancellation point */
|
||||
|
||||
|
@ -525,179 +139,22 @@ int psock_connect(FAR struct socket *psock, FAR const struct sockaddr *addr,
|
|||
|
||||
/* Verify that the psock corresponds to valid, allocated socket */
|
||||
|
||||
if (!psock || psock->s_crefs <= 0)
|
||||
if (psock == NULL || psock->s_crefs <= 0)
|
||||
{
|
||||
errcode = EBADF;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* Verify that a valid address has been provided */
|
||||
/* Let the address family's connect() method handle the operation */
|
||||
|
||||
switch (inaddr->sin_family)
|
||||
DEBUGASSERT(psock->s_sockif != NULL && psock->s_sockif->si_connect != NULL);
|
||||
ret = psock->s_sockif->si_connect(psock, addr, addrlen);
|
||||
if (ret < 0)
|
||||
{
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
case AF_INET:
|
||||
{
|
||||
if (addrlen < sizeof(struct sockaddr_in))
|
||||
{
|
||||
errcode = EBADF;
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
case AF_INET6:
|
||||
{
|
||||
if (addrlen < sizeof(struct sockaddr_in6))
|
||||
{
|
||||
errcode = EBADF;
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_LOCAL
|
||||
case AF_LOCAL:
|
||||
{
|
||||
if (addrlen < sizeof(sa_family_t))
|
||||
{
|
||||
errcode = EBADF;
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
#ifdef CONFIG_NET_USRSOCK
|
||||
if (psock->s_type == SOCK_USRSOCK_TYPE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
DEBUGPANIC();
|
||||
errcode = EAFNOSUPPORT;
|
||||
errcode = -ret;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* Perform the connection depending on the protocol type */
|
||||
|
||||
switch (psock->s_type)
|
||||
{
|
||||
#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_LOCAL_STREAM)
|
||||
case SOCK_STREAM:
|
||||
{
|
||||
/* Verify that the socket is not already connected */
|
||||
|
||||
if (_SS_ISCONNECTED(psock->s_flags))
|
||||
{
|
||||
errcode = EISCONN;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* It's not ... connect it */
|
||||
|
||||
#ifdef CONFIG_NET_LOCAL_STREAM
|
||||
#ifdef CONFIG_NET_TCP
|
||||
if (psock->s_domain == PF_LOCAL)
|
||||
#endif
|
||||
{
|
||||
/* Connect to the local Unix domain server */
|
||||
|
||||
ret = psock_local_connect(psock, addr);
|
||||
}
|
||||
#endif /* CONFIG_NET_LOCAL_STREAM */
|
||||
|
||||
#ifdef CONFIG_NET_TCP
|
||||
#ifdef CONFIG_NET_LOCAL_STREAM
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#ifdef NET_TCP_HAVE_STACK
|
||||
/* Connect the TCP/IP socket */
|
||||
|
||||
ret = psock_tcp_connect(psock, addr);
|
||||
#else
|
||||
ret = -ENOSYS;
|
||||
#endif
|
||||
}
|
||||
#endif /* CONFIG_NET_TCP */
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
errcode = -ret;
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_NET_TCP || CONFIG_NET_LOCAL_STREAM */
|
||||
|
||||
#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_LOCAL_DGRAM)
|
||||
case SOCK_DGRAM:
|
||||
{
|
||||
#ifdef CONFIG_NET_LOCAL_DGRAM
|
||||
#ifdef CONFIG_NET_UDP
|
||||
if (psock->s_domain == PF_LOCAL)
|
||||
#endif
|
||||
{
|
||||
/* Perform the datagram connection logic */
|
||||
|
||||
ret = psock_local_connect(psock, addr);
|
||||
}
|
||||
#endif /* CONFIG_NET_LOCAL_DGRAM */
|
||||
|
||||
#ifdef CONFIG_NET_UDP
|
||||
#ifdef CONFIG_NET_LOCAL_DGRAM
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#ifdef NET_UDP_HAVE_STACK
|
||||
ret = udp_connect(psock->s_conn, addr);
|
||||
if (ret < 0 || addr == NULL)
|
||||
{
|
||||
psock->s_flags &= ~_SF_CONNECTED;
|
||||
}
|
||||
else
|
||||
{
|
||||
psock->s_flags |= _SF_CONNECTED;
|
||||
}
|
||||
#else
|
||||
ret = -ENOSYS;
|
||||
#endif
|
||||
}
|
||||
#endif /* CONFIG_NET_UDP */
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
errcode = -ret;
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_NET_UDP || CONFIG_NET_LOCAL_DGRAM */
|
||||
|
||||
#ifdef CONFIG_NET_USRSOCK
|
||||
case SOCK_USRSOCK_TYPE:
|
||||
{
|
||||
ret = usrsock_connect(psock, addr, addrlen);
|
||||
if (ret < 0)
|
||||
{
|
||||
errcode = -ret;
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_NET_USRSOCK */
|
||||
|
||||
default:
|
||||
errcode = EBADF;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
leave_cancellation_point();
|
||||
return OK;
|
||||
|
||||
|
|
610
net/socket/inet_close.c
Normal file
610
net/socket/inet_close.c
Normal file
|
@ -0,0 +1,610 @@
|
|||
/****************************************************************************
|
||||
* net/socket/inet_close.c
|
||||
*
|
||||
* Copyright (C) 2007-2017 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#ifdef CONFIG_NET
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <arch/irq.h>
|
||||
|
||||
#include <nuttx/semaphore.h>
|
||||
#include <nuttx/net/net.h>
|
||||
#include <nuttx/net/netdev.h>
|
||||
#include <nuttx/net/tcp.h>
|
||||
#include <nuttx/net/udp.h>
|
||||
|
||||
#ifdef CONFIG_NET_SOLINGER
|
||||
# include <nuttx/clock.h>
|
||||
#endif
|
||||
|
||||
#include "netdev/netdev.h"
|
||||
#include "devif/devif.h"
|
||||
#include "tcp/tcp.h"
|
||||
#include "udp/udp.h"
|
||||
#include "pkt/pkt.h"
|
||||
#include "local/local.h"
|
||||
#include "socket/socket.h"
|
||||
#include "usrsock/usrsock.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef NET_TCP_HAVE_STACK
|
||||
struct tcp_close_s
|
||||
{
|
||||
FAR struct devif_callback_s *cl_cb; /* Reference to TCP callback instance */
|
||||
#ifdef CONFIG_NET_SOLINGER
|
||||
FAR struct socket *cl_psock; /* Reference to the TCP socket */
|
||||
sem_t cl_sem; /* Signals disconnect completion */
|
||||
int cl_result; /* The result of the close */
|
||||
systime_t cl_start; /* Time close started (in ticks) */
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: tcp_close_timeout
|
||||
*
|
||||
* Description:
|
||||
* Check for a timeout on a lingering close.
|
||||
*
|
||||
* Parameters:
|
||||
* pstate - close state structure
|
||||
*
|
||||
* Returned Value:
|
||||
* TRUE:timeout FALSE:no timeout
|
||||
*
|
||||
* Assumptions:
|
||||
* Running at the interrupt level
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(NET_TCP_HAVE_STACK) && defined(CONFIG_NET_SOLINGER)
|
||||
static inline int tcp_close_timeout(FAR struct tcp_close_s *pstate)
|
||||
{
|
||||
FAR struct socket *psock = 0;
|
||||
|
||||
/* Make sure that we are performing a lingering close */
|
||||
|
||||
if (pstate != NULL)
|
||||
{
|
||||
/* Yes Check for a timeout configured via setsockopts(SO_LINGER).
|
||||
* If none... we well let the send wait forever.
|
||||
*/
|
||||
|
||||
psock = pstate->cl_psock;
|
||||
if (psock && psock->s_linger != 0)
|
||||
{
|
||||
/* Check if the configured timeout has elapsed */
|
||||
|
||||
return net_timeo(pstate->cl_start, psock->s_linger);
|
||||
}
|
||||
}
|
||||
|
||||
/* No timeout */
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
#endif /* NET_TCP_HAVE_STACK && CONFIG_NET_SOLINGER */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: tcp_close_interrupt
|
||||
*
|
||||
* Description:
|
||||
* Handle network callback events.
|
||||
*
|
||||
* Parameters:
|
||||
* conn - TCP connection structure
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
* Assumptions:
|
||||
* Called from normal user-level logic
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef NET_TCP_HAVE_STACK
|
||||
static uint16_t tcp_close_interrupt(FAR struct net_driver_s *dev,
|
||||
FAR void *pvconn, FAR void *pvpriv,
|
||||
uint16_t flags)
|
||||
{
|
||||
#ifdef CONFIG_NET_SOLINGER
|
||||
FAR struct tcp_close_s *pstate = (FAR struct tcp_close_s *)pvpriv;
|
||||
#endif
|
||||
FAR struct tcp_conn_s *conn = (FAR struct tcp_conn_s *)pvconn;
|
||||
|
||||
DEBUGASSERT(conn != NULL);
|
||||
|
||||
ninfo("conn: %p flags: %04x\n", conn, flags);
|
||||
|
||||
/* TCP_DISCONN_EVENTS:
|
||||
* TCP_CLOSE: The remote host has closed the connection
|
||||
* TCP_ABORT: The remote host has aborted the connection
|
||||
* TCP_TIMEDOUT: The remote did not respond, the connection timed out
|
||||
* NETDEV_DOWN: The network device went down
|
||||
*/
|
||||
|
||||
if ((flags & TCP_DISCONN_EVENTS) != 0)
|
||||
{
|
||||
/* The disconnection is complete */
|
||||
|
||||
#ifdef CONFIG_NET_SOLINGER
|
||||
/* pstate non-NULL means that we are performing a LINGERing close. */
|
||||
|
||||
if (pstate != NULL)
|
||||
{
|
||||
/* Wake up the waiting thread with a successful result */
|
||||
|
||||
pstate->cl_result = OK;
|
||||
goto end_wait;
|
||||
}
|
||||
|
||||
/* Otherwise, nothing is waiting on the close event and we can perform
|
||||
* the completion actions here.
|
||||
*/
|
||||
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* Free connection resources */
|
||||
|
||||
tcp_free(conn);
|
||||
|
||||
/* Stop further callbacks */
|
||||
|
||||
flags = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET_SOLINGER
|
||||
/* Check for a timeout. */
|
||||
|
||||
else if (pstate && tcp_close_timeout(pstate))
|
||||
{
|
||||
/* Yes.. Wake up the waiting thread and report the timeout */
|
||||
|
||||
nerr("ERROR: CLOSE timeout\n");
|
||||
pstate->cl_result = -ETIMEDOUT;
|
||||
goto end_wait;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NET_SOLINGER */
|
||||
|
||||
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
|
||||
/* Check if all outstanding bytes have been ACKed */
|
||||
|
||||
else if (conn->unacked != 0 || !sq_empty(&conn->write_q))
|
||||
{
|
||||
/* No... we are still waiting for ACKs. Drop any received data, but
|
||||
* do not yet report TCP_CLOSE in the response.
|
||||
*/
|
||||
|
||||
dev->d_len = 0;
|
||||
flags = (flags & ~TCP_NEWDATA);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NET_TCP_WRITE_BUFFERS */
|
||||
|
||||
else
|
||||
{
|
||||
/* Drop data received in this state and make sure that TCP_CLOSE
|
||||
* is set in the response
|
||||
*/
|
||||
|
||||
dev->d_len = 0;
|
||||
flags = (flags & ~TCP_NEWDATA) | TCP_CLOSE;
|
||||
}
|
||||
|
||||
return flags;
|
||||
|
||||
#ifdef CONFIG_NET_SOLINGER
|
||||
end_wait:
|
||||
pstate->cl_cb->flags = 0;
|
||||
pstate->cl_cb->priv = NULL;
|
||||
pstate->cl_cb->event = NULL;
|
||||
sem_post(&pstate->cl_sem);
|
||||
|
||||
ninfo("Resuming\n");
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
#endif /* NET_TCP_HAVE_STACK */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: tcp_close_txnotify
|
||||
*
|
||||
* Description:
|
||||
* Notify the appropriate device driver that we are have data ready to
|
||||
* be send (TCP)
|
||||
*
|
||||
* Parameters:
|
||||
* psock - Socket state structure
|
||||
* conn - The TCP connection structure
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef NET_TCP_HAVE_STACK
|
||||
static inline void tcp_close_txnotify(FAR struct socket *psock,
|
||||
FAR struct tcp_conn_s *conn)
|
||||
{
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
/* If both IPv4 and IPv6 support are enabled, then we will need to select
|
||||
* the device driver using the appropriate IP domain.
|
||||
*/
|
||||
|
||||
if (psock->s_domain == PF_INET)
|
||||
#endif
|
||||
{
|
||||
/* Notify the device driver that send data is available */
|
||||
|
||||
#ifdef CONFIG_NETDEV_MULTINIC
|
||||
netdev_ipv4_txnotify(conn->u.ipv4.laddr, conn->u.ipv4.raddr);
|
||||
#else
|
||||
netdev_ipv4_txnotify(conn->u.ipv4.raddr);
|
||||
#endif
|
||||
}
|
||||
#endif /* CONFIG_NET_IPv4 */
|
||||
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
else /* if (psock->s_domain == PF_INET6) */
|
||||
#endif /* CONFIG_NET_IPv4 */
|
||||
{
|
||||
/* Notify the device driver that send data is available */
|
||||
|
||||
DEBUGASSERT(psock->s_domain == PF_INET6);
|
||||
#ifdef CONFIG_NETDEV_MULTINIC
|
||||
netdev_ipv6_txnotify(conn->u.ipv6.laddr, conn->u.ipv6.raddr);
|
||||
#else
|
||||
netdev_ipv6_txnotify(conn->u.ipv6.raddr);
|
||||
#endif
|
||||
}
|
||||
#endif /* CONFIG_NET_IPv6 */
|
||||
}
|
||||
#endif /* NET_TCP_HAVE_STACK */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: tcp_close_disconnect
|
||||
*
|
||||
* Description:
|
||||
* Break any current TCP connection
|
||||
*
|
||||
* Parameters:
|
||||
* conn - TCP connection structure
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
* Assumptions:
|
||||
* Called from normal user-level logic
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef NET_TCP_HAVE_STACK
|
||||
static inline int tcp_close_disconnect(FAR struct socket *psock)
|
||||
{
|
||||
struct tcp_close_s state;
|
||||
FAR struct tcp_conn_s *conn;
|
||||
#ifdef CONFIG_NET_SOLINGER
|
||||
bool linger;
|
||||
#endif
|
||||
int ret = OK;
|
||||
|
||||
/* Interrupts are disabled here to avoid race conditions */
|
||||
|
||||
net_lock();
|
||||
conn = (FAR struct tcp_conn_s *)psock->s_conn;
|
||||
|
||||
/* If we have a semi-permanent write buffer callback in place, then
|
||||
* release it now.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
|
||||
if (psock->s_sndcb)
|
||||
{
|
||||
psock->s_sndcb = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
DEBUGASSERT(conn != NULL);
|
||||
|
||||
/* Check for the case where the host beat us and disconnected first */
|
||||
|
||||
if (conn->tcpstateflags == TCP_ESTABLISHED &&
|
||||
(state.cl_cb = tcp_callback_alloc(conn)) != NULL)
|
||||
{
|
||||
/* Set up to receive TCP data event callbacks */
|
||||
|
||||
state.cl_cb->flags = (TCP_NEWDATA | TCP_POLL | TCP_DISCONN_EVENTS);
|
||||
state.cl_cb->event = tcp_close_interrupt;
|
||||
|
||||
#ifdef CONFIG_NET_SOLINGER
|
||||
/* Check for a lingering close */
|
||||
|
||||
linger = _SO_GETOPT(psock->s_options, SO_LINGER);
|
||||
|
||||
/* Has a lingering close been requested */
|
||||
|
||||
if (linger)
|
||||
{
|
||||
/* A non-NULL value of the priv field means that lingering is
|
||||
* enabled.
|
||||
*/
|
||||
|
||||
state.cl_cb->priv = (FAR void *)&state;
|
||||
|
||||
/* Set up for the lingering wait */
|
||||
|
||||
state.cl_psock = psock;
|
||||
state.cl_result = -EBUSY;
|
||||
|
||||
/* This semaphore is used for signaling and, hence, should not have
|
||||
* priority inheritance enabled.
|
||||
*/
|
||||
|
||||
sem_init(&state.cl_sem, 0, 0);
|
||||
sem_setprotocol(&state.cl_sem, SEM_PRIO_NONE);
|
||||
|
||||
/* Record the time that we started the wait (in ticks) */
|
||||
|
||||
state.cl_start = clock_systimer();
|
||||
}
|
||||
else
|
||||
#endif /* CONFIG_NET_SOLINGER */
|
||||
|
||||
{
|
||||
/* We will close immediately. The NULL priv field signals this */
|
||||
|
||||
state.cl_cb->priv = NULL;
|
||||
|
||||
/* No further references on the connection */
|
||||
|
||||
conn->crefs = 0;
|
||||
}
|
||||
|
||||
/* Notify the device driver of the availability of TX data */
|
||||
|
||||
tcp_close_txnotify(psock, conn);
|
||||
|
||||
#ifdef CONFIG_NET_SOLINGER
|
||||
/* Wait only if we are lingering */
|
||||
|
||||
if (linger)
|
||||
{
|
||||
/* Wait for the disconnect event */
|
||||
|
||||
(void)net_lockedwait(&state.cl_sem);
|
||||
|
||||
/* We are now disconnected */
|
||||
|
||||
sem_destroy(&state.cl_sem);
|
||||
tcp_callback_free(conn, state.cl_cb);
|
||||
|
||||
/* Free the connection */
|
||||
|
||||
conn->crefs = 0; /* No more references on the connection */
|
||||
tcp_free(conn); /* Free network resources */
|
||||
|
||||
/* Get the result of the close */
|
||||
|
||||
ret = state.cl_result;
|
||||
}
|
||||
#endif /* CONFIG_NET_SOLINGER */
|
||||
}
|
||||
else
|
||||
{
|
||||
tcp_free(conn);
|
||||
}
|
||||
|
||||
net_unlock();
|
||||
return ret;
|
||||
}
|
||||
#endif /* NET_TCP_HAVE_STACK */
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: inet_close
|
||||
*
|
||||
* Description:
|
||||
* Performs the close operation on an AF_INET or AF_INET6 socket instance
|
||||
*
|
||||
* Parameters:
|
||||
* psock Socket instance
|
||||
*
|
||||
* Returned Value:
|
||||
* 0 on success; -1 on error with errno set appropriately.
|
||||
*
|
||||
* Assumptions:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int inet_close(FAR struct socket *psock)
|
||||
{
|
||||
/* Perform some pre-close operations for the AF_INET/AF_INET6 address
|
||||
* types.
|
||||
*/
|
||||
|
||||
switch (psock->s_type)
|
||||
{
|
||||
#ifdef CONFIG_NET_TCP
|
||||
case SOCK_STREAM:
|
||||
{
|
||||
#ifdef NET_TCP_HAVE_STACK
|
||||
FAR struct tcp_conn_s *conn = psock->s_conn;
|
||||
int ret;
|
||||
|
||||
/* Is this the last reference to the connection structure (there
|
||||
* could be more if the socket was dup'ed).
|
||||
*/
|
||||
|
||||
if (conn->crefs <= 1)
|
||||
{
|
||||
/* Yes... then perform the disconnection now */
|
||||
|
||||
tcp_unlisten(conn); /* No longer accepting connections */
|
||||
conn->crefs = 0; /* Discard our reference to the connection */
|
||||
|
||||
/* Break any current connections */
|
||||
|
||||
ret = tcp_close_disconnect(psock);
|
||||
if (ret < 0)
|
||||
{
|
||||
/* This would normally occur only if there is a timeout
|
||||
* from a lingering close.
|
||||
*/
|
||||
|
||||
nerr("ERROR: tcp_close_disconnect failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Stop the network monitor */
|
||||
|
||||
net_stopmonitor(conn);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No.. Just decrement the reference count */
|
||||
|
||||
conn->crefs--;
|
||||
}
|
||||
#else
|
||||
nwarn("WARNING: SOCK_STREAM support is not available in this configuration\n");
|
||||
return -EAFNOSUPPORT;
|
||||
#endif /* NET_TCP_HAVE_STACK */
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_NET_TCP */
|
||||
|
||||
#ifdef CONFIG_NET_UDP
|
||||
case SOCK_DGRAM:
|
||||
{
|
||||
#ifdef NET_UDP_HAVE_STACK
|
||||
FAR struct udp_conn_s *conn = psock->s_conn;
|
||||
|
||||
/* Is this the last reference to the connection structure (there
|
||||
* could be more if the socket was dup'ed).
|
||||
*/
|
||||
|
||||
if (conn->crefs <= 1)
|
||||
{
|
||||
/* Yes... free the connection structure */
|
||||
|
||||
conn->crefs = 0;
|
||||
udp_free(psock->s_conn);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No.. Just decrement the reference count */
|
||||
|
||||
conn->crefs--;
|
||||
}
|
||||
#else
|
||||
nwarn("WARNING: SOCK_DGRAM support is not available in this configuration\n");
|
||||
return -EAFNOSUPPORT;
|
||||
#endif /* NET_UDP_HAVE_STACK */
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_NET_UDP */
|
||||
|
||||
#ifdef CONFIG_NET_USRSOCK
|
||||
case SOCK_USRSOCK_TYPE:
|
||||
{
|
||||
FAR struct usrsock_conn_s *conn = psock->s_conn;
|
||||
int ret;
|
||||
|
||||
/* Is this the last reference to the connection structure (there
|
||||
* could be more if the socket was dup'ed).
|
||||
*/
|
||||
|
||||
if (conn->crefs <= 1)
|
||||
{
|
||||
/* Yes... inform user-space daemon of socket close. */
|
||||
|
||||
ret = usrsock_close(conn);
|
||||
|
||||
/* Free the connection structure */
|
||||
|
||||
conn->crefs = 0;
|
||||
usrsock_free(psock->s_conn);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
/* Return with error code, but free resources. */
|
||||
|
||||
nerr("ERROR: usrsock_close failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No.. Just decrement the reference count */
|
||||
|
||||
conn->crefs--;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
#endif /* CONFIG_NET */
|
567
net/socket/inet_connect.c
Normal file
567
net/socket/inet_connect.c
Normal file
|
@ -0,0 +1,567 @@
|
|||
/****************************************************************************
|
||||
* net/socket/inet_connect.c
|
||||
*
|
||||
* Copyright (C) 2007-2012, 2015-2017 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <arch/irq.h>
|
||||
|
||||
#include <nuttx/semaphore.h>
|
||||
#include <nuttx/net/net.h>
|
||||
#include <nuttx/net/netdev.h>
|
||||
#include <nuttx/net/udp.h>
|
||||
#include <nuttx/net/tcp.h>
|
||||
|
||||
#include "devif/devif.h"
|
||||
#include "tcp/tcp.h"
|
||||
#include "udp/udp.h"
|
||||
#include "socket/socket.h"
|
||||
#include "usrsock/usrsock.h"
|
||||
|
||||
#ifdef CONFIG_NET
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef NET_TCP_HAVE_STACK
|
||||
struct tcp_connect_s
|
||||
{
|
||||
FAR struct tcp_conn_s *tc_conn; /* Reference to TCP connection structure */
|
||||
FAR struct devif_callback_s *tc_cb; /* Reference to callback instance */
|
||||
FAR struct socket *tc_psock; /* The socket being connected */
|
||||
sem_t tc_sem; /* Semaphore signals recv completion */
|
||||
int tc_result; /* OK on success, otherwise a negated errno. */
|
||||
};
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef NET_TCP_HAVE_STACK
|
||||
static inline int psock_setup_callbacks(FAR struct socket *psock,
|
||||
FAR struct tcp_connect_s *pstate);
|
||||
static void psock_teardown_callbacks(FAR struct tcp_connect_s *pstate,
|
||||
int status);
|
||||
static uint16_t psock_connect_interrupt(FAR struct net_driver_s *dev,
|
||||
FAR void *pvconn, FAR void *pvpriv,
|
||||
uint16_t flags);
|
||||
static inline int psock_tcp_connect(FAR struct socket *psock,
|
||||
FAR const struct sockaddr *addr);
|
||||
#endif /* NET_TCP_HAVE_STACK */
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
/****************************************************************************
|
||||
* Name: psock_setup_callbacks
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef NET_TCP_HAVE_STACK
|
||||
static inline int psock_setup_callbacks(FAR struct socket *psock,
|
||||
FAR struct tcp_connect_s *pstate)
|
||||
{
|
||||
FAR struct tcp_conn_s *conn = psock->s_conn;
|
||||
int ret = -EBUSY;
|
||||
|
||||
/* Initialize the TCP state structure */
|
||||
|
||||
/* This semaphore is used for signaling and, hence, should not have
|
||||
* priority inheritance enabled.
|
||||
*/
|
||||
|
||||
(void)sem_init(&pstate->tc_sem, 0, 0); /* Doesn't really fail */
|
||||
(void)sem_setprotocol(&pstate->tc_sem, SEM_PRIO_NONE);
|
||||
|
||||
pstate->tc_conn = conn;
|
||||
pstate->tc_psock = psock;
|
||||
pstate->tc_result = -EAGAIN;
|
||||
|
||||
/* Set up the callbacks in the connection */
|
||||
|
||||
pstate->tc_cb = tcp_callback_alloc(conn);
|
||||
if (pstate->tc_cb)
|
||||
{
|
||||
/* Set up the connection "interrupt" handler */
|
||||
|
||||
pstate->tc_cb->flags = (TCP_NEWDATA | TCP_CLOSE | TCP_ABORT |
|
||||
TCP_TIMEDOUT | TCP_CONNECTED | NETDEV_DOWN);
|
||||
pstate->tc_cb->priv = (FAR void *)pstate;
|
||||
pstate->tc_cb->event = psock_connect_interrupt;
|
||||
ret = OK;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* NET_TCP_HAVE_STACK */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: psock_teardown_callbacks
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef NET_TCP_HAVE_STACK
|
||||
static void psock_teardown_callbacks(FAR struct tcp_connect_s *pstate,
|
||||
int status)
|
||||
{
|
||||
FAR struct tcp_conn_s *conn = pstate->tc_conn;
|
||||
|
||||
/* Make sure that no further interrupts are processed */
|
||||
|
||||
tcp_callback_free(conn, pstate->tc_cb);
|
||||
pstate->tc_cb = NULL;
|
||||
|
||||
/* If we successfully connected, we will continue to monitor the connection
|
||||
* state via callbacks.
|
||||
*/
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
/* Failed to connect. Stop the connection event monitor */
|
||||
|
||||
net_stopmonitor(conn);
|
||||
}
|
||||
}
|
||||
#endif /* NET_TCP_HAVE_STACK */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: psock_connect_interrupt
|
||||
*
|
||||
* Description:
|
||||
* This function is called from the interrupt level to perform the actual
|
||||
* connection operation via by the lower, device interfacing layer.
|
||||
*
|
||||
* Parameters:
|
||||
* dev The structure of the network driver that caused the interrupt
|
||||
* pvconn The connection structure associated with the socket
|
||||
* flags Set of events describing why the callback was invoked
|
||||
*
|
||||
* Returned Value:
|
||||
* The new flags setting
|
||||
*
|
||||
* Assumptions:
|
||||
* Running at the interrupt level
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef NET_TCP_HAVE_STACK
|
||||
static uint16_t psock_connect_interrupt(FAR struct net_driver_s *dev,
|
||||
FAR void *pvconn, FAR void *pvpriv,
|
||||
uint16_t flags)
|
||||
{
|
||||
struct tcp_connect_s *pstate = (struct tcp_connect_s *)pvpriv;
|
||||
|
||||
ninfo("flags: %04x\n", flags);
|
||||
|
||||
/* 'priv' might be null in some race conditions (?) */
|
||||
|
||||
if (pstate)
|
||||
{
|
||||
/* The following errors should be detected here (someday)
|
||||
*
|
||||
* ECONNREFUSED
|
||||
* No one listening on the remote address.
|
||||
* ENETUNREACH
|
||||
* Network is unreachable.
|
||||
* ETIMEDOUT
|
||||
* Timeout while attempting connection. The server may be too busy
|
||||
* to accept new connections.
|
||||
*/
|
||||
|
||||
/* TCP_CLOSE: The remote host has closed the connection
|
||||
* TCP_ABORT: The remote host has aborted the connection
|
||||
*/
|
||||
|
||||
if ((flags & (TCP_CLOSE | TCP_ABORT)) != 0)
|
||||
{
|
||||
/* Indicate that remote host refused the connection */
|
||||
|
||||
pstate->tc_result = -ECONNREFUSED;
|
||||
}
|
||||
|
||||
/* TCP_TIMEDOUT: Connection aborted due to too many retransmissions. */
|
||||
|
||||
else if ((flags & TCP_TIMEDOUT) != 0)
|
||||
{
|
||||
/* Indicate that the connection timedout?) */
|
||||
|
||||
pstate->tc_result = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
else if ((flags & NETDEV_DOWN) != 0)
|
||||
{
|
||||
/* The network device went down. Indicate that the remote host
|
||||
* is unreachable.
|
||||
*/
|
||||
|
||||
pstate->tc_result = -ENETUNREACH;
|
||||
}
|
||||
|
||||
/* TCP_CONNECTED: The socket is successfully connected */
|
||||
|
||||
else if ((flags & TCP_CONNECTED) != 0)
|
||||
{
|
||||
FAR struct socket *psock = pstate->tc_psock;
|
||||
DEBUGASSERT(psock);
|
||||
|
||||
/* Mark the connection bound and connected. NOTE this is
|
||||
* is done here (vs. later) in order to avoid any race condition
|
||||
* in the socket state. It is known to connected here and now,
|
||||
* but not necessarily at any time later.
|
||||
*/
|
||||
|
||||
psock->s_flags |= (_SF_BOUND | _SF_CONNECTED);
|
||||
|
||||
/* Indicate that the socket is no longer connected */
|
||||
|
||||
pstate->tc_result = OK;
|
||||
}
|
||||
|
||||
/* Otherwise, it is not an event of importance to us at the moment */
|
||||
|
||||
else
|
||||
{
|
||||
/* Drop data received in this state */
|
||||
|
||||
dev->d_len = 0;
|
||||
return flags & ~TCP_NEWDATA;
|
||||
}
|
||||
|
||||
ninfo("Resuming: %d\n", pstate->tc_result);
|
||||
|
||||
/* Stop further callbacks */
|
||||
|
||||
psock_teardown_callbacks(pstate, pstate->tc_result);
|
||||
|
||||
#ifdef CONFIG_NET_MULTILINK
|
||||
/* When we set up the connection structure, we did not know the size
|
||||
* of the initial MSS. Now that the connection is associated with a
|
||||
* network device, we now know the size of link layer header and can
|
||||
* determine the correct initial MSS.
|
||||
*/
|
||||
|
||||
DEBUGASSERT(pstate->tc_conn);
|
||||
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
if (pstate->tc_conn->domain == PF_INET)
|
||||
#endif
|
||||
{
|
||||
pstate->tc_conn->mss = TCP_IPv4_INITIAL_MSS(dev);
|
||||
}
|
||||
#endif /* CONFIG_NET_IPv4 */
|
||||
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
else
|
||||
#endif
|
||||
{
|
||||
pstate->tc_conn->mss = TCP_IPv6_INITIAL_MSS(dev);
|
||||
}
|
||||
#endif /* CONFIG_NET_IPv6 */
|
||||
|
||||
#ifdef CONFIG_NETDEV_MULTINIC
|
||||
/* We now have to filter all outgoing transfers so that they use only
|
||||
* the MSS of this device.
|
||||
*/
|
||||
|
||||
DEBUGASSERT(pstate->tc_conn->dev == NULL ||
|
||||
pstate->tc_conn->dev == dev);
|
||||
pstate->tc_conn->dev = dev;
|
||||
|
||||
#endif /* CONFIG_NETDEV_MULTINIC */
|
||||
#endif /* CONFIG_NET_MULTILINK */
|
||||
|
||||
/* Wake up the waiting thread */
|
||||
|
||||
sem_post(&pstate->tc_sem);
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
#endif /* NET_TCP_HAVE_STACK */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: psock_tcp_connect
|
||||
*
|
||||
* Description:
|
||||
* Perform a TCP connection
|
||||
*
|
||||
* Parameters:
|
||||
* psock - A reference to the socket structure of the socket to be connected
|
||||
* addr - The address of the remote server to connect to
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
* Assumptions:
|
||||
* Running at the interrupt level
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef NET_TCP_HAVE_STACK
|
||||
static inline int psock_tcp_connect(FAR struct socket *psock,
|
||||
FAR const struct sockaddr *addr)
|
||||
{
|
||||
struct tcp_connect_s state;
|
||||
int ret = OK;
|
||||
|
||||
/* Interrupts must be disabled through all of the following because
|
||||
* we cannot allow the network callback to occur until we are completely
|
||||
* setup.
|
||||
*/
|
||||
|
||||
net_lock();
|
||||
|
||||
/* Get the connection reference from the socket */
|
||||
|
||||
if (!psock->s_conn) /* Should always be non-NULL */
|
||||
{
|
||||
ret = -EINVAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Perform the TCP connection operation */
|
||||
|
||||
ret = tcp_connect(psock->s_conn, addr);
|
||||
}
|
||||
|
||||
if (ret >= 0)
|
||||
{
|
||||
/* Set up the callbacks in the connection */
|
||||
|
||||
ret = psock_setup_callbacks(psock, &state);
|
||||
if (ret >= 0)
|
||||
{
|
||||
/* Wait for either the connect to complete or for an error/timeout
|
||||
* 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-disabled
|
||||
* when the task restarts.
|
||||
*/
|
||||
|
||||
ret = net_lockedwait(&state.tc_sem);
|
||||
|
||||
/* Uninitialize the state structure */
|
||||
|
||||
(void)sem_destroy(&state.tc_sem);
|
||||
|
||||
/* If net_lockedwait failed, recover the negated error (probably -EINTR) */
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
ret = -get_errno();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If the wait succeeded, then get the new error value from
|
||||
* the state structure
|
||||
*/
|
||||
|
||||
ret = state.tc_result;
|
||||
}
|
||||
|
||||
/* Make sure that no further interrupts are processed */
|
||||
|
||||
psock_teardown_callbacks(&state, ret);
|
||||
}
|
||||
|
||||
/* Check if the socket was successfully connected. */
|
||||
|
||||
if (ret >= 0)
|
||||
{
|
||||
/* Yes... Now that we are connected, we need to set up to monitor
|
||||
* the state of the connection up the connection event monitor.
|
||||
*/
|
||||
|
||||
ret = net_startmonitor(psock);
|
||||
if (ret < 0)
|
||||
{
|
||||
/* net_startmonitor() can only fail on certain race
|
||||
* conditions where the connection was lost just before
|
||||
* this function was called. That is not expected to
|
||||
* happen in this context, but just in case...
|
||||
*/
|
||||
|
||||
net_lostconnection(psock, TCP_ABORT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
net_unlock();
|
||||
return ret;
|
||||
}
|
||||
#endif /* NET_TCP_HAVE_STACK */
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: inet_connect
|
||||
*
|
||||
* Description:
|
||||
* inet_connect() connects the local socket referred to by the structure
|
||||
* 'psock' to the address specified by 'addr'. The addrlen argument
|
||||
* specifies the size of 'addr'. The format of the address in 'addr' is
|
||||
* determined by the address space of the socket 'psock'.
|
||||
*
|
||||
* If the socket 'psock' is of type SOCK_DGRAM then 'addr' is the address
|
||||
* to which datagrams are sent by default, and the only address from which
|
||||
* datagrams are received. If the socket is of type SOCK_STREAM or
|
||||
* SOCK_SEQPACKET, this call attempts to make a connection to the socket
|
||||
* that is bound to the address specified by 'addr'.
|
||||
*
|
||||
* Generally, connection-based protocol sockets may successfully
|
||||
* inet_connect() only once; connectionless protocol sockets may use
|
||||
* inet_connect() multiple times to change their association.
|
||||
* Connectionless sockets may dissolve the association by connecting to
|
||||
* an address with the sa_family member of sockaddr set to AF_UNSPEC.
|
||||
*
|
||||
* Parameters:
|
||||
* psock Pointer to a socket structure initialized by psock_socket()
|
||||
* addr Server address (form depends on type of socket)
|
||||
* addrlen Length of actual 'addr'
|
||||
*
|
||||
* Returned Value:
|
||||
* 0 on success; a negated errno value on failue. See connect() for the
|
||||
* list of appropriate errno values to be returned.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int inet_connect(FAR struct socket *psock, FAR const struct sockaddr *addr,
|
||||
socklen_t addrlen)
|
||||
{
|
||||
FAR const struct sockaddr_in *inaddr = (FAR const struct sockaddr_in *)addr;
|
||||
|
||||
/* Verify that a valid address has been provided */
|
||||
|
||||
switch (inaddr->sin_family)
|
||||
{
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
case AF_INET:
|
||||
{
|
||||
if (addrlen < sizeof(struct sockaddr_in))
|
||||
{
|
||||
return -EBADF;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
case AF_INET6:
|
||||
{
|
||||
if (addrlen < sizeof(struct sockaddr_in6))
|
||||
{
|
||||
return -EBADF;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
#ifdef CONFIG_NET_USRSOCK
|
||||
if (psock->s_type == SOCK_USRSOCK_TYPE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
DEBUGPANIC();
|
||||
return -EAFNOSUPPORT;
|
||||
}
|
||||
|
||||
/* 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))
|
||||
{
|
||||
return -EISCONN;
|
||||
}
|
||||
|
||||
/* It's not ... Connect the TCP/IP socket */
|
||||
|
||||
return psock_tcp_connect(psock, addr);
|
||||
}
|
||||
#endif /* CONFIG_NET_TCP */
|
||||
|
||||
#ifdef CONFIG_NET_UDP
|
||||
case SOCK_DGRAM:
|
||||
{
|
||||
int ret = udp_connect(psock->s_conn, addr);
|
||||
if (ret < 0 || addr == NULL)
|
||||
{
|
||||
psock->s_flags &= ~_SF_CONNECTED;
|
||||
}
|
||||
else
|
||||
{
|
||||
psock->s_flags |= _SF_CONNECTED;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_NET_UDP */
|
||||
|
||||
#ifdef CONFIG_NET_USRSOCK
|
||||
case SOCK_USRSOCK_TYPE:
|
||||
{
|
||||
return usrsock_connect(psock, addr, addrlen);
|
||||
}
|
||||
#endif /* CONFIG_NET_USRSOCK */
|
||||
|
||||
default:
|
||||
return -EBADF;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NET */
|
1674
net/socket/inet_recvfrom.c
Normal file
1674
net/socket/inet_recvfrom.c
Normal file
File diff suppressed because it is too large
Load diff
1022
net/socket/inet_sockif.c
Normal file
1022
net/socket/inet_sockif.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,7 +1,7 @@
|
|||
/****************************************************************************
|
||||
* net/socket/listen.c
|
||||
*
|
||||
* Copyright (C) 2007-2009, 201-2016 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 2007-2009, 201-2017 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -38,17 +38,15 @@
|
|||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#if defined(CONFIG_NET) && CONFIG_NSOCKET_DESCRIPTORS > 0
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include "tcp/tcp.h"
|
||||
#include "local/local.h"
|
||||
#include "socket/socket.h"
|
||||
#include "usrsock/usrsock.h"
|
||||
|
||||
#if defined(CONFIG_NET) && CONFIG_NSOCKET_DESCRIPTORS > 0
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
|
@ -86,83 +84,29 @@
|
|||
int psock_listen(FAR struct socket *psock, int backlog)
|
||||
{
|
||||
int errcode;
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(psock != NULL);
|
||||
|
||||
/* Verify that the sockfd corresponds to a connected SOCK_STREAM */
|
||||
|
||||
if (psock->s_type != SOCK_STREAM || !psock->s_conn)
|
||||
if (psock == NULL || psock->s_conn == NULL)
|
||||
{
|
||||
#ifdef CONFIG_NET_USRSOCK
|
||||
if (psock->s_type == SOCK_USRSOCK_TYPE)
|
||||
{
|
||||
#warning "Missing logic"
|
||||
}
|
||||
#endif
|
||||
|
||||
errcode = EOPNOTSUPP;
|
||||
nerr("ERROR: Invalid or unconnected socket\n");
|
||||
errcode = EINVAL;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET_LOCAL
|
||||
#ifdef CONFIG_NET_TCP
|
||||
if (psock->s_domain == PF_LOCAL)
|
||||
#endif
|
||||
/* Let the address family's listen() method handle the operation */
|
||||
|
||||
DEBUGASSERT(psock->s_sockif != NULL && psock->s_sockif->si_listen != NULL);
|
||||
ret = psock->s_sockif->si_listen(psock, backlog);
|
||||
if (ret < 0)
|
||||
{
|
||||
FAR struct local_conn_s *conn =
|
||||
(FAR struct local_conn_s *)psock->s_conn;
|
||||
|
||||
errcode = local_listen(conn, backlog);
|
||||
if (errcode < 0)
|
||||
{
|
||||
errcode = -errcode;
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_NET_LOCAL */
|
||||
|
||||
#ifdef CONFIG_NET_TCP
|
||||
#ifdef CONFIG_NET_LOCAL
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#ifdef NET_TCP_HAVE_STACK
|
||||
FAR struct tcp_conn_s *conn =
|
||||
(FAR struct tcp_conn_s *)psock->s_conn;
|
||||
|
||||
if (conn->lport <= 0)
|
||||
{
|
||||
errcode = EOPNOTSUPP;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* Set up the backlog for this connection */
|
||||
|
||||
#ifdef CONFIG_NET_TCPBACKLOG
|
||||
errcode = tcp_backlogcreate(conn, backlog);
|
||||
if (errcode < 0)
|
||||
{
|
||||
errcode = -errcode;
|
||||
goto errout;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Start listening to the bound port. This enables callbacks when
|
||||
* accept() is called and enables poll()/select() logic.
|
||||
*/
|
||||
|
||||
errcode = tcp_listen(conn);
|
||||
if (errcode < 0)
|
||||
{
|
||||
errcode = -errcode;
|
||||
goto errout;
|
||||
}
|
||||
#else
|
||||
errcode = EOPNOTSUPP;
|
||||
nerr("ERROR: si_listen failed: %d\n", ret);
|
||||
errcode = -ret;
|
||||
goto errout;
|
||||
#endif /* NET_TCP_HAVE_STACK */
|
||||
}
|
||||
#endif /* CONFIG_NET_TCP */
|
||||
|
||||
psock->s_flags |= _SF_LISTENING;
|
||||
return OK;
|
||||
|
|
|
@ -79,6 +79,7 @@ int net_clone(FAR struct socket *psock1, FAR struct socket *psock2)
|
|||
|
||||
psock2->s_domain = psock1->s_domain; /* IP domain: PF_INET, PF_INET6, or PF_PACKET */
|
||||
psock2->s_type = psock1->s_type; /* Protocol type: Only SOCK_STREAM or SOCK_DGRAM */
|
||||
psock2->s_sockif = psock1->s_sockif; /* Socket interface */
|
||||
psock2->s_flags = psock1->s_flags; /* See _SF_* definitions */
|
||||
#ifdef CONFIG_NET_SOCKOPTS
|
||||
psock2->s_options = psock1->s_options; /* Selected socket options */
|
||||
|
@ -94,65 +95,19 @@ int net_clone(FAR struct socket *psock1, FAR struct socket *psock2)
|
|||
* instance for TCP send */
|
||||
#endif
|
||||
|
||||
/* Increment the reference count on the connection */
|
||||
/* Increment the reference count on the socket */
|
||||
|
||||
DEBUGASSERT(psock2->s_conn);
|
||||
psock2->s_crefs = 1; /* One reference on the new socket itself */
|
||||
|
||||
#ifdef CONFIG_NET_LOCAL
|
||||
if (psock2->s_domain == PF_LOCAL)
|
||||
{
|
||||
FAR struct local_conn_s *conn = psock2->s_conn;
|
||||
DEBUGASSERT(conn->lc_crefs > 0 && conn->lc_crefs < 255);
|
||||
conn->lc_crefs++;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#ifdef CONFIG_NET_PKT
|
||||
if (psock2->s_type == SOCK_RAW)
|
||||
{
|
||||
FAR struct pkt_conn_s *conn = psock2->s_conn;
|
||||
DEBUGASSERT(conn->crefs > 0 && conn->crefs < 255);
|
||||
conn->crefs++;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#ifdef NET_TCP_HAVE_STACK
|
||||
if (psock2->s_type == SOCK_STREAM)
|
||||
{
|
||||
FAR struct tcp_conn_s *conn = psock2->s_conn;
|
||||
DEBUGASSERT(conn->crefs > 0 && conn->crefs < 255);
|
||||
conn->crefs++;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#ifdef NET_UDP_HAVE_STACK
|
||||
if (psock2->s_type == SOCK_DGRAM)
|
||||
{
|
||||
FAR struct udp_conn_s *conn = psock2->s_conn;
|
||||
DEBUGASSERT(conn->crefs > 0 && conn->crefs < 255);
|
||||
conn->crefs++;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#ifdef CONFIG_NET_USRSOCK
|
||||
if (psock2->s_type == SOCK_USRSOCK_TYPE)
|
||||
{
|
||||
FAR struct usrsock_conn_s *conn = psock2->s_conn;
|
||||
DEBUGASSERT(conn->crefs > 0 && conn->crefs < 255);
|
||||
conn->crefs++;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
nerr("ERROR: Unsupported type: %d\n", psock2->s_type);
|
||||
ret = -EBADF;
|
||||
}
|
||||
/* Increment the reference count on the underlying connection structure
|
||||
* for this address family type.
|
||||
*/
|
||||
|
||||
DEBUGASSERT(psock2->s_sockif != NULL && psock2->s_sockif->si_addref != NULL);
|
||||
psock2->s_sockif->si_addref(psock2);
|
||||
|
||||
net_unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NET */
|
||||
|
||||
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#ifdef CONFIG_NET
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
@ -48,450 +47,11 @@
|
|||
#include <debug.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <arch/irq.h>
|
||||
|
||||
#include <nuttx/semaphore.h>
|
||||
#include <nuttx/net/net.h>
|
||||
#include <nuttx/net/netdev.h>
|
||||
#include <nuttx/net/tcp.h>
|
||||
#include <nuttx/net/udp.h>
|
||||
|
||||
#ifdef CONFIG_NET_SOLINGER
|
||||
# include <nuttx/clock.h>
|
||||
#endif
|
||||
|
||||
#include "netdev/netdev.h"
|
||||
#include "devif/devif.h"
|
||||
#include "tcp/tcp.h"
|
||||
#include "udp/udp.h"
|
||||
#include "pkt/pkt.h"
|
||||
#include "local/local.h"
|
||||
#include "socket/socket.h"
|
||||
#include "usrsock/usrsock.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef NET_TCP_HAVE_STACK
|
||||
struct tcp_close_s
|
||||
{
|
||||
FAR struct devif_callback_s *cl_cb; /* Reference to TCP callback instance */
|
||||
#ifdef CONFIG_NET_SOLINGER
|
||||
FAR struct socket *cl_psock; /* Reference to the TCP socket */
|
||||
sem_t cl_sem; /* Signals disconnect completion */
|
||||
int cl_result; /* The result of the close */
|
||||
systime_t cl_start; /* Time close started (in ticks) */
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: close_timeout
|
||||
*
|
||||
* Description:
|
||||
* Check for a timeout on a lingering close.
|
||||
*
|
||||
* Parameters:
|
||||
* pstate - close state structure
|
||||
*
|
||||
* Returned Value:
|
||||
* TRUE:timeout FALSE:no timeout
|
||||
*
|
||||
* Assumptions:
|
||||
* Running at the interrupt level
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(NET_TCP_HAVE_STACK) && defined(CONFIG_NET_SOLINGER)
|
||||
static inline int close_timeout(FAR struct tcp_close_s *pstate)
|
||||
{
|
||||
FAR struct socket *psock = 0;
|
||||
|
||||
/* Make sure that we are performing a lingering close */
|
||||
|
||||
if (pstate)
|
||||
{
|
||||
/* Yes Check for a timeout configured via setsockopts(SO_LINGER).
|
||||
* If none... we well let the send wait forever.
|
||||
*/
|
||||
|
||||
psock = pstate->cl_psock;
|
||||
if (psock && psock->s_linger != 0)
|
||||
{
|
||||
/* Check if the configured timeout has elapsed */
|
||||
|
||||
return net_timeo(pstate->cl_start, psock->s_linger);
|
||||
}
|
||||
}
|
||||
|
||||
/* No timeout */
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
#endif /* NET_TCP_HAVE_STACK && CONFIG_NET_SOLINGER */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: netclose_interrupt
|
||||
*
|
||||
* Description:
|
||||
* Handle network callback events.
|
||||
*
|
||||
* Parameters:
|
||||
* conn - TCP connection structure
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
* Assumptions:
|
||||
* Called from normal user-level logic
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef NET_TCP_HAVE_STACK
|
||||
static uint16_t netclose_interrupt(FAR struct net_driver_s *dev,
|
||||
FAR void *pvconn, FAR void *pvpriv,
|
||||
uint16_t flags)
|
||||
{
|
||||
#ifdef CONFIG_NET_SOLINGER
|
||||
FAR struct tcp_close_s *pstate = (FAR struct tcp_close_s *)pvpriv;
|
||||
#endif
|
||||
FAR struct tcp_conn_s *conn = (FAR struct tcp_conn_s *)pvconn;
|
||||
|
||||
DEBUGASSERT(conn != NULL);
|
||||
|
||||
ninfo("conn: %p flags: %04x\n", conn, flags);
|
||||
|
||||
/* TCP_DISCONN_EVENTS:
|
||||
* TCP_CLOSE: The remote host has closed the connection
|
||||
* TCP_ABORT: The remote host has aborted the connection
|
||||
* TCP_TIMEDOUT: The remote did not respond, the connection timed out
|
||||
* NETDEV_DOWN: The network device went down
|
||||
*/
|
||||
|
||||
if ((flags & TCP_DISCONN_EVENTS) != 0)
|
||||
{
|
||||
/* The disconnection is complete */
|
||||
|
||||
#ifdef CONFIG_NET_SOLINGER
|
||||
/* pstate non-NULL means that we are performing a LINGERing close. */
|
||||
|
||||
if (pstate)
|
||||
{
|
||||
/* Wake up the waiting thread with a successful result */
|
||||
|
||||
pstate->cl_result = OK;
|
||||
goto end_wait;
|
||||
}
|
||||
|
||||
/* Otherwise, nothing is waiting on the close event and we can perform
|
||||
* the completion actions here.
|
||||
*/
|
||||
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* Free connection resources */
|
||||
|
||||
tcp_free(conn);
|
||||
|
||||
/* Stop further callbacks */
|
||||
|
||||
flags = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET_SOLINGER
|
||||
/* Check for a timeout. */
|
||||
|
||||
else if (pstate && close_timeout(pstate))
|
||||
{
|
||||
/* Yes.. Wake up the waiting thread and report the timeout */
|
||||
|
||||
nerr("ERROR: CLOSE timeout\n");
|
||||
pstate->cl_result = -ETIMEDOUT;
|
||||
goto end_wait;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NET_SOLINGER */
|
||||
|
||||
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
|
||||
/* Check if all outstanding bytes have been ACKed */
|
||||
|
||||
else if (conn->unacked != 0 || !sq_empty(&conn->write_q))
|
||||
{
|
||||
/* No... we are still waiting for ACKs. Drop any received data, but
|
||||
* do not yet report TCP_CLOSE in the response.
|
||||
*/
|
||||
|
||||
dev->d_len = 0;
|
||||
flags = (flags & ~TCP_NEWDATA);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NET_TCP_WRITE_BUFFERS */
|
||||
|
||||
else
|
||||
{
|
||||
/* Drop data received in this state and make sure that TCP_CLOSE
|
||||
* is set in the response
|
||||
*/
|
||||
|
||||
dev->d_len = 0;
|
||||
flags = (flags & ~TCP_NEWDATA) | TCP_CLOSE;
|
||||
}
|
||||
|
||||
return flags;
|
||||
|
||||
#ifdef CONFIG_NET_SOLINGER
|
||||
end_wait:
|
||||
pstate->cl_cb->flags = 0;
|
||||
pstate->cl_cb->priv = NULL;
|
||||
pstate->cl_cb->event = NULL;
|
||||
sem_post(&pstate->cl_sem);
|
||||
|
||||
ninfo("Resuming\n");
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
#endif /* NET_TCP_HAVE_STACK */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: netclose_txnotify
|
||||
*
|
||||
* Description:
|
||||
* Notify the appropriate device driver that we are have data ready to
|
||||
* be send (TCP)
|
||||
*
|
||||
* Parameters:
|
||||
* psock - Socket state structure
|
||||
* conn - The TCP connection structure
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef NET_TCP_HAVE_STACK
|
||||
static inline void netclose_txnotify(FAR struct socket *psock,
|
||||
FAR struct tcp_conn_s *conn)
|
||||
{
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
/* If both IPv4 and IPv6 support are enabled, then we will need to select
|
||||
* the device driver using the appropriate IP domain.
|
||||
*/
|
||||
|
||||
if (psock->s_domain == PF_INET)
|
||||
#endif
|
||||
{
|
||||
/* Notify the device driver that send data is available */
|
||||
|
||||
#ifdef CONFIG_NETDEV_MULTINIC
|
||||
netdev_ipv4_txnotify(conn->u.ipv4.laddr, conn->u.ipv4.raddr);
|
||||
#else
|
||||
netdev_ipv4_txnotify(conn->u.ipv4.raddr);
|
||||
#endif
|
||||
}
|
||||
#endif /* CONFIG_NET_IPv4 */
|
||||
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
else /* if (psock->s_domain == PF_INET6) */
|
||||
#endif /* CONFIG_NET_IPv4 */
|
||||
{
|
||||
/* Notify the device driver that send data is available */
|
||||
|
||||
DEBUGASSERT(psock->s_domain == PF_INET6);
|
||||
#ifdef CONFIG_NETDEV_MULTINIC
|
||||
netdev_ipv6_txnotify(conn->u.ipv6.laddr, conn->u.ipv6.raddr);
|
||||
#else
|
||||
netdev_ipv6_txnotify(conn->u.ipv6.raddr);
|
||||
#endif
|
||||
}
|
||||
#endif /* CONFIG_NET_IPv6 */
|
||||
}
|
||||
#endif /* NET_TCP_HAVE_STACK */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: netclose_disconnect
|
||||
*
|
||||
* Description:
|
||||
* Break any current TCP connection
|
||||
*
|
||||
* Parameters:
|
||||
* conn - TCP connection structure
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
* Assumptions:
|
||||
* Called from normal user-level logic
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef NET_TCP_HAVE_STACK
|
||||
static inline int netclose_disconnect(FAR struct socket *psock)
|
||||
{
|
||||
struct tcp_close_s state;
|
||||
FAR struct tcp_conn_s *conn;
|
||||
#ifdef CONFIG_NET_SOLINGER
|
||||
bool linger;
|
||||
#endif
|
||||
int ret = OK;
|
||||
|
||||
/* Interrupts are disabled here to avoid race conditions */
|
||||
|
||||
net_lock();
|
||||
conn = (FAR struct tcp_conn_s *)psock->s_conn;
|
||||
|
||||
/* If we have a semi-permanent write buffer callback in place, then
|
||||
* release it now.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
|
||||
if (psock->s_sndcb)
|
||||
{
|
||||
psock->s_sndcb = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
DEBUGASSERT(conn != NULL);
|
||||
|
||||
/* Check for the case where the host beat us and disconnected first */
|
||||
|
||||
if (conn->tcpstateflags == TCP_ESTABLISHED &&
|
||||
(state.cl_cb = tcp_callback_alloc(conn)) != NULL)
|
||||
{
|
||||
/* Set up to receive TCP data event callbacks */
|
||||
|
||||
state.cl_cb->flags = (TCP_NEWDATA | TCP_POLL | TCP_DISCONN_EVENTS);
|
||||
state.cl_cb->event = netclose_interrupt;
|
||||
|
||||
#ifdef CONFIG_NET_SOLINGER
|
||||
/* Check for a lingering close */
|
||||
|
||||
linger = _SO_GETOPT(psock->s_options, SO_LINGER);
|
||||
|
||||
/* Has a lingering close been requested */
|
||||
|
||||
if (linger)
|
||||
{
|
||||
/* A non-NULL value of the priv field means that lingering is
|
||||
* enabled.
|
||||
*/
|
||||
|
||||
state.cl_cb->priv = (FAR void *)&state;
|
||||
|
||||
/* Set up for the lingering wait */
|
||||
|
||||
state.cl_psock = psock;
|
||||
state.cl_result = -EBUSY;
|
||||
|
||||
/* This semaphore is used for signaling and, hence, should not have
|
||||
* priority inheritance enabled.
|
||||
*/
|
||||
|
||||
sem_init(&state.cl_sem, 0, 0);
|
||||
sem_setprotocol(&state.cl_sem, SEM_PRIO_NONE);
|
||||
|
||||
/* Record the time that we started the wait (in ticks) */
|
||||
|
||||
state.cl_start = clock_systimer();
|
||||
}
|
||||
else
|
||||
#endif /* CONFIG_NET_SOLINGER */
|
||||
|
||||
{
|
||||
/* We will close immediately. The NULL priv field signals this */
|
||||
|
||||
state.cl_cb->priv = NULL;
|
||||
|
||||
/* No further references on the connection */
|
||||
|
||||
conn->crefs = 0;
|
||||
}
|
||||
|
||||
/* Notify the device driver of the availability of TX data */
|
||||
|
||||
netclose_txnotify(psock, conn);
|
||||
|
||||
#ifdef CONFIG_NET_SOLINGER
|
||||
/* Wait only if we are lingering */
|
||||
|
||||
if (linger)
|
||||
{
|
||||
/* Wait for the disconnect event */
|
||||
|
||||
(void)net_lockedwait(&state.cl_sem);
|
||||
|
||||
/* We are now disconnected */
|
||||
|
||||
sem_destroy(&state.cl_sem);
|
||||
tcp_callback_free(conn, state.cl_cb);
|
||||
|
||||
/* Free the connection */
|
||||
|
||||
conn->crefs = 0; /* No more references on the connection */
|
||||
tcp_free(conn); /* Free network resources */
|
||||
|
||||
/* Get the result of the close */
|
||||
|
||||
ret = state.cl_result;
|
||||
}
|
||||
#endif /* CONFIG_NET_SOLINGER */
|
||||
}
|
||||
else
|
||||
{
|
||||
tcp_free(conn);
|
||||
}
|
||||
|
||||
net_unlock();
|
||||
return ret;
|
||||
}
|
||||
#endif /* NET_TCP_HAVE_STACK */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: local_close
|
||||
*
|
||||
* Description:
|
||||
* Performs the close operation on a local socket instance
|
||||
*
|
||||
* Parameters:
|
||||
* psock Socket instance
|
||||
*
|
||||
* Returned Value:
|
||||
* 0 on success; -1 on error with errno set appropriately.
|
||||
*
|
||||
* Assumptions:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET_LOCAL
|
||||
static void local_close(FAR struct socket *psock)
|
||||
{
|
||||
FAR struct local_conn_s *conn = psock->s_conn;
|
||||
|
||||
/* Is this the last reference to the connection structure (there could
|
||||
* be more if the socket was dup'ed).
|
||||
*/
|
||||
|
||||
if (conn->lc_crefs <= 1)
|
||||
{
|
||||
conn->lc_crefs = 0;
|
||||
local_release(conn);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No.. Just decrement the reference count */
|
||||
|
||||
conn->lc_crefs--;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_NET_LOCAL */
|
||||
#ifdef CONFIG_NET
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
|
@ -516,6 +76,7 @@ static void local_close(FAR struct socket *psock)
|
|||
int psock_close(FAR struct socket *psock)
|
||||
{
|
||||
int errcode;
|
||||
int ret;
|
||||
|
||||
/* Verify that the sockfd corresponds to valid, allocated socket */
|
||||
|
||||
|
@ -535,185 +96,17 @@ int psock_close(FAR struct socket *psock)
|
|||
|
||||
if (psock->s_crefs <= 1 && psock->s_conn != NULL)
|
||||
{
|
||||
/* Perform local side of the close depending on the protocol type */
|
||||
/* Let the address family's close() method handle the operation */
|
||||
|
||||
switch (psock->s_type)
|
||||
DEBUGASSERT(psock->s_sockif != NULL && psock->s_sockif->si_close != NULL);
|
||||
ret = psock->s_sockif->si_close(psock);
|
||||
|
||||
/* Was the close successful */
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_LOCAL_STREAM)
|
||||
case SOCK_STREAM:
|
||||
{
|
||||
#ifdef CONFIG_NET_LOCAL_STREAM
|
||||
#ifdef CONFIG_NET_TCP
|
||||
if (psock->s_domain == PF_LOCAL)
|
||||
#endif
|
||||
{
|
||||
/* Release our reference to the local connection structure */
|
||||
|
||||
local_close(psock);
|
||||
}
|
||||
#endif /* CONFIG_NET_LOCAL_STREAM */
|
||||
|
||||
#ifdef CONFIG_NET_TCP
|
||||
#ifdef CONFIG_NET_LOCAL_STREAM
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#ifdef NET_TCP_HAVE_STACK
|
||||
FAR struct tcp_conn_s *conn = psock->s_conn;
|
||||
|
||||
/* Is this the last reference to the connection structure
|
||||
* (there could be more if the socket was dup'ed).
|
||||
*/
|
||||
|
||||
if (conn->crefs <= 1)
|
||||
{
|
||||
/* Yes... then perform the disconnection now */
|
||||
|
||||
tcp_unlisten(conn); /* No longer accepting connections */
|
||||
conn->crefs = 0; /* Discard our reference to the connection */
|
||||
|
||||
/* Break any current connections */
|
||||
|
||||
errcode = netclose_disconnect(psock);
|
||||
if (errcode < 0)
|
||||
{
|
||||
/* This would normally occur only if there is a
|
||||
* timeout from a lingering close.
|
||||
*/
|
||||
|
||||
goto errout_with_psock;
|
||||
}
|
||||
|
||||
/* Stop the network monitor */
|
||||
|
||||
net_stopmonitor(conn);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No.. Just decrement the reference count */
|
||||
|
||||
conn->crefs--;
|
||||
}
|
||||
#endif /* NET_TCP_HAVE_STACK */
|
||||
}
|
||||
#endif /* CONFIG_NET_TCP || CONFIG_NET_LOCAL_STREAM */
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_LOCAL_DGRAM)
|
||||
case SOCK_DGRAM:
|
||||
{
|
||||
#ifdef CONFIG_NET_LOCAL_DGRAM
|
||||
#ifdef CONFIG_NET_UDP
|
||||
if (psock->s_domain == PF_LOCAL)
|
||||
#endif
|
||||
{
|
||||
/* Release our reference to the local connection structure */
|
||||
|
||||
local_close(psock);
|
||||
}
|
||||
#endif /* CONFIG_NET_LOCAL_DGRAM */
|
||||
|
||||
#ifdef CONFIG_NET_UDP
|
||||
#ifdef CONFIG_NET_LOCAL_DGRAM
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#ifdef NET_UDP_HAVE_STACK
|
||||
FAR struct udp_conn_s *conn = psock->s_conn;
|
||||
|
||||
/* Is this the last reference to the connection structure
|
||||
* (there could be more if the socket was dup'ed).
|
||||
*/
|
||||
|
||||
if (conn->crefs <= 1)
|
||||
{
|
||||
/* Yes... free the connection structure */
|
||||
|
||||
conn->crefs = 0;
|
||||
udp_free(psock->s_conn);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No.. Just decrement the reference count */
|
||||
|
||||
conn->crefs--;
|
||||
}
|
||||
#endif /* NET_UDP_HAVE_STACK */
|
||||
}
|
||||
#endif /* CONFIG_NET_UDP || CONFIG_NET_LOCAL_DGRAM */
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_PKT
|
||||
case SOCK_RAW:
|
||||
{
|
||||
FAR struct pkt_conn_s *conn = psock->s_conn;
|
||||
|
||||
/* Is this the last reference to the connection structure (there
|
||||
* could be more if the socket was dup'ed).
|
||||
*/
|
||||
|
||||
if (conn->crefs <= 1)
|
||||
{
|
||||
/* Yes... free the connection structure */
|
||||
|
||||
conn->crefs = 0; /* No more references on the connection */
|
||||
pkt_free(psock->s_conn); /* Free network resources */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No.. Just decrement the reference count */
|
||||
|
||||
conn->crefs--;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_USRSOCK
|
||||
case SOCK_USRSOCK_TYPE:
|
||||
{
|
||||
FAR struct usrsock_conn_s *conn = psock->s_conn;
|
||||
|
||||
/* Is this the last reference to the connection structure (there
|
||||
* could be more if the socket was dup'ed).
|
||||
*/
|
||||
|
||||
if (conn->crefs <= 1)
|
||||
{
|
||||
/* Yes... inform user-space daemon of socket close. */
|
||||
|
||||
errcode = usrsock_close(conn);
|
||||
|
||||
/* Free the connection structure */
|
||||
|
||||
conn->crefs = 0;
|
||||
usrsock_free(psock->s_conn);
|
||||
|
||||
if (errcode < 0)
|
||||
{
|
||||
/* Return with error code, but free resources. */
|
||||
|
||||
errcode = -errcode;
|
||||
goto errout_with_psock;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No.. Just decrement the reference count */
|
||||
|
||||
conn->crefs--;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
errcode = EBADF;
|
||||
goto errout;
|
||||
errcode = -ret;
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -722,11 +115,6 @@ int psock_close(FAR struct socket *psock)
|
|||
sock_release(psock);
|
||||
return OK;
|
||||
|
||||
#if defined(NET_TCP_HAVE_STACK) || defined(CONFIG_NET_USRSOCK)
|
||||
errout_with_psock:
|
||||
sock_release(psock);
|
||||
#endif
|
||||
|
||||
errout:
|
||||
set_errno(errcode);
|
||||
return ERROR;
|
||||
|
|
111
net/socket/net_sockif.c
Normal file
111
net/socket/net_sockif.c
Normal file
|
@ -0,0 +1,111 @@
|
|||
/****************************************************************************
|
||||
* net/socket/net_sockif.c
|
||||
*
|
||||
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/net/net.h>
|
||||
|
||||
#include "local/local.h"
|
||||
#include "pkt/pkt.h"
|
||||
#include "socket/socket.h"
|
||||
|
||||
#ifdef CONFIG_NET
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: net_sockif
|
||||
*
|
||||
* Description:
|
||||
* Return the socket interface associated with this address family.
|
||||
*
|
||||
* Parameters:
|
||||
* family - Address family
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, a non-NULL instance of struct sock_intf_s is returned. NULL
|
||||
* is returned only if the address family is not supported.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR const struct sock_intf_s *net_sockif(sa_family_t family)
|
||||
{
|
||||
FAR const struct sock_intf_s *sockif = NULL;
|
||||
|
||||
/* Get the socket interface */
|
||||
|
||||
switch (family)
|
||||
{
|
||||
#if defined(CONFIG_NET_IPv4) || defined(CONFIG_NET_IPv6)
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
case PF_INET:
|
||||
#endif
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
case PF_INET6:
|
||||
#endif
|
||||
sockif = &g_inet_sockif;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_LOCAL
|
||||
case PF_LOCAL:
|
||||
sockif = &g_local_sockif;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_PKT
|
||||
case PF_PACKET:
|
||||
sockif = &g_pkt_sockif;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
nerr("ERROR: Address family unsupported: %d\n", family);
|
||||
}
|
||||
|
||||
return sockif;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NET */
|
|
@ -84,7 +84,7 @@ int net_vfcntl(int sockfd, int cmd, va_list ap)
|
|||
|
||||
/* Verify that the sockfd corresponds to valid, allocated socket */
|
||||
|
||||
if (!psock || psock->s_crefs <= 0)
|
||||
if (psock == NULL || psock->s_crefs <= 0)
|
||||
{
|
||||
errcode = EBADF;
|
||||
goto errout;
|
||||
|
@ -140,38 +140,25 @@ int net_vfcntl(int sockfd, int cmd, va_list ap)
|
|||
*/
|
||||
|
||||
{
|
||||
sockcaps_t sockcaps;
|
||||
|
||||
/* 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 */
|
||||
DEBUGASSERT(psock->s_sockif != NULL &&
|
||||
psock->s_sockif->si_sockcaps != NULL);
|
||||
sockcaps = psock->s_sockif->si_sockcaps(psock);
|
||||
|
||||
#ifdef CONFIG_NET_USRSOCK
|
||||
if (psock->s_type == SOCK_USRSOCK_TYPE && _SS_ISNONBLOCK(psock->s_flags))
|
||||
if ((sockcaps & SOCKCAP_NONBLOCKING) != 0 &&
|
||||
_SS_ISNONBLOCK(psock->s_flags))
|
||||
{
|
||||
ret |= O_NONBLOCK;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -185,16 +172,19 @@ int net_vfcntl(int sockfd, int cmd, va_list ap)
|
|||
*/
|
||||
|
||||
{
|
||||
#if defined(CONFIG_NET_LOCAL) || defined(CONFIG_NET_TCP_READAHEAD) || \
|
||||
defined(CONFIG_NET_UDP_READAHEAD) || defined(CONFIG_NET_USRSOCK)
|
||||
/* 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 */
|
||||
sockcaps_t sockcaps;
|
||||
|
||||
DEBUGASSERT(psock->s_sockif != NULL &&
|
||||
psock->s_sockif->si_sockcaps != NULL);
|
||||
sockcaps = psock->s_sockif->si_sockcaps(psock);
|
||||
|
||||
if ((sockcaps & SOCKCAP_NONBLOCKING) != 0)
|
||||
{
|
||||
if ((mode & O_NONBLOCK) != 0)
|
||||
{
|
||||
|
@ -206,37 +196,6 @@ int net_vfcntl(int sockfd, int cmd, va_list ap)
|
|||
}
|
||||
}
|
||||
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
|
||||
#if defined(CONFIG_NET_USRSOCK)
|
||||
if (psock->s_type == SOCK_USRSOCK_TYPE) /* usrsock socket */
|
||||
{
|
||||
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 || CONFIG_NET_USRSOCK */
|
||||
{
|
||||
nerr("ERROR: Non-blocking not supported for this socket\n");
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -42,6 +42,8 @@
|
|||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/cancelpt.h>
|
||||
|
||||
|
@ -51,7 +53,6 @@
|
|||
#include "sixlowpan/sixlowpan.h"
|
||||
#include "local/local.h"
|
||||
#include "socket/socket.h"
|
||||
#include "usrsock/usrsock.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
|
@ -126,132 +127,21 @@ ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len,
|
|||
{
|
||||
ssize_t ret;
|
||||
|
||||
DEBUGASSERT(psock != NULL && buf != NULL);
|
||||
|
||||
/* Treat as a cancellation point */
|
||||
|
||||
(void)enter_cancellation_point();
|
||||
|
||||
switch (psock->s_type)
|
||||
{
|
||||
#if defined(CONFIG_NET_PKT)
|
||||
case SOCK_RAW:
|
||||
{
|
||||
/* Raw packet send */
|
||||
/* Let the address family's send() method handle the operation */
|
||||
|
||||
ret = psock_pkt_send(psock, buf, len);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_LOCAL_STREAM)
|
||||
case SOCK_STREAM:
|
||||
{
|
||||
#ifdef CONFIG_NET_LOCAL_STREAM
|
||||
#ifdef CONFIG_NET_TCP
|
||||
if (psock->s_domain == PF_LOCAL)
|
||||
#endif
|
||||
{
|
||||
/* Local TCP packet send */
|
||||
|
||||
ret = psock_local_send(psock, buf, len, flags);
|
||||
}
|
||||
#endif /* CONFIG_NET_LOCAL_STREAM */
|
||||
|
||||
#ifdef CONFIG_NET_TCP
|
||||
#ifdef CONFIG_NET_LOCAL_STREAM
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#ifdef CONFIG_NET_6LOWPAN
|
||||
/* Try 6LoWPAN TCP packet send */
|
||||
|
||||
ret = psock_6lowpan_tcp_send(psock, buf, len);
|
||||
|
||||
#if defined(CONFIG_NETDEV_MULTINIC) && defined(NET_TCP_HAVE_STACK)
|
||||
if (ret < 0)
|
||||
{
|
||||
/* TCP/IP packet send */
|
||||
|
||||
ret = psock_tcp_send(psock, buf, len);
|
||||
}
|
||||
#endif /* CONFIG_NETDEV_MULTINIC && NET_TCP_HAVE_STACK */
|
||||
#elif defined(NET_TCP_HAVE_STACK)
|
||||
ret = psock_tcp_send(psock, buf, len);
|
||||
#else
|
||||
ret = -ENOSYS;
|
||||
#endif /* CONFIG_NET_6LOWPAN */
|
||||
}
|
||||
#endif /* CONFIG_NET_TCP */
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_NET_TCP || CONFIG_NET_LOCAL_STREAM */
|
||||
|
||||
#ifdef CONFIG_NET_UDP
|
||||
case SOCK_DGRAM:
|
||||
{
|
||||
#ifdef CONFIG_NET_LOCAL_DGRAM
|
||||
#ifdef CONFIG_NET_UDP
|
||||
if (psock->s_domain == PF_LOCAL)
|
||||
#endif
|
||||
{
|
||||
/* Local UDP packet send */
|
||||
#warning Missing logic
|
||||
ret = -ENOSYS;
|
||||
}
|
||||
#endif /* CONFIG_NET_LOCAL_DGRAM */
|
||||
|
||||
#ifdef CONFIG_NET_UDP
|
||||
#ifdef CONFIG_NET_LOCAL_DGRAM
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#if defined(CONFIG_NET_6LOWPAN)
|
||||
/* Try 6LoWPAN UDP packet send */
|
||||
|
||||
ret = psock_6lowpan_udp_send(psock, buf, len);
|
||||
|
||||
#if defined(CONFIG_NETDEV_MULTINIC) && defined(NET_UDP_HAVE_STACK)
|
||||
if (ret < 0)
|
||||
{
|
||||
/* UDP/IP packet send */
|
||||
|
||||
ret = psock_udp_send(psock, buf, len);
|
||||
}
|
||||
#endif /* CONFIG_NETDEV_MULTINIC && NET_UDP_HAVE_STACK */
|
||||
#elif defined(NET_UDP_HAVE_STACK)
|
||||
/* Only UDP/IP packet send */
|
||||
|
||||
ret = psock_udp_send(psock, buf, len);
|
||||
#else
|
||||
ret = -ENOSYS;
|
||||
#endif /* CONFIG_NET_6LOWPAN */
|
||||
}
|
||||
#endif /* CONFIG_NET_UDP */
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_NET_UDP */
|
||||
|
||||
#ifdef CONFIG_NET_USRSOCK
|
||||
case SOCK_USRSOCK_TYPE:
|
||||
{
|
||||
ret = usrsock_sendto(psock, buf, len, NULL, 0);
|
||||
}
|
||||
break;
|
||||
#endif /*CONFIG_NET_USRSOCK*/
|
||||
|
||||
default:
|
||||
{
|
||||
/* EDESTADDRREQ. Signifies that the socket is not connection-mode
|
||||
* and no peer address is set.
|
||||
*/
|
||||
|
||||
ret = -EDESTADDRREQ;
|
||||
}
|
||||
break;
|
||||
}
|
||||
DEBUGASSERT(psock->s_sockif != NULL && psock->s_sockif->si_send != NULL);
|
||||
ret = psock->s_sockif->si_send(psock, buf, len, flags);
|
||||
|
||||
leave_cancellation_point();
|
||||
if (ret < 0)
|
||||
{
|
||||
nerr("ERROR: socket si_send() (or usrsock_sendto()) failed: %d\n", ret);
|
||||
set_errno(-ret);
|
||||
ret = ERROR;
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
|
||||
|
@ -52,7 +53,6 @@
|
|||
#include "sixlowpan/sixlowpan.h"
|
||||
#include "local/local.h"
|
||||
#include "socket/socket.h"
|
||||
#include "usrsock/usrsock.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
|
@ -127,18 +127,16 @@ ssize_t psock_sendto(FAR struct socket *psock, FAR const void *buf,
|
|||
size_t len, int flags, FAR const struct sockaddr *to,
|
||||
socklen_t tolen)
|
||||
{
|
||||
socklen_t minlen;
|
||||
#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_LOCAL_DGRAM) || \
|
||||
defined(CONFIG_NET_USRSOCK)
|
||||
ssize_t nsent;
|
||||
#endif
|
||||
int errcode;
|
||||
|
||||
DEBUGASSERT(psock != NULL && buf != NULL);
|
||||
|
||||
/* If to is NULL or tolen is zero, then this function is same as send (for
|
||||
* connected socket types)
|
||||
*/
|
||||
|
||||
if (!to || !tolen)
|
||||
if (to == NULL || tolen <= 0)
|
||||
{
|
||||
#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_LOCAL_STREAM) || \
|
||||
defined(CONFIG_NET_USRSOCK)
|
||||
|
@ -150,57 +148,6 @@ ssize_t psock_sendto(FAR struct socket *psock, FAR const void *buf,
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET_USRSOCK
|
||||
if (psock->s_type == SOCK_USRSOCK_TYPE)
|
||||
{
|
||||
/* Perform the usrsock sendto operation */
|
||||
|
||||
nsent = usrsock_sendto(psock, buf, len, to, tolen);
|
||||
if (nsent < 0)
|
||||
{
|
||||
errcode = -nsent;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
return nsent;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Verify that a valid address has been provided */
|
||||
|
||||
switch (to->sa_family)
|
||||
{
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
case AF_INET:
|
||||
minlen = sizeof(struct sockaddr_in);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
case AF_INET6:
|
||||
minlen = sizeof(struct sockaddr_in6);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_LOCAL_DGRAM
|
||||
case AF_LOCAL:
|
||||
minlen = sizeof(sa_family_t);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
nerr("ERROR: Unrecognized address family: %d\n", to->sa_family);
|
||||
errcode = EAFNOSUPPORT;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (tolen < minlen)
|
||||
{
|
||||
nerr("ERROR: Invalid address length: %d < %d\n", tolen, minlen);
|
||||
errcode = EBADF;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* Verify that the psock corresponds to valid, allocated socket */
|
||||
|
||||
if (!psock || psock->s_crefs <= 0)
|
||||
|
@ -210,68 +157,21 @@ ssize_t psock_sendto(FAR struct socket *psock, FAR const void *buf,
|
|||
goto errout;
|
||||
}
|
||||
|
||||
/* If this is a connected socket, then return EISCONN */
|
||||
/* Let the address family's send() method handle the operation */
|
||||
|
||||
if (psock->s_type != SOCK_DGRAM)
|
||||
{
|
||||
nerr("ERROR: Connected socket\n");
|
||||
errcode = EISCONN;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_LOCAL_DGRAM)
|
||||
/* Now handle the sendto() operation according to the socket domain,
|
||||
* currently either IP or Unix domains.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_NET_LOCAL_DGRAM
|
||||
#ifdef CONFIG_NET_UDP
|
||||
if (psock->s_domain == PF_LOCAL)
|
||||
#endif
|
||||
{
|
||||
nsent = psock_local_sendto(psock, buf, len, flags, to, tolen);
|
||||
}
|
||||
#endif /* CONFIG_NET_LOCAL_DGRAM */
|
||||
|
||||
#ifdef CONFIG_NET_UDP
|
||||
#ifdef CONFIG_NET_LOCAL_DGRAM
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#if defined(CONFIG_NET_6LOWPAN)
|
||||
/* Try 6LoWPAN UDP packet sendto() */
|
||||
|
||||
nsent = psock_6lowpan_udp_sendto(psock, buf, len, flags, to, tolen);
|
||||
|
||||
#if defined(CONFIG_NETDEV_MULTINIC) && defined(NET_UDP_HAVE_STACK)
|
||||
if (nsent < 0)
|
||||
{
|
||||
/* UDP/IP packet sendto */
|
||||
|
||||
nsent = psock_udp_sendto(psock, buf, len, flags, to, tolen);
|
||||
}
|
||||
#endif /* CONFIG_NETDEV_MULTINIC && NET_UDP_HAVE_STACK */
|
||||
#elif defined(NET_UDP_HAVE_STACK)
|
||||
nsent = psock_udp_sendto(psock, buf, len, flags, to, tolen);
|
||||
#else
|
||||
nsent = -ENOSYS;
|
||||
#endif /* CONFIG_NET_6LOWPAN */
|
||||
}
|
||||
#endif /* CONFIG_NET_UDP */
|
||||
DEBUGASSERT(psock->s_sockif != NULL && psock->s_sockif->si_send != NULL);
|
||||
nsent = psock->s_sockif->si_send(psock, buf, len, flags);
|
||||
|
||||
/* Check if the domain-specific sendto() logic failed */
|
||||
|
||||
if (nsent < 0)
|
||||
{
|
||||
nerr("ERROR: UDP or Unix domain sendto() failed: %ld\n", (long)nsent);
|
||||
nerr("ERROR: Family-specific send failed: %ld\n", (long)nsent);
|
||||
errcode = -nsent;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
return nsent;
|
||||
#else
|
||||
errcode = ENOSYS;
|
||||
#endif /* CONFIG_NET_UDP || CONFIG_NET_LOCAL_DGRAM */
|
||||
|
||||
errout:
|
||||
set_errno(errcode);
|
||||
|
|
|
@ -38,167 +38,15 @@
|
|||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#ifdef CONFIG_NET
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/net/udp.h>
|
||||
|
||||
#include "socket/socket.h"
|
||||
#include "tcp/tcp.h"
|
||||
#include "udp/udp.h"
|
||||
#include "pkt/pkt.h"
|
||||
#include "local/local.h"
|
||||
#include "usrsock/usrsock.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: psock_tcp_alloc
|
||||
*
|
||||
* Description:
|
||||
* Allocate and attach a TCP connection structure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef NET_TCP_HAVE_STACK
|
||||
static int psock_tcp_alloc(FAR struct socket *psock)
|
||||
{
|
||||
/* Allocate the TCP connection structure */
|
||||
|
||||
FAR struct tcp_conn_s *conn = tcp_alloc(psock->s_domain);
|
||||
if (!conn)
|
||||
{
|
||||
/* Failed to reserve a connection structure */
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Set the reference count on the connection structure. This reference
|
||||
* count will be incremented only if the socket is dup'ed
|
||||
*/
|
||||
|
||||
DEBUGASSERT(conn->crefs == 0);
|
||||
conn->crefs = 1;
|
||||
|
||||
/* Save the pre-allocated connection in the socket structure */
|
||||
|
||||
psock->s_conn = conn;
|
||||
return OK;
|
||||
}
|
||||
#endif /* NET_TCP_HAVE_STACK */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: psock_udp_alloc
|
||||
*
|
||||
* Description:
|
||||
* Allocate and attach a UDP connection structure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef NET_UDP_HAVE_STACK
|
||||
static int psock_udp_alloc(FAR struct socket *psock)
|
||||
{
|
||||
/* Allocate the UDP connection structure */
|
||||
|
||||
FAR struct udp_conn_s *conn = udp_alloc(psock->s_domain);
|
||||
if (!conn)
|
||||
{
|
||||
/* Failed to reserve a connection structure */
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Set the reference count on the connection structure. This reference
|
||||
* count will be incremented only if the socket is dup'ed
|
||||
*/
|
||||
|
||||
DEBUGASSERT(conn->crefs == 0);
|
||||
conn->crefs = 1;
|
||||
|
||||
/* Save the pre-allocated connection in the socket structure */
|
||||
|
||||
psock->s_conn = conn;
|
||||
return OK;
|
||||
}
|
||||
#endif /* NET_UDP_HAVE_STACK */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: psock_pkt_alloc
|
||||
*
|
||||
* Description:
|
||||
* Allocate and attach a raw packet connection structure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET_PKT
|
||||
static int psock_pkt_alloc(FAR struct socket *psock)
|
||||
{
|
||||
/* Allocate the packet socket connection structure and save in the new
|
||||
* socket instance.
|
||||
*/
|
||||
|
||||
FAR struct pkt_conn_s *conn = pkt_alloc();
|
||||
if (!conn)
|
||||
{
|
||||
/* Failed to reserve a connection structure */
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Set the reference count on the connection structure. This reference
|
||||
* count will be incremented only if the socket is dup'ed
|
||||
*/
|
||||
|
||||
DEBUGASSERT(conn->crefs == 0);
|
||||
conn->crefs = 1;
|
||||
|
||||
/* Save the pre-allocated connection in the socket structure */
|
||||
|
||||
psock->s_conn = conn;
|
||||
return OK;
|
||||
}
|
||||
#endif /* CONFIG_NET_PKT */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: psock_local_alloc
|
||||
*
|
||||
* Description:
|
||||
* Allocate and attach a local, Unix domain connection structure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET_LOCAL
|
||||
static int psock_local_alloc(FAR struct socket *psock)
|
||||
{
|
||||
/* Allocate the local connection structure */
|
||||
|
||||
FAR struct local_conn_s *conn = local_alloc();
|
||||
if (!conn)
|
||||
{
|
||||
/* Failed to reserve a connection structure */
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Set the reference count on the connection structure. This reference
|
||||
* count will be incremented only if the socket is dup'ed
|
||||
*/
|
||||
|
||||
DEBUGASSERT(conn->lc_crefs == 0);
|
||||
conn->lc_crefs = 1;
|
||||
|
||||
/* Save the pre-allocated connection in the socket structure */
|
||||
|
||||
psock->s_conn = conn;
|
||||
return OK;
|
||||
}
|
||||
#endif /* CONFIG_NET_LOCAL */
|
||||
#ifdef CONFIG_NET
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
|
@ -244,180 +92,11 @@ static int psock_local_alloc(FAR struct socket *psock)
|
|||
|
||||
int psock_socket(int domain, int type, int protocol, FAR struct socket *psock)
|
||||
{
|
||||
#ifdef CONFIG_NET_LOCAL
|
||||
bool ipdomain = false;
|
||||
#endif
|
||||
bool dgramok = false;
|
||||
int ret;
|
||||
FAR const struct sock_intf_s *sockif = NULL;
|
||||
int errcode;
|
||||
|
||||
#ifdef CONFIG_NET_USRSOCK
|
||||
switch (domain)
|
||||
{
|
||||
default:
|
||||
break;
|
||||
|
||||
case PF_INET:
|
||||
case PF_INET6:
|
||||
{
|
||||
#ifndef CONFIG_NET_USRSOCK_UDP
|
||||
if (type == SOCK_DGRAM)
|
||||
break;
|
||||
#endif
|
||||
#ifndef CONFIG_NET_USRSOCK_TCP
|
||||
if (type == SOCK_STREAM)
|
||||
break;
|
||||
#endif
|
||||
psock->s_type = 0;
|
||||
psock->s_conn = NULL;
|
||||
|
||||
ret = usrsock_socket(domain, type, protocol, psock);
|
||||
if (ret >= 0)
|
||||
{
|
||||
/* Successfully handled and opened by usrsock daemon. */
|
||||
|
||||
return OK;
|
||||
}
|
||||
else if (ret == -ENETDOWN)
|
||||
{
|
||||
/* Net down means that usrsock daemon is not running.
|
||||
* Attempt to open socket with kernel networking stack. */
|
||||
}
|
||||
else
|
||||
{
|
||||
errcode = -ret;
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_NET_USRSOCK */
|
||||
|
||||
/* Only PF_INET, PF_INET6 or PF_PACKET domains supported */
|
||||
|
||||
switch (domain)
|
||||
{
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
case PF_INET:
|
||||
#ifdef CONFIG_NET_LOCAL
|
||||
ipdomain = true;
|
||||
#endif
|
||||
dgramok = true;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
case PF_INET6:
|
||||
#ifdef CONFIG_NET_LOCAL
|
||||
ipdomain = true;
|
||||
#endif
|
||||
dgramok = true;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_LOCAL
|
||||
case PF_LOCAL:
|
||||
dgramok = true;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_PKT
|
||||
case PF_PACKET:
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
errcode = EAFNOSUPPORT;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_NET_LOCAL) && !defined(CONFIG_NET_LOCAL_STREAM) && !defined(CONFIG_NET_LOCAL_DGRAM)
|
||||
UNUSED(ipdomain);
|
||||
#endif
|
||||
|
||||
/* Only SOCK_STREAM, SOCK_DGRAM and possible SOCK_RAW are supported */
|
||||
|
||||
switch (type)
|
||||
{
|
||||
#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_LOCAL_STREAM)
|
||||
case SOCK_STREAM:
|
||||
#ifdef CONFIG_NET_TCP
|
||||
#ifdef CONFIG_NET_LOCAL_STREAM
|
||||
if (ipdomain)
|
||||
#endif
|
||||
{
|
||||
if ((protocol != 0 && protocol != IPPROTO_TCP) || !dgramok)
|
||||
{
|
||||
errcode = EPROTONOSUPPORT;
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_NET_TCP */
|
||||
|
||||
#ifdef CONFIG_NET_LOCAL_STREAM
|
||||
#ifdef CONFIG_NET_TCP
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (protocol != 0 || !dgramok)
|
||||
{
|
||||
errcode = EPROTONOSUPPORT;
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_NET_LOCAL_STREAM */
|
||||
|
||||
break;
|
||||
#endif /* CONFIG_NET_TCP || CONFIG_NET_LOCAL_STREAM */
|
||||
|
||||
#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_LOCAL_DGRAM)
|
||||
case SOCK_DGRAM:
|
||||
#ifdef CONFIG_NET_UDP
|
||||
#ifdef CONFIG_NET_LOCAL_DGRAM
|
||||
if (ipdomain)
|
||||
#endif
|
||||
{
|
||||
if ((protocol != 0 && protocol != IPPROTO_UDP) || !dgramok)
|
||||
{
|
||||
errcode = EPROTONOSUPPORT;
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_NET_UDP */
|
||||
|
||||
#ifdef CONFIG_NET_LOCAL_DGRAM
|
||||
#ifdef CONFIG_NET_UDP
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (protocol != 0 || !dgramok)
|
||||
{
|
||||
errcode = EPROTONOSUPPORT;
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_NET_LOCAL_DGRAM */
|
||||
|
||||
break;
|
||||
#endif /* CONFIG_NET_UDP || CONFIG_NET_LOCAL_DGRAM */
|
||||
|
||||
#ifdef CONFIG_NET_PKT
|
||||
case SOCK_RAW:
|
||||
if (dgramok)
|
||||
{
|
||||
errcode = EPROTONOSUPPORT;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
errcode = EPROTONOSUPPORT;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* Everything looks good. Initialize the socket structure */
|
||||
/* Save the protocol type */
|
||||
int ret;
|
||||
|
||||
/* Initialize the socket structure */
|
||||
|
||||
psock->s_domain = domain;
|
||||
psock->s_type = type;
|
||||
|
@ -426,115 +105,29 @@ int psock_socket(int domain, int type, int protocol, FAR struct socket *psock)
|
|||
psock->s_sndcb = NULL;
|
||||
#endif
|
||||
|
||||
/* Allocate the appropriate connection structure. This reserves the
|
||||
* the connection structure is is unallocated at this point. It will
|
||||
* not actually be initialized until the socket is connected.
|
||||
/* Get the socket interface */
|
||||
|
||||
sockif = net_sockif(domain);
|
||||
if (sockif == NULL)
|
||||
{
|
||||
nerr("ERROR: socket address family unsupported: %d\n", domain);
|
||||
errcode = EAFNOSUPPORT;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* The remaining of the socket initialization depends on the address
|
||||
* family.
|
||||
*/
|
||||
|
||||
errcode = ENOMEM; /* Assume failure to allocate connection instance */
|
||||
switch (type)
|
||||
DEBUGASSERT(sockif->si_setup != NULL);
|
||||
psock->s_sockif = sockif;
|
||||
|
||||
ret = sockif->si_setup(psock, protocol);
|
||||
if (ret < 0)
|
||||
{
|
||||
#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_LOCAL_STREAM)
|
||||
case SOCK_STREAM:
|
||||
{
|
||||
#ifdef CONFIG_NET_TCP
|
||||
#ifdef CONFIG_NET_LOCAL_STREAM
|
||||
if (ipdomain)
|
||||
#endif
|
||||
{
|
||||
#ifdef NET_TCP_HAVE_STACK
|
||||
/* Allocate and attach the TCP connection structure */
|
||||
|
||||
ret = psock_tcp_alloc(psock);
|
||||
#else
|
||||
ret = -ENETDOWN;
|
||||
#endif
|
||||
}
|
||||
#endif /* CONFIG_NET_TCP */
|
||||
|
||||
#ifdef CONFIG_NET_LOCAL_STREAM
|
||||
#ifdef CONFIG_NET_TCP
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* Allocate and attach the local connection structure */
|
||||
|
||||
ret = psock_local_alloc(psock);
|
||||
}
|
||||
#endif /* CONFIG_NET_LOCAL_STREAM */
|
||||
|
||||
/* Check for failures to allocate the connection structure. */
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
/* Failed to reserve a connection structure */
|
||||
|
||||
errcode = -ret;
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_LOCAL_DGRAM)
|
||||
case SOCK_DGRAM:
|
||||
{
|
||||
#ifdef CONFIG_NET_UDP
|
||||
#ifdef CONFIG_NET_LOCAL_DGRAM
|
||||
if (ipdomain)
|
||||
#endif
|
||||
{
|
||||
#ifdef NET_UDP_HAVE_STACK
|
||||
/* Allocate and attach the UDP connection structure */
|
||||
|
||||
ret = psock_udp_alloc(psock);
|
||||
#else
|
||||
ret = -ENETDOWN;
|
||||
#endif
|
||||
}
|
||||
#endif /* CONFIG_NET_UDP */
|
||||
|
||||
#ifdef CONFIG_NET_LOCAL_DGRAM
|
||||
#ifdef CONFIG_NET_UDP
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* Allocate and attach the local connection structure */
|
||||
|
||||
ret = psock_local_alloc(psock);
|
||||
}
|
||||
#endif /* CONFIG_NET_LOCAL_DGRAM */
|
||||
|
||||
/* Check for failures to allocate the connection structure. */
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
/* Failed to reserve a connection structure */
|
||||
|
||||
errcode = -ret;
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_PKT
|
||||
case SOCK_RAW:
|
||||
{
|
||||
ret = psock_pkt_alloc(psock);
|
||||
if (ret < 0)
|
||||
{
|
||||
/* Failed to reserve a connection structure */
|
||||
|
||||
errcode = -ret;
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
break;
|
||||
nerr("ERROR: socket si_setup() failed: %d\n", ret);
|
||||
errcode = -ret;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
return OK;
|
||||
|
@ -592,6 +185,7 @@ int socket(int domain, int type, int protocol)
|
|||
sockfd = sockfd_allocate(0);
|
||||
if (sockfd < 0)
|
||||
{
|
||||
nerr("ERROR: Failed to allodate a socket descriptor\n");
|
||||
set_errno(ENFILE);
|
||||
return ERROR;
|
||||
}
|
||||
|
@ -610,8 +204,9 @@ int socket(int domain, int type, int protocol)
|
|||
ret = psock_socket(domain, type, protocol, psock);
|
||||
if (ret < 0)
|
||||
{
|
||||
/* Error already set by psock_socket() */
|
||||
/* errno already set by psock_socket() */
|
||||
|
||||
nerr("ERROR: psock_socket() failed: %d\n", ret);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
|
|
|
@ -149,6 +149,10 @@ extern "C"
|
|||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NET_IPv4) || defined(CONFIG_NET_IPv6)
|
||||
EXTERN const struct sock_intf_s g_inet_sockif;
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
@ -223,6 +227,23 @@ void sockfd_release(int sockfd);
|
|||
|
||||
FAR struct socket *sockfd_socket(int sockfd);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: net_sockif
|
||||
*
|
||||
* Description:
|
||||
* Return the socket interface associated with this address family.
|
||||
*
|
||||
* Parameters:
|
||||
* family - Address family
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, a non-NULL instance of struct sock_intf_s is returned. NULL
|
||||
* is returned only if the address family is not supported.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR const struct sock_intf_s *net_sockif(sa_family_t family);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: net_startmonitor
|
||||
*
|
||||
|
@ -410,13 +431,99 @@ int net_timeo(systime_t start_time, socktimeo_t timeo);
|
|||
* In this case the process will also receive a SIGPIPE unless
|
||||
* MSG_NOSIGNAL is set.
|
||||
*
|
||||
* Assumptions:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len,
|
||||
int flags);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: inet_connect
|
||||
*
|
||||
* Description:
|
||||
* inet_connect() connects the local socket referred to by the structure
|
||||
* 'psock' to the address specified by 'addr'. The addrlen argument
|
||||
* specifies the size of 'addr'. The format of the address in 'addr' is
|
||||
* determined by the address space of the socket 'psock'.
|
||||
*
|
||||
* If the socket 'psock' is of type SOCK_DGRAM then 'addr' is the address
|
||||
* to which datagrams are sent by default, and the only address from which
|
||||
* datagrams are received. If the socket is of type SOCK_STREAM or
|
||||
* SOCK_SEQPACKET, this call attempts to make a connection to the socket
|
||||
* that is bound to the address specified by 'addr'.
|
||||
*
|
||||
* Generally, connection-based protocol sockets may successfully
|
||||
* inet_connect() only once; connectionless protocol sockets may use
|
||||
* inet_connect() multiple times to change their association.
|
||||
* Connectionless sockets may dissolve the association by connecting to
|
||||
* an address with the sa_family member of sockaddr set to AF_UNSPEC.
|
||||
*
|
||||
* Parameters:
|
||||
* psock Pointer to a socket structure initialized by psock_socket()
|
||||
* addr Server address (form depends on type of socket)
|
||||
* addrlen Length of actual 'addr'
|
||||
*
|
||||
* Returned Value:
|
||||
* 0 on success; a negated errno value on failue. See connect() for the
|
||||
* list of appropriate errno values to be returned.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int inet_connect(FAR struct socket *psock, FAR const struct sockaddr *addr,
|
||||
socklen_t addrlen);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: inet_recvfrom
|
||||
*
|
||||
* Description:
|
||||
* Implements the socket recvfrom interface for the case of the AF_INET
|
||||
* and AF_INET6 address families. inet_recvfrom() receives messages from
|
||||
* a socket, and may be used to receive data on a socket whether or not it
|
||||
* is connection-oriented.
|
||||
*
|
||||
* If 'from' is not NULL, and the underlying protocol provides the source
|
||||
* address, this source address is filled in. The argument 'fromlen' is
|
||||
* initialized to the size of the buffer associated with from, and
|
||||
* modified on return to indicate the actual size of the address stored
|
||||
* there.
|
||||
*
|
||||
* Parameters:
|
||||
* psock A pointer to a NuttX-specific, internal socket structure
|
||||
* buf Buffer to receive data
|
||||
* len Length of buffer
|
||||
* flags Receive flags
|
||||
* from Address of source (may be NULL)
|
||||
* fromlen The length of the address structure
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, returns the number of characters received. If no data is
|
||||
* available to be received and the peer has performed an orderly shutdown,
|
||||
* recv() will return 0. Otherwise, on errors, a negated errno value is
|
||||
* returned (see recvfrom() for the list of appropriate error values).
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
ssize_t inet_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
|
||||
int flags, FAR struct sockaddr *from,
|
||||
FAR socklen_t *fromlen);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: inet_close
|
||||
*
|
||||
* Description:
|
||||
* Performs the close operation on an AF_INET or AF_INET6 socket instance
|
||||
*
|
||||
* Parameters:
|
||||
* psock Socket instance
|
||||
*
|
||||
* Returned Value:
|
||||
* 0 on success; -1 on error with errno set appropriately.
|
||||
*
|
||||
* Assumptions:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int inet_close(FAR struct socket *psock);
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
|
|
|
@ -874,7 +874,7 @@ static void enable_feature(const char *destconfig, const char *varname)
|
|||
int ret;
|
||||
|
||||
snprintf(g_buffer, BUFFER_SIZE,
|
||||
"kconfig-tweak --file %s --disable %s",
|
||||
"kconfig-tweak --file %s --enable %s",
|
||||
destconfig, varname);
|
||||
|
||||
ret = system(g_buffer);
|
||||
|
|
Loading…
Reference in a new issue