diff options
55 files changed, 4833 insertions, 449 deletions
diff --git a/apps/ChangeLog.txt b/apps/ChangeLog.txt index 9be1899a3..4f8ed9288 100644 --- a/apps/ChangeLog.txt +++ b/apps/ChangeLog.txt @@ -1199,3 +1199,6 @@ * apps/interpreters/micropython: Add math library defines for nan(), copysign(), and trunc() functions. From Brennan Ashton (2015-01-26). + * apps/examples/ustreadm: Add a simple test of Unix domain sockets + (2014-01-27). + diff --git a/apps/examples/Kconfig b/apps/examples/Kconfig index 6714e6351..329077071 100644 --- a/apps/examples/Kconfig +++ b/apps/examples/Kconfig @@ -75,6 +75,7 @@ source "$APPSDIR/examples/discover/Kconfig" source "$APPSDIR/examples/webserver/Kconfig" source "$APPSDIR/examples/usbserial/Kconfig" source "$APPSDIR/examples/usbterm/Kconfig" +source "$APPSDIR/examples/ustream/Kconfig" source "$APPSDIR/examples/watchdog/Kconfig" source "$APPSDIR/examples/wget/Kconfig" source "$APPSDIR/examples/wgetjson/Kconfig" diff --git a/apps/examples/Make.defs b/apps/examples/Make.defs index 2c23a68e6..520ba8cc0 100644 --- a/apps/examples/Make.defs +++ b/apps/examples/Make.defs @@ -318,6 +318,10 @@ ifeq ($(CONFIG_EXAMPLES_USBTERM),y) CONFIGURED_APPS += examples/usbterm endif +ifeq ($(CONFIG_EXAMPLES_USTREAM),y) +CONFIGURED_APPS += examples/ustream +endif + ifeq ($(CONFIG_EXAMPLES_WATCHDOG),y) CONFIGURED_APPS += examples/watchdog endif diff --git a/apps/examples/Makefile b/apps/examples/Makefile index 8d39c1a5f..ddcea687c 100644 --- a/apps/examples/Makefile +++ b/apps/examples/Makefile @@ -45,7 +45,7 @@ SUBDIRS += nxffs nxflat nxhello nximage nxlines nxtext ostest pashello pipe SUBDIRS += poll posix_spawn pwm qencoder random relays rgmp romfs sendmail SUBDIRS += serialblaster serloop serialrx slcd smart smart_test tcpecho SUBDIRS += telnetd thttpd tiff timer touchscreen udp usbserial usbterm -SUBDIRS += watchdog webserver wget wgetjson xmlrpc +SUBDIRS += ustream watchdog webserver wget wgetjson xmlrpc # Sub-directories that might need context setup. Directories may need # context setup for a variety of reasons, but the most common is because @@ -59,7 +59,7 @@ CNTXTDIRS += djoystick flash_test ftpd hello helloxx i2schar json keypadtest CNTXTDIRS += ltdc modbus lcdrw mtdpart mtdrwb netpkt nettest nx nxhello CNTXTDIRS += nximage nxlines nxtext nrf24l01_term ostest random relays CNTXTDIRS += qencoder serialblasters lcd serialrx smart_test tcpecho telnetd -CNTXTDIRS += tiff timer touchscreen usbterm watchdog wgetjson +CNTXTDIRS += tiff timer touchscreen usbterm ustream watchdog wgetjson endif all: nothing diff --git a/apps/examples/README.txt b/apps/examples/README.txt index 13586419b..c9436df91 100644 --- a/apps/examples/README.txt +++ b/apps/examples/README.txt @@ -1976,6 +1976,20 @@ examples/usbterm Prolifics emulation (not defined) and the CDC serial implementation (when defined). CONFIG_USBDEV_TRACE_INITIALIDSET. +examples/ustream +^^^^^^^^^^^^^^^^ + + This is the same test as examples/nettest, but using Unix domain + sockets. + + Dependencies: + CONFIG_NET_LOCAL - Depends on support for Unix domain sockets + + Configuration: + CONFIG_EXAMPLES_USTREAM - Enables the Unix domain socket example. + CONFIG_EXAMPLES_USTREAM_ADDR - Specifics the Unix domain address. + Default "/var/fifo/fifo". + examples/watchdog ^^^^^^^^^^^^^^^^^ diff --git a/apps/examples/ustream/.gitignore b/apps/examples/ustream/.gitignore new file mode 100644 index 000000000..52ae9aa90 --- /dev/null +++ b/apps/examples/ustream/.gitignore @@ -0,0 +1,14 @@ +/Make.dep +/.depend +/.built +/*.asm +/*.obj +/*.rel +/*.lst +/*.sym +/*.adb +/*.lib +/*.src +/*.hobj +/*.exe +/*.dSYM diff --git a/apps/examples/ustream/Kconfig b/apps/examples/ustream/Kconfig new file mode 100644 index 000000000..5731a7c5a --- /dev/null +++ b/apps/examples/ustream/Kconfig @@ -0,0 +1,19 @@ +# +# For a description of the syntax of this configuration file, +# see misc/tools/kconfig-language.txt. +# + +config EXAMPLES_USTREAM + bool "Unix domain socket example" + default n + depends on NET_LOCAL + ---help--- + Enable the Unix domain SOCK_STREAM test example + +if EXAMPLES_USTREAM + +config EXAMPLES_USTREAM_ADDR + string "Unix domain address" + default "/var/fifo/fifo" + +endif # EXAMPLES_USTREAM diff --git a/apps/examples/ustream/Makefile b/apps/examples/ustream/Makefile new file mode 100644 index 000000000..b5570cbe3 --- /dev/null +++ b/apps/examples/ustream/Makefile @@ -0,0 +1,173 @@ +############################################################################ +# examples/ustream/Makefile +# +# Copyright (C) 2015 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. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# Basic Unix domain networking test + +SERVER_ASRCS = +SERVER_AOBJS = $(SERVER_ASRCS:.S=$(OBJEXT)) + +SERVER_CSRCS = +SERVER_COBJS = $(SERVER_CSRCS:.c=$(OBJEXT)) + +SERVER_MAINSRC = ustream_server.c +SERVER_MAINOBJ = $(SERVER_MAINSRC:.c=$(OBJEXT)) + +SERVER_SRCS = $(SERVER_ASRCS) $(SERVER_CSRCS) $(SERVER_MAINSRC) +SERVER_OBJS = $(SERVER_AOBJS) $(SERVER_COBJS) + +SERVER_PROGNAME = server$(EXEEXT) + +SERVER_APPNAME = server +SERVER_PRIORITY = SCHED_PRIORITY_DEFAULT +SERVER_STACKSIZE = 2048 + +CLIENT_ASRCS = +CLIENT_AOBJS = $(CLIENT_ASRCS:.S=$(OBJEXT)) + +CLIENT_CSRCS = +CLIENT_COBJS = $(CLIENT_CSRCS:.c=$(OBJEXT)) + +CLIENT_MAINSRC = ustream_client.c +CLIENT_MAINOBJ = $(CLIENT_MAINSRC:.c=$(OBJEXT)) + +CLIENT_SRCS = $(CLIENT_ASRCS) $(CLIENT_CSRCS) $(CLIENT_MAINSRC) +CLIENT_OBJS = $(CLIENT_AOBJS) $(CLIENT_COBJS) + +CLIENT_PROGNAME = server$(EXEEXT) + +CLIENT_APPNAME = client +CLIENT_PRIORITY = SCHED_PRIORITY_DEFAULT +CLIENT_STACKSIZE = 2048 + +AOBJS = $(CLIENT_AOBJS) $(SERVER_AOBJS) +COBJS = $(CLIENT_COBJS) $(CLIENT_MAINOBJ) $(SERVER_COBJS) $(SERVER_MAINOBJ) + +SRCS = $(CLIENT_SRCS) $(SERVER_SRCS) +OBJS = $(AOBJS) $(COBJS) + +ifneq ($(CONFIG_BUILD_KERNEL),y) + SERVER_OBJS += $(SERVER_MAINOBJ) + CLIENT_OBJS += $(CLIENT_MAINOBJ) +endif + +ifeq ($(CONFIG_WINDOWS_NATIVE),y) + USTREAM_BIN = ..\..\libapps$(LIBEXT) +else +ifeq ($(WINTOOL),y) + USTREAM_BIN = ..\\..\\libapps$(LIBEXT) +else + USTREAM_BIN = ../../libapps$(LIBEXT) +endif +endif + +ifeq ($(WINTOOL),y) + INSTALL_DIR = "${shell cygpath -w $(BIN_DIR)}" +else + INSTALL_DIR = $(BIN_DIR) +endif + +# Common build + +VPATH = + +all: .built +.PHONY: clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + $(call ARCHIVE, $(USTREAM_BIN), $(OBJS)) + $(Q) touch .built + +ifeq ($(CONFIG_BUILD_KERNEL),y) + +$(BIN_DIR)$(DELIM)$(CLIENT_PROGNAME): $(CLIENT_OBJS) + @echo "LD: $(CLIENT_PROGNAME)" + $(Q) $(LD) $(LDELFFLAGS) $(LDLIBPATH) -o $(INSTALL_DIR)$(DELIM)$(CLIENT_PROGNAME) $(ARCHCRT0OBJ) $(CLIENT_MAINOBJ) $(LDLIBS) + $(Q) $(NM) -u $(INSTALL_DIR)$(DELIM)$(CLIENT_PROGNAME) + +$(BIN_DIR)$(DELIM)$(SERVER_PROGNAME): $(OBJS) $(SERVER_MAINOBJ) + @echo "LD: $(SERVER_PROGNAME)" + $(Q) $(LD) $(LDELFFLAGS) $(LDLIBPATH) -o $(INSTALL_DIR)$(DELIM)$(SERVER_PROGNAME) $(ARCHCRT0OBJ) $(SERVER_MAINOBJ) $(LDLIBS) + $(Q) $(NM) -u $(INSTALL_DIR)$(DELIM)$(SERVER_PROGNAME) + +install: $(BIN_DIR)$(DELIM)$(CLIENT_PROGNAME) $(BIN_DIR)$(DELIM)$(SERVER_PROGNAME) + +else +install: + +endif + +ifeq ($(CONFIG_NSH_BUILTIN_APPS),y) + +$(BUILTIN_REGISTRY)$(DELIM)$(CLIENT_APPNAME)_main.bdat: $(DEPCONFIG) Makefile + $(call REGISTER,$(CLIENT_APPNAME),$(CLIENT_PRIORITY),$(CLIENT_STACKSIZE),$(CLIENT_APPNAME)_main) + +$(BUILTIN_REGISTRY)$(DELIM)$(SERVER_APPNAME)_main.bdat: $(DEPCONFIG) Makefile + $(call REGISTER,$(SERVER_APPNAME),$(SERVER_PRIORITY),$(SERVER_STACKSIZE),$(SERVER_APPNAME)_main) + +context: $(BUILTIN_REGISTRY)$(DELIM)$(CLIENT_APPNAME)_main.bdat $(BUILTIN_REGISTRY)$(DELIM)$(SERVER_APPNAME)_main.bdat + +else + +context: + +endif + +.depend: Makefile $(SERVER_SRCS) + @$(MKDEP) $(ROOTDEPPATH) "$(CC)" -- $(CFLAGS) -- $(SERVER_SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + $(call DELFILE, .built) + $(call DELFILE, *.dSYM) + $(call CLEAN) + +distclean: clean + $(call DELFILE, Make.dep) + $(call DELFILE, .depend) + +-include Make.dep + diff --git a/apps/examples/ustream/ustream.h b/apps/examples/ustream/ustream.h new file mode 100644 index 000000000..2d4533c05 --- /dev/null +++ b/apps/examples/ustream/ustream.h @@ -0,0 +1,53 @@ +/**************************************************************************** + * examples/ustream/ustream.h + * + * Copyright (C) 2015 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 __APPS_EXAMPLES_USTREAM_H +#define __APPS_EXAMPLES_USTREAM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define SENDSIZE 4096 + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#endif /* __APPS_EXAMPLES_USTREAM_H */ diff --git a/apps/examples/ustream/ustream_client.c b/apps/examples/ustream/ustream_client.c new file mode 100644 index 000000000..797a5a18c --- /dev/null +++ b/apps/examples/ustream/ustream_client.c @@ -0,0 +1,191 @@ +/**************************************************************************** + * examples/ustream/ustream_client.c + * + * Copyright (C) 2015 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 Gregory Nutt 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/socket.h> +#include <sys/un.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include "ustream.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#ifdef CONFIG_BUILD_KERNEL +int main(int argc, FAR char *argv[]) +#else +int client_main(int argc, char *argv[]) +#endif +{ + struct sockaddr_un myaddr; + socklen_t addrlen; + FAR char *outbuf; + FAR char *inbuf; + int sockfd; + int nbytessent; + int nbytesrecvd; + int totalbytesrecvd; + int ch; + int ret; + int i; + + /* Allocate buffers */ + + outbuf = (char*)malloc(SENDSIZE); + inbuf = (char*)malloc(SENDSIZE); + if (!outbuf || !inbuf) + { + printf("client: failed to allocate buffers\n"); + exit(1); + } + + /* Create a new Unix domain socket */ + + sockfd = socket(PF_LOCAL, SOCK_STREAM, 0); + if (sockfd < 0) + { + printf("client socket failure %d\n", errno); + goto errout_with_buffers; + } + + /* Connect the socket to the server */ + + addrlen = strlen(CONFIG_EXAMPLES_USTREAM_ADDR); + if (addrlen > UNIX_PATH_MAX - 1) + { + addrlen = UNIX_PATH_MAX - 1; + } + + myaddr.sun_family = AF_LOCAL; + strncpy(myaddr.sun_path, CONFIG_EXAMPLES_USTREAM_ADDR, addrlen); + myaddr.sun_path[addrlen] = '\0'; + + printf("client: Connecting...\n"); + addrlen += sizeof(sa_family_t) + 1; + ret = connect( sockfd, (struct sockaddr *)&myaddr, addrlen); + if (ret < 0) + { + printf("client: connect failure: %d\n", errno); + goto errout_with_socket; + } + + printf("client: Connected\n"); + + /* Initialize the buffer */ + + ch = 0x20; + for (i = 0; i < SENDSIZE; i++ ) + { + outbuf[i] = ch; + if (++ch > 0x7e) + { + ch = 0x20; + } + } + + /* Then send and receive one message */ + + printf("client: Sending %d bytes\n", SENDSIZE); + nbytessent = send(sockfd, outbuf, SENDSIZE, 0); + printf("client: Sent %d bytes\n", nbytessent); + + if (nbytessent < 0) + { + printf("client: send failed: %d\n", errno); + goto errout_with_socket; + } + else if (nbytessent != SENDSIZE) + { + printf("client: Bad send length: %d Expected: %d\n", nbytessent, SENDSIZE); + goto errout_with_socket; + } + + totalbytesrecvd = 0; + do + { + printf("client: Receiving...\n"); + nbytesrecvd = recv(sockfd, &inbuf[totalbytesrecvd], SENDSIZE - totalbytesrecvd, 0); + + if (nbytesrecvd < 0) + { + printf("client: recv failed: %d\n", errno); + goto errout_with_socket; + } + else if (nbytesrecvd == 0) + { + printf("client: The server closed the connection\n"); + goto errout_with_socket; + } + + totalbytesrecvd += nbytesrecvd; + printf("client: Received %d of %d bytes\n", totalbytesrecvd, SENDSIZE); + } + while (totalbytesrecvd < SENDSIZE); + + if (totalbytesrecvd != SENDSIZE) + { + printf("client: Bad recv length: %d Expected: %d\n", totalbytesrecvd, SENDSIZE); + goto errout_with_socket; + } + else if (memcmp(inbuf, outbuf, SENDSIZE) != 0) + { + printf("client: Received buffer does not match sent buffer\n"); + goto errout_with_socket; + } + + close(sockfd); + free(outbuf); + free(inbuf); + return 0; + +errout_with_socket: + close(sockfd); + +errout_with_buffers: + free(outbuf); + free(inbuf); + return 1; +} diff --git a/apps/examples/ustream/ustream_server.c b/apps/examples/ustream/ustream_server.c new file mode 100644 index 000000000..4432019a4 --- /dev/null +++ b/apps/examples/ustream/ustream_server.c @@ -0,0 +1,212 @@ +/**************************************************************************** + * examples/ustream/ustream_server.c + * + * Copyright (C) 2015 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 Gregory Nutt 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 <sys/un.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> + +#include "ustream.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#ifdef CONFIG_BUILD_KERNEL +int main(int argc, FAR char *argv[]) +#else +int server_main(int argc, char *argv[]) +#endif +{ + struct sockaddr_un myaddr; + socklen_t addrlen; + FAR char *buffer; + int listensd; + int acceptsd; + int nbytesread; + int totalbytesread; + int nbytessent; + int ch; + int ret; + int i; + + /* Allocate a BIG buffer */ + + buffer = (char*)malloc(2*SENDSIZE); + if (!buffer) + { + printf("server: failed to allocate buffer\n"); + exit(1); + } + + /* Create a new Unix domain socket */ + + listensd = socket(PF_LOCAL, SOCK_STREAM, 0); + if (listensd < 0) + { + printf("server: socket failure: %d\n", errno); + goto errout_with_buffer; + } + + /* Bind the socket to a local address */ + + addrlen = strlen(CONFIG_EXAMPLES_USTREAM_ADDR); + if (addrlen > UNIX_PATH_MAX - 1) + { + addrlen = UNIX_PATH_MAX - 1; + } + + myaddr.sun_family = AF_LOCAL; + strncpy(myaddr.sun_path, CONFIG_EXAMPLES_USTREAM_ADDR, addrlen); + myaddr.sun_path[addrlen] = '\0'; + + addrlen += sizeof(sa_family_t) + 1; + ret = bind(listensd, (struct sockaddr*)&myaddr, addrlen); + if (ret < 0) + { + printf("server: bind failure: %d\n", errno); + goto errout_with_listensd; + } + + /* Listen for connections on the bound socket */ + + if (listen(listensd, 5) < 0) + { + printf("server: listen failure %d\n", errno); + goto errout_with_listensd; + } + + /* Accept only one connection */ + + printf("server: Accepting connections on %s\n", CONFIG_EXAMPLES_USTREAM_ADDR); + acceptsd = accept(listensd, (struct sockaddr*)&myaddr, &addrlen); + if (acceptsd < 0) + { + printf("server: accept failure: %d\n", errno); + goto errout_with_listensd; + } + + printf("server: Connection accepted -- receiving\n"); + + /* Receive canned message */ + + totalbytesread = 0; + while (totalbytesread < SENDSIZE) + { + printf("server: Reading...\n"); + nbytesread = recv(acceptsd, &buffer[totalbytesread], 2*SENDSIZE - totalbytesread, 0); + if (nbytesread < 0) + { + printf("server: recv failed: %d\n", errno); + goto errout_with_acceptsd; + } + else if (nbytesread == 0) + { + printf("server: The client broke the connection\n"); + goto errout_with_acceptsd; + } + + totalbytesread += nbytesread; + printf("server: Received %d of %d bytes\n", totalbytesread, SENDSIZE); + } + + /* Verify the message */ + + if (totalbytesread != SENDSIZE) + { + printf("server: Received %d / Expected %d bytes\n", totalbytesread, SENDSIZE); + goto errout_with_acceptsd; + } + + ch = 0x20; + for (i = 0; i < SENDSIZE; i++ ) + { + if (buffer[i] != ch) + { + printf("server: Byte %d is %02x / Expected %02x\n", i, buffer[i], ch); + goto errout_with_acceptsd; + } + + if (++ch > 0x7e) + { + ch = 0x20; + } + } + + /* Then send the same data back to the client */ + + printf("server: Sending %d bytes\n", totalbytesread); + nbytessent = send(acceptsd, buffer, totalbytesread, 0); + if (nbytessent <= 0) + { + printf("server: send failed: %d\n", errno); + goto errout_with_acceptsd; + } + + printf("server: Sent %d bytes\n", nbytessent); + + /* If this platform only does abortive disconnects, then wait a bit to get the + * client side a change to receive the data. + */ + + printf("server: Wait before closing\n"); + sleep(60); + + close(listensd); + close(acceptsd); + free(buffer); + return 0; + +errout_with_acceptsd: + close(acceptsd); + +errout_with_listensd: + close(listensd); + +errout_with_buffer: + free(buffer); + return 1; +} diff --git a/apps/nshlib/nsh.h b/apps/nshlib/nsh.h index 1bd41f319..eccf5c23d 100644 --- a/apps/nshlib/nsh.h +++ b/apps/nshlib/nsh.h @@ -154,6 +154,22 @@ # define CONFIG_NSH_NETINIT_THREAD_PRIORITY 100 #endif +/* Some networking commands do not make sense unless there is a network + * device. There might not be a network device if, for example, only Unix + * domain sockets were enable. + */ + +#if !defined(CONFIG_NET_ETHERNET) && !defined(CONFIG_NET_SLIP) + /* No link layer protocol is a good indication that there is no network + * device. + */ + +# undef CONFIG_NSH_DISABLE_IFUPDOWN +# undef CONFIG_NSH_DISABLE_IFCONFIG +# define CONFIG_NSH_DISABLE_IFUPDOWN 1 +# define CONFIG_NSH_DISABLE_IFCONFIG 1 +#endif + /* Telnetd requires networking support */ #ifndef CONFIG_NET diff --git a/apps/nshlib/nsh_netinit.c b/apps/nshlib/nsh_netinit.c index ed42bb9ba..d2ea3520f 100644 --- a/apps/nshlib/nsh_netinit.c +++ b/apps/nshlib/nsh_netinit.c @@ -107,7 +107,7 @@ # ifndef CONFIG_NSH_NOMAC # error "CONFIG_NSH_NOMAC must be defined for SLIP" # endif -#else +#elif !defined(CONFIG_NET_LOCAL) # error ERROR: No link layer protocol defined #endif @@ -235,7 +235,8 @@ static void nsh_netinit_configure(void) /* Set the MAC address */ netlib_setmacaddr(NET_DEVNAME, mac); -#endif + +#endif /* CONFIG_NSH_NOMAC && CONFIG_NET_ETHERNET */ #ifdef CONFIG_NET_IPv4 /* Set up our host address */ diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog index d1e6eea6b..3ea6bd3fc 100755 --- a/nuttx/ChangeLog +++ b/nuttx/ChangeLog @@ -9535,6 +9535,9 @@ * arch/arm/src/stm32/stm32_rtcc.c and Kconfig: Recent changes to stm32_rtcc.c do not compile with STM32L15XX configurations. From Jussi Kivilinna (2015-01-27). + * net/local: Add initial support for local, Unix domain sockets. + Initial support is limited to SOCK_STREAM and is untested on + initial commit (2014-01-27). * net/iob, net/tcp/tcp_callback.c, and include/nuttx/net/iob.h: There were issues with the TCP write-ahead buffering if CONFIG_NET_NOINTS was enabled: There is a possibility of deadlocks in certain timing conditions. diff --git a/nuttx/arch/sim/src/Makefile b/nuttx/arch/sim/src/Makefile index 4507ce60d..0fd5bfea9 100644 --- a/nuttx/arch/sim/src/Makefile +++ b/nuttx/arch/sim/src/Makefile @@ -98,7 +98,7 @@ ifeq ($(CONFIG_ARCH_ROMGETC),y) CSRCS += up_romgetc.c endif -ifeq ($(CONFIG_NET),y) +ifeq ($(CONFIG_NET_ETHERNET),y) CSRCS += up_netdriver.c HOSTCFLAGS += -DNETDEV_BUFSIZE=$(CONFIG_NET_ETH_MTU) ifneq ($(HOSTOS),Cygwin) diff --git a/nuttx/arch/sim/src/nuttx-names.dat b/nuttx/arch/sim/src/nuttx-names.dat index 9658cf644..bfd3c051c 100644 --- a/nuttx/arch/sim/src/nuttx-names.dat +++ b/nuttx/arch/sim/src/nuttx-names.dat @@ -1,3 +1,4 @@ +accept NXaccept calloc NXcalloc clock_gettime NXclock_gettime close NXclose @@ -13,6 +14,7 @@ fsync NXfsync gettimeofday NXgettimeofday ioctl NXioctl isatty NXisatty +listen NXlisten lseek NXlseek malloc NXmalloc malloc_init NXmalloc_init diff --git a/nuttx/arch/sim/src/up_idle.c b/nuttx/arch/sim/src/up_idle.c index ae7c2d704..3cc7875b9 100644 --- a/nuttx/arch/sim/src/up_idle.c +++ b/nuttx/arch/sim/src/up_idle.c @@ -117,7 +117,7 @@ void up_idle(void) #endif -#ifdef CONFIG_NET +#ifdef CONFIG_NET_ETHERNET /* Run the network if enabled */ netdriver_loop(); diff --git a/nuttx/arch/sim/src/up_initialize.c b/nuttx/arch/sim/src/up_initialize.c index 6ae39f94a..82eb32d1c 100644 --- a/nuttx/arch/sim/src/up_initialize.c +++ b/nuttx/arch/sim/src/up_initialize.c @@ -158,7 +158,7 @@ void up_initialize(void) up_registerblockdevice(); /* Our FAT ramdisk at /dev/ram0 */ #endif -#ifdef CONFIG_NET +#ifdef CONFIG_NET_ETHERNET netdriver_init(); /* Our "real" network driver */ #endif diff --git a/nuttx/include/nuttx/net/netconfig.h b/nuttx/include/nuttx/net/netconfig.h index fed4f4ada..58e285b5f 100644 --- a/nuttx/include/nuttx/net/netconfig.h +++ b/nuttx/include/nuttx/net/netconfig.h @@ -148,7 +148,7 @@ # define MIN_NET_DEV_MTU CONFIG_NET_SLIP_MTU # define MAX_NET_DEV_MTU CONFIG_NET_SLIP_MTU -#else /* if defined(CONFIG_NET_ETHERNET) */ +#elif defined(CONFIG_NET_ETHERNET) /* Assume standard Ethernet link layer header */ # define NET_LL_HDRLEN(d) 14 @@ -156,6 +156,14 @@ # define MIN_NET_DEV_MTU CONFIG_NET_ETH_MTU # define MAX_NET_DEV_MTU CONFIG_NET_ETH_MTU +#else + /* Perhaps only Unix domain sockets */ + +# define NET_LL_HDRLEN(d) 0 +# define NET_DEV_MTU(d) 0 +# define MIN_NET_DEV_MTU 0 +# define MAX_NET_DEV_MTU 0 + #endif /* MULTILINK or SLIP or ETHERNET */ /* Layer 3/4 Configuration Options ******************************************/ diff --git a/nuttx/net/Kconfig b/nuttx/net/Kconfig index 2c2eabef6..272743d2b 100644 --- a/nuttx/net/Kconfig +++ b/nuttx/net/Kconfig @@ -202,6 +202,7 @@ endmenu # Internet Protocol Selection source "net/socket/Kconfig" source "net/pkt/Kconfig" +source "net/local/Kconfig" source "net/tcp/Kconfig" source "net/udp/Kconfig" source "net/icmp/Kconfig" diff --git a/nuttx/net/Makefile b/nuttx/net/Makefile index 7a9cf03d5..ce3faf0f3 100644 --- a/nuttx/net/Makefile +++ b/nuttx/net/Makefile @@ -63,9 +63,10 @@ include icmp/Make.defs include icmpv6/Make.defs include neighbor/Make.defs include igmp/Make.defs +include pkt/Make.defs +include local/Make.defs include tcp/Make.defs include udp/Make.defs -include pkt/Make.defs include devif/Make.defs include route/Make.defs include utils/Make.defs diff --git a/nuttx/net/README.txt b/nuttx/net/README.txt index bbbccc0db..db0a59452 100644 --- a/nuttx/net/README.txt +++ b/nuttx/net/README.txt @@ -13,6 +13,7 @@ Directory Structure +- icmp - Internet Control Message Protocol (IPv4) +- icmpv6 - Internet Control Message Protocol (IPv6) +- iob - I/O buffering logic + +- local - Unix domain (local) sockets +- neighbor - Neighbor Discovery Protocol (IPv6) +- netdev - Socket network device interface +- pkt - "Raw" packet socket support diff --git a/nuttx/net/devif/devif_poll.c b/nuttx/net/devif/devif_poll.c index 3070584b6..c942ea266 100644 --- a/nuttx/net/devif/devif_poll.c +++ b/nuttx/net/devif/devif_poll.c @@ -313,7 +313,7 @@ static inline int devif_poll_tcp_timer(FAR struct net_driver_s *dev, int devif_poll(FAR struct net_driver_s *dev, devif_poll_callback_t callback) { - int bstop; + int bstop = false; /* Traverse all of the active packet connections and perform the poll * action. @@ -417,7 +417,7 @@ int devif_poll(FAR struct net_driver_s *dev, devif_poll_callback_t callback) int devif_timer(FAR struct net_driver_s *dev, devif_poll_callback_t callback, int hsec) { - int bstop; + int bstop = false; /* Increment the timer used by the IP reassembly logic */ diff --git a/nuttx/net/local/Kconfig b/nuttx/net/local/Kconfig new file mode 100644 index 000000000..2f720c348 --- /dev/null +++ b/nuttx/net/local/Kconfig @@ -0,0 +1,19 @@ +# +# For a description of the syntax of this configuration file, +# see misc/tools/kconfig-language.txt. +# + +menu "Unix Domain Socket Support" + depends on NET && EXPERIMENTAL + +config NET_LOCAL + bool "Unix domain (local) sockets" + default n + ---help--- + Enable or disable Unix domain (aka Local) sockets. + +if NET_LOCAL + +endif # NET_LOCAL + +endmenu # Unix Domain Sockets diff --git a/nuttx/net/local/Make.defs b/nuttx/net/local/Make.defs new file mode 100644 index 000000000..6b101cd7a --- /dev/null +++ b/nuttx/net/local/Make.defs @@ -0,0 +1,49 @@ +############################################################################ +# net/local/Make.defs +# +# Copyright (C) 2015 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. +# +############################################################################ + +# UDP source files + +ifeq ($(CONFIG_NET_LOCAL),y) + +NET_CSRCS += local_conn.c local_connect.c local_release.c local_bind.c +NET_CSRCS += local_listen.c local_accept.c local_fifo.c local_recvfrom.c +NET_CSRCS += local_send.c local_sendto.c local_sendpacket.c local_recvutils.c + +# Include UDP build support + +DEPPATH += --dep-path local +VPATH += :local + +endif # CONFIG_NET_LOCAL diff --git a/nuttx/net/local/local.h b/nuttx/net/local/local.h new file mode 100644 index 000000000..23a4ed8fe --- /dev/null +++ b/nuttx/net/local/local.h @@ -0,0 +1,549 @@ +/**************************************************************************** + * net/local/loal.h + * + * Copyright (C) 2015 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 __NET_LOCAL_LOCAL_H +#define __NET_LOCAL_LOCAL_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <sys/un.h> +#include <semaphore.h> +#include <queue.h> +#include <stdint.h> + +#ifdef CONFIG_NET_LOCAL + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Packet format in FIFO: + * + * 1. Sync bytes (7 at most) + * 2. End/Start byte + * 3. 16-bit packet length (in host order) + * 4. Packet data (in host order) + */ + +#define LOCAL_SYNC_BYTE 0x42 /* Byte in sync sequence */ +#define LOCAL_END_BYTE 0xbd /* End of sync seqence */ + +/**************************************************************************** + * Public Type Definitions + ****************************************************************************/ +/* Local, Unix domain socket types */ + +enum local_type_e +{ + LOCAL_TYPE_UNTYPED = 0, /* Type is not determined until the socket is bound */ + LOCAL_TYPE_UNNAMED, /* A Unix socket that is not bound to any name */ + LOCAL_TYPE_PATHNAME, /* lc_path holds a null terminated string */ + LOCAL_TYPE_ABSTRACT /* lc_path is length zero */ +}; + +/* The state of a Unix socket */ + +enum local_state_s +{ + /* Common states */ + + LOCAL_STATE_UNBOUND = 0, /* Created by socket, but not bound */ + LOCAL_STATE_BOUND, /* Bound to an path */ + + /* SOCK_STREAM server only */ + + LOCAL_STATE_LISTENING, /* Server listening for connections */ + + /* SOCK_STREAM peers only */ + + LOCAL_STATE_ACCEPT, /* Client waiting for a connection */ + LOCAL_STATE_CONNECTED, /* Peer connected */ + LOCAL_STATE_DISCONNECTED /* Peer disconnected */ +}; + +/* Representation of a local connection. There are four types of + * connection structures: + * + * 1. Server. A SOCK_STREAM that only listens for and accepts + * connections from server. + * 2. Client. A SOCK_STREAM peer that connects via the server. + * 3. Peer. A connected SOCK_STREAM that sends() and recvs() packets. + * May either be the client that connect with the server of the + * new peer connect generated with the connection was accepted by + * the server. + * + * And + * + * 4. Connectionless. Like a peer but using a connectionless datagram + * style of communication. SOCK_DRAM support has not yet been + * implemented. + */ + +struct local_conn_s +{ + /* lc_node supports a doubly linked list: Listening SOCK_STREAM servers + * will be linked into a list of listeners; SOCK_STREAM clients will be + * linked to the lc_waiters and lc_conn lists. + */ + + dq_entry_t lc_node; /* Supports a doubly linked list */ + + /* Fields common to SOCK_STREAM and SOCK_DGRAM */ + + uint8_t lc_crefs; /* Reference counts on this instance */ + uint8_t lc_proto; /* SOCK_STREAM or SOCK_DGRAM */ + uint8_t lc_type; /* See enum local_type_e */ + uint8_t lc_state; /* See enum local_state_e */ + int16_t lc_infd; /* File descriptor of read-only FIFO (peers) */ + int16_t lc_outfd; /* File descriptor of write-only FIFO (peers) */ + char lc_path[UNIX_PATH_MAX]; /* Path assigned by bind() */ + + /* SOCK_STREAM fields common to both client and server */ + + sem_t lc_waitsem; /* Use to wait for a connection to be accepted */ + + /* Union of fields unique to SOCK_STREAM client, server, and connected + * peers. + */ + + union + { + /* Fields unique to the SOCK_STREAM server side */ + + struct + { + uint8_t lc_pending; /* Number of pending connections */ + uint8_t lc_backlog; /* Maximum number of pending connections */ + dq_queue_t lc_waiters; /* List of connections waiting to be accepted */ + } server; + + /* Fields unique to the connecting client side */ + + struct + { + uint16_t lc_remaining; /* (For binary compatibility with peer) */ + volatile int lc_result; /* Result of the connection operation (client)*/ + } client; + + /* Fields common to connected peers (connected or accepted) */ + + struct + { + uint16_t lc_remaining; /* Bytes remaining in the incoming stream */ + } peer; + } u; +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifdef __cplusplus +# define EXTERN extern "C" +extern "C" +{ +#else +# define EXTERN extern +#endif + +/* A list of all SOCK_STREAM listener connections */ + +EXTERN dq_queue_t g_local_listeners; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +struct sockaddr; /* Forward reference */ +struct socket; /* Forward reference */ + +/**************************************************************************** + * Name: local_initialize + * + * Description: + * Initialize the local, Unix domain connection structures. Called once + * and only from the common network initialization logic. + * + ****************************************************************************/ + +void local_initialize(void); + +/**************************************************************************** + * Name: local_alloc + * + * Description: + * Allocate a new, uninitialized local connection structure. This is + * normally something done by the implementation of the socket() API + * + ****************************************************************************/ + +FAR struct local_conn_s *local_alloc(void); + +/**************************************************************************** + * Name: local_free + * + * Description: + * Free a local connection structure that is no longer in use. This should + * be done by the implementation of close(). + * + ****************************************************************************/ + +void local_free(FAR struct local_conn_s *conn); + +/**************************************************************************** + * Name: psock_local_bind + * + * Description: + * This function implements the low-level parts of the standard local + * bind()operation. + * + ****************************************************************************/ + +int psock_local_bind(FAR struct socket *psock, + FAR const struct sockaddr *addr, socklen_t addrlen); + +/**************************************************************************** + * Name: local_connect + * + * Description: + * This function sets up a new local connection. The function will + * automatically allocate an unused local port for the new + * connection. However, another port can be chosen by using the + * psock_local_bind() call, after the local_connect() function has been + * called. + * + * This function is called as part of the implementation of sendto + * and recvfrom. + * + * Input Parameters: + * client - A reference to the client-side local connection structure + * addr - The address of the remote host. + * + ****************************************************************************/ + +int local_connect(FAR struct local_conn_s *client, + FAR const struct sockaddr *addr); + +/**************************************************************************** + * Name: local_release + * + * Description: + * If the local, Unix domain socket is in the connected state, then + * disconnect it. Release the local connection structure in any event + * + * Input Parameters: + * conn - A reference to local connection structure + * + ****************************************************************************/ + +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. + * + * 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. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + * Assumptions: + * The network is NOT locked + * + ****************************************************************************/ + +int local_listen(FAR struct local_conn_s *server, int backlog); + +/**************************************************************************** + * Function: psock_local_accept + * + * Description: + * This function implements accept() for Unix domain sockets. See the + * description of accept() for further information. + * + * Parameters: + * psock The listening Unix domain socket structure + * addr Receives the address of the connecting client + * addrlen Input: allocated size of 'addr', Return: returned size of 'addr' + * newconn The new, accepted Unix domain connection structure + * + * Returned Value: + * Returns zero (OK) on success or a negated errno value on failure. + * See the description of accept of the possible errno values in the + * description of accept(). + * + * Assumptions: + * Network is NOT locked. + * + ****************************************************************************/ + +int psock_local_accept(FAR struct socket *psock, FAR struct sockaddr *addr, + FAR socklen_t *addrlen, FAR void **newconn); + +/**************************************************************************** + * Name: psock_local_send + * + * Description: + * Send a local packet as a stream. + * + * Parameters: + * psock An instance of the internal socket structure. + * buf Data to send + * len Length of data to send + * flags Send flags (ignored for now) + * + * Return: + * On success, returns the number of characters sent. On error, + * -1 is returned, and errno is set appropriately (see send() for the + * list of errno numbers). + * + ****************************************************************************/ + +ssize_t psock_local_send(FAR struct socket *psock, FAR const void *buf, + size_t len, int flags); + +/**************************************************************************** + * Function: psock_sendto + * + * Description: + * Send a local packet as a datagram. + * + * Parameters: + * psock A pointer to a NuttX-specific, internal socket structure + * buf Data to send + * len Length of data to send + * flags Send flags (ignored for now) + * to Address of recipient + * tolen The length of the address structure + * + * Returned Value: + * On success, returns the number of characters sent. On error, + * -1 is returned, and errno is set appropriately (see sendto() for the + * list of errno numbers). + * + ****************************************************************************/ + +ssize_t psock_local_sendto(FAR struct socket *psock, FAR const void *buf, + size_t len, int flags, FAR const struct sockaddr *to, + socklen_t tolen); + +/**************************************************************************** + * Name: local_send_packet + * + * Description: + * Send a packet on the write-only FIFO. + * + * Parameters: + * fd File descriptor of write-only FIFO. + * buf Data to send + * len Length of data to send + * + * Return: + * Zero is returned on success; a negated errno value is returned on any + * failure. + * + ****************************************************************************/ + +int local_send_packet(int fd, FAR const uint8_t *buf, size_t len); + +/**************************************************************************** + * Function: psock_recvfrom + * + * Description: + * 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 + * 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 (ignored for now) + * from Address of source (may be NULL) + * fromlen The length of the address structure + * + * Returned Value: + * On success, returns the number of characters sent. 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 receivefrom for the complete list). + * + ****************************************************************************/ + +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); + +/**************************************************************************** + * Name: local_fifo_read + * + * Description: + * Read a data from the read-only FIFO. + * + * Parameters: + * fd - File descriptor of read-only FIFO. + * buf - Local to store the received data + * len - Length of data to receive [in] + * Length of data actually received [out] + * + * Return: + * Zero is returned on success; a negated errno value is returned on any + * failure. If -ECONNRESET is received, then the sending side has closed + * the FIFO. In this case, the returned data may still be valid (if the + * returned len > 0). + * + ****************************************************************************/ + +int local_fifo_read(int fd, FAR uint8_t *buf, size_t *len); + +/**************************************************************************** + * Name: local_getaddr + * + * Description: + * Return the Unix domain address of a connection. + * + * Parameters: + * conn - The connection + * addr - The location to return the address + * addrlen - The size of the memory allocat by the caller to receive the + * address. + * + * Return: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int local_getaddr(FAR struct local_conn_s *conn, FAR struct sockaddr *addr, + FAR socklen_t *addrlen); + +/**************************************************************************** + * Name: local_sync + * + * Description: + * Read a sync bytes until the start of the packet is found. + * + * Parameters: + * fd - File descriptor of read-only FIFO. + * + * Return: + * The non-zero size of the following packet is returned on success; a + * negated errno value is returned on any failure. + * + ****************************************************************************/ + +int local_sync(int fd); + +/**************************************************************************** + * Name: local_create_fifos + * + * Description: + * Create the FIFO pair needed for a connection. + * + ****************************************************************************/ + +int local_create_fifos(FAR struct local_conn_s *client); + +/**************************************************************************** + * Name: local_destroy_fifos + * + * Description: + * Destroy the FIFO pair used for a connection. + * + ****************************************************************************/ + +int local_destroy_fifos(FAR struct local_conn_s *client); + +/**************************************************************************** + * Name: local_open_client_rx + * + * Description: + * Only the client-side Rx FIFO. + * + ****************************************************************************/ + +int local_open_client_rx(FAR struct local_conn_s *client); + +/**************************************************************************** + * Name: local_open_client_tx + * + * Description: + * Only the client-side Tx FIFO. + * + ****************************************************************************/ + +int local_open_client_tx(FAR struct local_conn_s *client); + +/**************************************************************************** + * Name: local_open_server_rx + * + * Description: + * Only the server-side Rx FIFO. + * + ****************************************************************************/ + +int local_open_server_rx(FAR struct local_conn_s *server); + +/**************************************************************************** + * Name: local_open_server_tx + * + * Description: + * Only the server-side Tx FIFO. + * + ****************************************************************************/ + +int local_open_server_tx(FAR struct local_conn_s *server); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* CONFIG_NET_LOCAL */ +#endif /* __NET_LOCAL_LOCAL_H */ diff --git a/nuttx/net/local/local_accept.c b/nuttx/net/local/local_accept.c new file mode 100644 index 000000000..2fd1b92d3 --- /dev/null +++ b/nuttx/net/local/local_accept.c @@ -0,0 +1,224 @@ +/**************************************************************************** + * net/local/local_accept.c + * + * Copyright (C) 2015 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> +#if defined(CONFIG_NET) && defined(CONFIG_NET_LOCAL) + +#include <string.h> +#include <errno.h> +#include <assert.h> +#include <queue.h> +#include <debug.h> + +#include <nuttx/net/net.h> + +#include "socket/socket.h" +#include "local/local.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: psock_local_accept + * + * Description: + * This function implements accept() for Unix domain sockets. See the + * description of accept() for further information. + * + * Parameters: + * psock The listening Unix domain socket structure + * addr Receives the address of the connecting client + * addrlen Input: allocated size of 'addr', Return: returned size of 'addr' + * newconn The new, accepted Unix domain connection structure + * + * Returned Value: + * Returns zero (OK) on success or a negated errno value on failure. + * See the description of accept of the possible errno values in the + * description of accept(). + * + * Assumptions: + * Network is NOT locked. + * + ****************************************************************************/ + +int psock_local_accept(FAR struct socket *psock, FAR struct sockaddr *addr, + FAR socklen_t *addrlen, FAR void **newconn) + +{ + FAR struct local_conn_s *server; + FAR struct local_conn_s *client; + FAR struct local_conn_s *conn; + int ret; + + /* Some sanity checks */ + + DEBUGASSERT(psock && psock->s_conn); + server = (FAR struct local_conn_s *)psock->s_conn; + + if (server->lc_proto != SOCK_STREAM || + server->lc_state != LOCAL_STATE_LISTENING || + server->lc_type != LOCAL_TYPE_PATHNAME) + { + return -EOPNOTSUPP; + } + + /* Loop as necessary if we have to wait for a connection */ + + for (;;) + { + /* Are there pending connections. Remove the client from the + * head of the waiting list. + */ + + client = (FAR struct local_conn_s *) + dq_remfirst(&server->u.server.lc_waiters); + + if (client) + { + /* Decrement the number of pending clients */ + + DEBUGASSERT(server->u.server.lc_pending > 0); + server->u.server.lc_pending--; + + /* Create a new connection structure for the server side of the + * connection. + */ + + conn = local_alloc(); + if (!conn) + { + ndbg("ERROR: Failed to allocate new connection structure\n"); + ret = -ENOMEM; + } + else + { + /* Initialize the new connection structure */ + + conn->lc_crefs = 1; + conn->lc_proto = SOCK_STREAM; + conn->lc_type = LOCAL_TYPE_PATHNAME; + conn->lc_state = LOCAL_STATE_CONNECTED; + + strncpy(conn->lc_path, client->lc_path, UNIX_PATH_MAX-1); + conn->lc_path[UNIX_PATH_MAX-1] = '\0'; + + /* Open the server-side write-only FIFO. This should not + * block. + */ + + ret = local_open_server_tx(conn); + if (ret < 0) + { + ndbg("ERROR: Failed to open write-only FIFOs for %s: %d\n", + conn->lc_path, ret); + } + } + + /* Do we have a connection? Is the write-side FIFO opened? */ + + if (ret == OK) + { + DEBUGASSERT(conn->lc_outfd >= 0); + + /* Open the server-side read-only FIFO. This should not + * block because the client side has already opening it + * for writing. + */ + + ret = local_open_server_rx(conn); + if (ret < 0) + { + ndbg("ERROR: Failed to open read-only FIFOs for %s: %d\n", + conn->lc_path, ret); + } + } + + /* Do we have a connection? Are the FIFOs opened? */ + + if (ret == OK) + { + DEBUGASSERT(conn->lc_infd >= 0); + + /* Return the address family */ + + if (addr) + { + ret = local_getaddr(client, addr, addrlen); + } + } + + if (ret == OK) + { + /* Return the client connection structure */ + + *newconn = (FAR void *)conn; + } + + /* Signal the client with the result of the connection */ + + client->u.client.lc_result = ret; + sem_post(&client->lc_waitsem); + return ret; + } + + /* No.. then there should be no pending connections */ + + DEBUGASSERT(server->u.server.lc_pending == 0); + + /* Was the socket opened non-blocking? */ + + if (_SS_ISNONBLOCK(psock->s_flags)) + { + /* Yes.. return EAGAIN */ + + return -EAGAIN; + } + + /* Otherwise, listen for a connection and try again. */ + + ret = local_listen(server, server->u.server.lc_backlog); + if (ret < 0) + { + return ret; + } + } +} + +#endif /* CONFIG_NET && CONFIG_NET_LOCAL */ diff --git a/nuttx/net/local/local_bind.c b/nuttx/net/local/local_bind.c new file mode 100644 index 000000000..675b49516 --- /dev/null +++ b/nuttx/net/local/local_bind.c @@ -0,0 +1,119 @@ +/**************************************************************************** + * net/local/local_bind.c + * + * Copyright (C) 2015 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> +#if defined(CONFIG_NET) && defined(CONFIG_NET_LOCAL) + +#include <sys/socket.h> +#include <string.h> +#include <assert.h> + +#include <nuttx/net/net.h> + +#include "local/local.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: local_bind + * + * Description: + * This function implements the low-level parts of the standard local + * bind()operation. + * + ****************************************************************************/ + +int psock_local_bind(FAR struct socket *psock, + FAR const struct sockaddr *addr, socklen_t addrlen) +{ + FAR struct local_conn_s *conn; + FAR const struct sockaddr_un *unaddr = + (FAR const struct sockaddr_un *)addr; + int namelen; + + DEBUGASSERT(psock && psock->s_conn && unaddr && + unaddr->sun_family == AF_LOCAL && + addrlen >= sizeof(sa_family_t)); + + conn = (FAR struct local_conn_s *)psock->s_conn; + + /* Save the address family */ + + conn->lc_proto = psock->s_type; + + /* No determine the type of the Unix domain socket by comparing the size + * of the address description. + */ + + if (addrlen == sizeof(sa_family_t)) + { + /* No sun_path... This is an un-named Unix domain socket */ + + conn->lc_type = LOCAL_TYPE_UNNAMED; + } + else + { + namelen = strnlen(unaddr->sun_path, UNIX_PATH_MAX-1); + if (namelen <= 0) + { + /* Zero-length sun_path... This is an abstract Unix domain socket */ + + conn->lc_type = LOCAL_TYPE_ABSTRACT; + conn->lc_path[0] = '\0'; + } + else + { + /* This is an normal, pathname Unix domain socket */ + + conn->lc_type = LOCAL_TYPE_PATHNAME; + + /* Copy the path into the connection structure */ + + (void)strncpy(conn->lc_path, unaddr->sun_path, UNIX_PATH_MAX-1); + conn->lc_path[UNIX_PATH_MAX-1] = '\0'; + } + } + + conn->lc_state = LOCAL_STATE_BOUND; + return OK; +} + +#endif /* CONFIG_NET && CONFIG_NET_LOCAL */ diff --git a/nuttx/net/local/local_conn.c b/nuttx/net/local/local_conn.c new file mode 100644 index 000000000..171313b29 --- /dev/null +++ b/nuttx/net/local/local_conn.c @@ -0,0 +1,136 @@ +/**************************************************************************** + * net/local/local_conn.c + * + * Copyright (C) 2015 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> +#if defined(CONFIG_NET) && defined(CONFIG_NET_LOCAL) + +#include <semaphore.h> +#include <string.h> +#include <assert.h> +#include <errno.h> +#include <queue.h> +#include <debug.h> + +#include <nuttx/kmalloc.h> + +#include "local/local.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: local_initialize + * + * Description: + * Initialize the local, Unix domain connection structures. Called once + * and only from the common network initialization logic. + * + ****************************************************************************/ + + void local_initialize(void) +{ + dq_init(&g_local_listeners); +} + +/**************************************************************************** + * Name: local_alloc() + * + * Description: + * Allocate a new, uninitialized Unix domain socket connection structure. + * This is normally something done by the implementation of the socket() + * API + * + ****************************************************************************/ + +FAR struct local_conn_s *local_alloc(void) +{ + FAR struct local_conn_s *conn = + (FAR struct local_conn_s *)kmm_zalloc(sizeof(struct local_conn_s)); + + if (conn) + { + /* Initialize non-zero elements the new connection structure */ + + conn->lc_infd = -1; + conn->lc_outfd = -1; + sem_init(&conn->lc_waitsem, 0, 0); + } + + return conn; +} + +/**************************************************************************** + * Name: local_free() + * + * Description: + * Free a packet Unix domain connection structure that is no longer in use. + * This should be done by the implementation of close(). + * + ****************************************************************************/ + +void local_free(FAR struct local_conn_s *conn) +{ + DEBUGASSERT(conn != NULL); + + /* Make sure that the read-only FIFO is closed */ + + if (conn->lc_infd >= 0) + { + close(conn->lc_infd); + } + + /* Make sure that the write-only FIFO is closed */ + + if (conn->lc_outfd >= 0) + { + close(conn->lc_outfd); + } + + /* Destroy all FIFOs associted with the connection */ + + local_destroy_fifos(conn); + sem_destroy(&conn->lc_waitsem); + + /* And free the connection structure */ + + kmm_free(conn); +} + +#endif /* CONFIG_NET && CONFIG_NET_LOCAL */ diff --git a/nuttx/net/local/local_connect.c b/nuttx/net/local/local_connect.c new file mode 100644 index 000000000..c10de214a --- /dev/null +++ b/nuttx/net/local/local_connect.c @@ -0,0 +1,305 @@ +/**************************************************************************** + * net/local/local_connnect.c + * + * Copyright (C) 2015 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> +#if defined(CONFIG_NET) && defined(CONFIG_NET_LOCAL) + +#include <string.h> +#include <unistd.h> +#include <assert.h> +#include <errno.h> +#include <queue.h> +#include <debug.h> + +#include <nuttx/net/net.h> + +#include "utils/utils.h" +#include "local/local.h" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: _local_semtake() and _local_semgive() + * + * Description: + * Take/give semaphore + * + ****************************************************************************/ + +static inline void _local_semtake(sem_t *sem) +{ + /* Take the semaphore (perhaps waiting) */ + + while (sem_wait(sem) != 0) + { + /* The only case that an error should occur here is if + * the wait was awakened by a signal. + */ + + ASSERT(*get_errno_ptr() == EINTR); + } +} + +#define _local_semgive(sem) sem_post(sem) + +/**************************************************************************** + * Name: local_stream_connect + * + * Description: + * Find a local connection structure that is the appropriate "server" + * connection to be used with the provided "client" connection. + * + * Returned Values: + * Zero (OK) returned on success; A negated errno value is returned on a + * failure. Possible failures include: + * + * Assumptions: + * The network is locked on entry, unlocked on return. This logic is + * an integral part of the lock_connect() implementation and was + * separated out only to improve readability. + * + ****************************************************************************/ + +int inline local_stream_connect(FAR struct local_conn_s *client, + FAR struct local_conn_s *server, + net_lock_t state) +{ + int ret; + + /* Has server backlog been reached? + * NOTE: The backlog will be zero if listen() has never been called by the + * server. + */ + + if (server->lc_state != LOCAL_STATE_LISTENING || + server->u.server.lc_pending >= server->u.server.lc_backlog) + { + net_unlock(state); + ndbg("ERROR: Server is not listening: lc_state=%d\n", + server->lc_state); + ndbg(" OR: The backlog limit was reached: %d or %d\n", + server->u.server.lc_pending, server->u.server.lc_backlog); + return -ECONNREFUSED; + } + + /* Increment the number of pending server connection s*/ + + server->u.server.lc_pending++; + DEBUGASSERT(server->u.server.lc_pending != 0); + + /* Create the FIFOs needed for the connection */ + + ret = local_create_fifos(client); + if (ret < 0) + { + ndbg("ERROR: Failed to create FIFOs for %s: %d\n", + client->lc_path, ret); + return ret; + } + + /* Open the client-side write-only FIFO. This should not block and should + * prevent the server-side from blocking as well. + */ + + ret = local_open_client_tx(client); + if (ret < 0) + { + ndbg("ERROR: Failed to open write-only FIFOs for %s: %d\n", + client->lc_path, ret); + goto errout_with_fifos; + } + + DEBUGASSERT(client->lc_outfd >= 0); + + /* Add ourself to the list of waiting connections and notify the server. */ + + dq_addlast(&client->lc_node, &server->u.server.lc_waiters); + client->lc_state = LOCAL_STATE_ACCEPT; + _local_semgive(&server->lc_waitsem); + net_unlock(state); + + /* Wait for the server to accept the connections */ + + client->u.client.lc_result = -EBUSY; + do + { + _local_semtake(&client->lc_waitsem); + ret = client->u.client.lc_result; + } + while (ret == -EBUSY); + + /* Did we successfully connect? */ + + if (ret < 0) + { + ndbg("ERROR: Failed to connect: %d\n", ret); + goto errout_with_outfd; + } + + /* Yes.. open the read-only FIFO */ + + ret = local_open_client_tx(client); + if (ret < 0) + { + ndbg("ERROR: Failed to open write-only FIFOs for %s: %d\n", + client->lc_path, ret); + goto errout_with_outfd; + } + + DEBUGASSERT(client->lc_infd >= 0); + client->lc_state = LOCAL_STATE_CONNECTED; + return OK; + +errout_with_outfd: + (void)close(client->lc_outfd); + +errout_with_fifos: + (void)local_destroy_fifos(client); + client->lc_state = LOCAL_STATE_BOUND; + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: local_connect + * + * Description: + * Find a local connection structure that is the appropriate "server" + * connection to be used with the provided "client" connection. + * + * Returned Values: + * Zero (OK) returned on success; A negated errno value is returned on a + * failure. Possible failures include: + * + * EISCONN - The specified socket is connection-mode and is already + * connected. + * EADDRNOTAVAIL - The specified address is not available from the + * local machine. + * ECONNREFUSED - The target address was not listening for connections or + * refused the connection request because the connection backlog has + * been exceeded. + * + ****************************************************************************/ + +int local_connect(FAR struct local_conn_s *client, + FAR const struct sockaddr *addr) +{ + FAR struct sockaddr_un *unaddr = (FAR struct sockaddr_un *)addr; + FAR struct local_conn_s *conn; + net_lock_t state; + + DEBUGASSERT(client); + + if (client->lc_state == LOCAL_STATE_ACCEPT || + client->lc_state == LOCAL_STATE_CONNECTED) + { + return -EISCONN; + } + + /* Find the matching server connection */ + + state = net_lock(); + for(conn = (FAR struct local_conn_s *)g_local_listeners.head; + conn; + conn = (FAR struct local_conn_s *)dq_next(&conn->lc_node)) + { + /* Anything in the listener list should be a stream socket in the + * istening state + */ + + DEBUGASSERT(conn->lc_state == LOCAL_STATE_LISTENING && + conn->lc_proto == SOCK_STREAM); + + /* Handle according to the server connection type */ + + switch (conn->lc_type) + { + case LOCAL_TYPE_UNNAMED: /* A Unix socket that is not bound to any name */ + case LOCAL_TYPE_ABSTRACT: /* lc_path is length zero */ + { +#warning Missing logic + net_unlock(state); + return OK; + } + break; + + case LOCAL_TYPE_PATHNAME: /* lc_path holds a null terminated string */ + { + if (strncmp(conn->lc_path, unaddr->sun_path, UNIX_PATH_MAX-1) == 0) + { + /* Bind the address and protocol */ + + client->lc_proto = conn->lc_proto; + strncpy(client->lc_path, unaddr->sun_path, UNIX_PATH_MAX-1); + client->lc_path[UNIX_PATH_MAX-1] = '\0'; + + /* We have to do more for the SOCK_STREAM family */ + + if (conn->lc_proto == SOCK_STREAM) + { + return local_stream_connect(client, conn, state); + } + + net_unlock(state); + return OK; + } + } + break; + + default: /* Bad, memory must be corrupted */ + DEBUGPANIC(); /* PANIC if debug on, else fall through */ + + case LOCAL_TYPE_UNTYPED: /* Type is not determined until the socket is bound */ + { + net_unlock(state); + return -EINVAL; + } + } + } + + net_unlock(state); + return -EADDRNOTAVAIL; +} + +#endif /* CONFIG_NET && CONFIG_NET_LOCAL */ diff --git a/nuttx/net/local/local_fifo.c b/nuttx/net/local/local_fifo.c new file mode 100644 index 000000000..15ded2932 --- /dev/null +++ b/nuttx/net/local/local_fifo.c @@ -0,0 +1,407 @@ +/**************************************************************************** + * net/local/local_fifo.c + * + * Copyright (C) 2015 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> +#if defined(CONFIG_NET) && defined(CONFIG_NET_LOCAL) + +#include <sys/stat.h> +#include <stdbool.h> +#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <errno.h> +#include <assert.h> + +#include "local/local.h" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +#define LOCAL_RX_SUFFIX "RX" +#define LOCAL_TX_SUFFIX "TX" +#define LOCAL_SUFFIX_LEN 2 + +#define LOCAL_FULLPATH_LEN (UNIX_PATH_MAX + LOCAL_SUFFIX_LEN) + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: local_rx_name + * + * Description: + * Create the name of the RX (client-to-server) FIFO name. + * + ****************************************************************************/ + +static inline void local_rx_name(FAR struct local_conn_s *conn, + FAR char *path) +{ + (void)snprintf(path, LOCAL_FULLPATH_LEN-1, "%s" LOCAL_RX_SUFFIX, + conn->lc_path); + path[LOCAL_FULLPATH_LEN-1] = '\0'; +} + +/**************************************************************************** + * Name: local_tx_name + * + * Description: + * Create the name of the TX (server-to-client) FIFO name. + * + ****************************************************************************/ + +static inline void local_tx_name(FAR struct local_conn_s *conn, + FAR char *path) +{ + (void)snprintf(path, LOCAL_FULLPATH_LEN-1, "%s" LOCAL_TX_SUFFIX, + conn->lc_path); + path[LOCAL_FULLPATH_LEN-1] = '\0'; +} + +/**************************************************************************** + * Name: local_fifo_exists + * + * Description: + * Check if a FIFO exists. + * + ****************************************************************************/ + +static bool local_fifo_exists(FAR const char *path) +{ + struct stat buf; + int ret; + + /* Create the client-to-server FIFO */ + + ret = stat(path, &buf); + if (ret < 0) + { + return false; + } + + /* FIFOs are character devices in NuttX. Return true if what we found + * is a FIFO. What if it is something else? In that case, we will + * return false and mkfifo() will fail. + */ + + return (bool)S_ISCHR(buf.st_mode); +} + +/**************************************************************************** + * Name: local_create_fifo + * + * Description: + * Create the one of FIFOs needed for a connection. + * + ****************************************************************************/ + +static int local_create_fifo(FAR const char *path) +{ + int ret; + + /* Create the client-to-server FIFO if it does not already exist. */ + + if (!local_fifo_exists(path)) + { + ret = mkfifo(path, 0644); + if (ret < 0) + { + int errcode = errno; + DEBUGASSERT(errcode > 0); + + ndbg("ERROR: Failed to create FIFO %s: %d\n", path, errcode); + return -errcode; + } + } + + /* The FIFO (or some character driver) exists at PATH or we successfully + * created the FIFO at that location. + */ + + return OK; +} + +/**************************************************************************** + * Name: local_destroy_fifo + * + * Description: + * Destroy one of the FIFOs used in a connection. + * + ****************************************************************************/ + +static int local_destroy_fifo(FAR const char *path) +{ + int ret; + + /* Unlink the client-to-server FIFO if it exists. */ + + if (local_fifo_exists(path)) + { + ret = unlink(path); + if (ret < 0) + { + int errcode = errno; + DEBUGASSERT(errcode > 0); + + ndbg("ERROR: Failed to unlink FIFO %s: %d\n", path, errcode); + return -errcode; + } + } + + /* The FIFO does not exist or we successfully unlinked it. */ + + return OK; +} + +/**************************************************************************** + * Name: local_rx_open + * + * Description: + * Open a FIFO for read-only access. + * + ****************************************************************************/ + +static inline int local_rx_open(FAR struct local_conn_s *conn, + FAR const char *path) +{ + conn->lc_infd = open(path, O_RDONLY); + if (conn->lc_infd < 0) + { + int errcode = errno; + DEBUGASSERT(errcode > 0); + + ndbg("ERROR: Failed on open %s for reading: %d\n", + path, errcode); + + /* Map the errcode to something consistent with the return + * error codes from connect(): + * + * If errcode is ENOENT, meaning that the FIFO does exist, + * return EFAULT meaning that the socket structure address is + * outside the user's address space. + */ + + return errcode == ENOENT ? -EFAULT : -errcode; + } + + return OK; +} + +/**************************************************************************** + * Name: local_tx_open + * + * Description: + * Open a FIFO for write-only access. + * + ****************************************************************************/ + +static inline int local_tx_open(FAR struct local_conn_s *conn, + FAR const char *path) +{ + conn->lc_infd = open(path, O_WRONLY); + if (conn->lc_infd < 0) + { + int errcode = errno; + DEBUGASSERT(errcode > 0); + + ndbg("ERROR: Failed on open %s for writing: %d\n", + path, errcode); + + /* Map the errcode to something consistent with the return + * error codes from connect(): + * + * If errcode is ENOENT, meaning that the FIFO does exist, + * return EFAULT meaning that the socket structure address is + * outside the user's address space. + */ + + return errcode == ENOENT ? -EFAULT : -errcode; + } + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: local_create_fifos + * + * Description: + * Create the FIFO pair needed for a connection. + * + ****************************************************************************/ + +int local_create_fifos(FAR struct local_conn_s *client) +{ + char path[LOCAL_FULLPATH_LEN]; + int ret; + + /* Create the client-to-server FIFO if it does not already exist. */ + + local_tx_name(client, path); + ret = local_create_fifo(path); + if (ret >= 0) + { + /* Create the server-to-client FIFO if it does not already exist. */ + + local_rx_name(client, path); + ret = local_create_fifo(path); + } + + return ret; +} + +/**************************************************************************** + * Name: local_destroy_fifos + * + * Description: + * Destroy the FIFO pair used for a connection. + * + ****************************************************************************/ + +int local_destroy_fifos(FAR struct local_conn_s *client) +{ + char path[LOCAL_FULLPATH_LEN]; + int ret1; + int ret2; + + /* Destroy the client-to-server FIFO if it exists. */ + + local_tx_name(client, path); + ret1 = local_destroy_fifo(path); + + /* Destroy the server-to-client FIFO if it exists. */ + + local_rx_name(client, path); + ret2 = local_create_fifo(path); + + /* Return a failure if one occurred. */ + + return ret1 < 0 ? ret1 : ret2; +} + +/**************************************************************************** + * Name: local_open_client_rx + * + * Description: + * Only the client-side Rx FIFO. + * + ****************************************************************************/ + +int local_open_client_rx(FAR struct local_conn_s *client) +{ + char path[LOCAL_FULLPATH_LEN]; + + /* Get the server-to-client path name */ + + local_tx_name(client, path); + + /* Then open the file for read-only access */ + + return local_rx_open(client, path); +} + +/**************************************************************************** + * Name: local_open_client_tx + * + * Description: + * Only the client-side Tx FIFO. + * + ****************************************************************************/ + +int local_open_client_tx(FAR struct local_conn_s *client) +{ + char path[LOCAL_FULLPATH_LEN]; + + /* Get the client-to-server path name */ + + local_rx_name(client, path); + + /* Then open the file for write-only access */ + + return local_tx_open(client, path); +} + +/**************************************************************************** + * Name: local_open_server_rx + * + * Description: + * Only the server-side Rx FIFO. + * + ****************************************************************************/ + +int local_open_server_rx(FAR struct local_conn_s *server) +{ + char path[LOCAL_FULLPATH_LEN]; + + /* Get the client-to-server path name */ + + local_rx_name(server, path); + + /* Then open the file for write-only access */ + + return local_rx_open(server, path); +} + +/**************************************************************************** + * Name: local_open_server_tx + * + * Description: + * Only the server-side Tx FIFO. + * + ****************************************************************************/ + +int local_open_server_tx(FAR struct local_conn_s *server) +{ + char path[LOCAL_FULLPATH_LEN]; + + /* Get the server-to-client path name */ + + local_tx_name(server, path); + + /* Then open the file for read-only access */ + + return local_tx_open(server, path); +} +#endif /* CONFIG_NET && CONFIG_NET_LOCAL */ diff --git a/nuttx/net/local/local_listen.c b/nuttx/net/local/local_listen.c new file mode 100644 index 000000000..5de0d1232 --- /dev/null +++ b/nuttx/net/local/local_listen.c @@ -0,0 +1,149 @@ +/**************************************************************************** + * net/local/local_listen.c + * + * Copyright (C) 2015 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> +#if defined(CONFIG_NET) && defined(CONFIG_NET_LOCAL) + +#include <assert.h> +#include <queue.h> +#include <errno.h> + +#include <nuttx/net/net.h> + +#include "local/local.h" + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* A list of all allocated packet socket connections */ + +dq_queue_t g_local_listeners; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: local_listen + * + * Description: + * Listen for a new connection of a SOCK_STREAM Unix domain socket. + * + * 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. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + * Assumptions: + * The network is NOT locked + * + ****************************************************************************/ + +int local_listen(FAR struct local_conn_s *server, int backlog) +{ + net_lock_t state; + int ret; + + /* Some sanity checks */ + + DEBUGASSERT(server); + + if (server->lc_proto != SOCK_STREAM || + server->lc_state == LOCAL_STATE_UNBOUND || + server->lc_type != LOCAL_TYPE_PATHNAME) + { + return -EOPNOTSUPP; + } + + DEBUGASSERT(server->lc_state == LOCAL_STATE_BOUND || + server->lc_state == LOCAL_STATE_LISTENING); + + /* Set the backlog value */ + + DEBUGASSERT((unsigned)backlog < 256); + server->u.server.lc_backlog = backlog; + + /* Is this the first time since being bound to an address and that + * listen() was called? If so, the state should be LOCAL_STATE_BOUND. + */ + + if (server->lc_state == LOCAL_STATE_BOUND) + { + /* The connection should not reside in any other list */ + + DEBUGASSERT(server->lc_node.flink == NULL && + server->lc_node.flink == NULL); + + /* Add the connection structure to the list of listeners */ + + state = net_lock(); + dq_addlast(&server->lc_node, &g_local_listeners); + net_unlock(state); + + /* And change the server state to listing */ + + server->lc_state = LOCAL_STATE_LISTENING; + } + + /* Loop until a connection is requested or we receive a signal */ + + while (dq_empty(&server->u.server.lc_waiters)) + { + /* No.. wait for a connection or a signal */ + + ret = sem_wait(&server->lc_waitsem); + if (ret < 0) + { + int errval = errno; + DEBUGASSERT(errval == EINTR); + return -errval; + } + } + + /* There is a client waiting for the connection */ + + return OK; +} + +#endif /* CONFIG_NET && CONFIG_NET_LOCAL */ diff --git a/nuttx/net/local/local_recvfrom.c b/nuttx/net/local/local_recvfrom.c new file mode 100644 index 000000000..c4c9e6a6c --- /dev/null +++ b/nuttx/net/local/local_recvfrom.c @@ -0,0 +1,256 @@ +/**************************************************************************** + * net/local/local_recvfrom.c + * + * Copyright (C) 2015 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> +#if defined(CONFIG_NET) && defined(CONFIG_NET_LOCAL) + +#include <sys/types.h> +#include <sys/socket.h> +#include <errno.h> +#include <assert.h> +#include <debug.h> + +#include <nuttx/net/net.h> + +#include "socket/socket.h" +#include "local/local.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef MIN +# define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ +/**************************************************************************** + * Name: psock_fifo_read + * + * Description: + * A thin layer aroudn local_fifo_read that handles socket-related loss-of- + * connection events. + * + ****************************************************************************/ + +static int psock_fifo_read(FAR struct socket *psock, FAR void *buf, + FAR size_t *readlen) +{ + FAR struct local_conn_s *conn = (FAR struct local_conn_s *)psock->s_conn; + int ret; + + ret = local_fifo_read(conn->lc_infd, buf, readlen); + if (ret < 0) + { + /* -ECONNRESET is a special case. We may or not have received + * data, then the peer closed the connection. + */ + + if (ret == -ECONNRESET) + { + ndbg("ERROR: Lost connection: %d\n", ret); + + /* Report an ungraceful loss of connection. This should + * eventually be reported as ENOTCONN. + */ + + psock->s_flags &= ~(_SF_CONNECTED |_SF_CLOSED); + conn->lc_state = LOCAL_STATE_DISCONNECTED; + + /* Did we receive any data? */ + + if (*readlen <= 0) + { + /* No.. return the ECONNRESET error now. Otherwise, + * process the received data and return ENOTCONN the + * next time that psock_recvfrom() is calle. + */ + + return ret; + } + } + else + { + ndbg("ERROR: Failed to read packet: %d\n", ret); + return ret; + } + } + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: psock_recvfrom + * + * Description: + * 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 + * 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 sent. 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). + * + ****************************************************************************/ + +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) +{ + FAR struct local_conn_s *conn; + size_t readlen; + int ret; + + DEBUGASSERT(psock && psock->s_conn && buf); + conn = (FAR struct local_conn_s *)psock->s_conn; + + /* Verify that this is a connected peer socket and that it has opened the + * incoming FIFO for read-only access. + */ + + if (conn->lc_state != LOCAL_STATE_CONNECTED || + conn->lc_infd < 0) + { + ndbg("ERROR: not connected\n"); + return -ENOTCONN; + } + + /* Are there still bytes in the FIFO from the last packet? */ + + if (conn->u.peer.lc_remaining == 0) + { + /* No.. Sync to the start of the next packet in the stream and get + * the size of the next packet. + */ + + ret = local_sync(conn->lc_infd); + if (ret < 0) + { + ndbg("ERROR: Failed to get packet length: %d\n", ret); + return ret; + } + else if (ret > 0xffff) + { + ndbg("ERROR: Packet is too big: %d\n", ret); + return -E2BIG; + } + + conn->u.peer.lc_remaining = (uint16_t)ret; + } + + /* Read the packet */ + /* REVISIT: Does this make sense if the socket is SOCK_DGRAM? */ + + readlen = MIN(conn->u.peer.lc_remaining, len); + ret = psock_fifo_read(psock, buf, &readlen); + if (ret < 0) + { + return ret; + } + + /* Adjust the number of bytes remaining to be read from the packet */ + + DEBUGASSERT(readlen <= conn->u.peer.lc_remaining); + conn->u.peer.lc_remaining -= readlen; + + /* If this is a SOCK_STREAM socket and there are unread bytes remaining + * in the packet, we will get those bytes the next time recv is called. + * What if this is a SOCK_DRAM? REVISIT: Here we flush the remainder of + * the packet to the bit bucket. + */ + + if (psock->s_type == SOCK_DGRAM && conn->u.peer.lc_remaining > 0) + { + uint8_t bitbucket[32]; + size_t tmplen; + + do + { + /* Read 32 bytes into the bit bucket */ + + tmplen = MIN(conn->u.peer.lc_remaining, 32); + ret = psock_fifo_read(psock, bitbucket, &tmplen); + if (ret < 0) + { + return ret; + } + + /* Adjust the number of bytes remaining to be read from the packet */ + + DEBUGASSERT(tmplen <= conn->u.peer.lc_remaining); + conn->u.peer.lc_remaining -= tmplen; + } + while (conn->u.peer.lc_remaining > 0); + } + + /* Return the address family */ + + if (from) + { + ret = local_getaddr(conn, from, fromlen); + if (ret < 0) + { + return ret; + } + } + + return readlen; +} + +#endif /* CONFIG_NET && CONFIG_NET_LOCAL */ diff --git a/nuttx/net/local/local_recvutils.c b/nuttx/net/local/local_recvutils.c new file mode 100644 index 000000000..a7eee1c4a --- /dev/null +++ b/nuttx/net/local/local_recvutils.c @@ -0,0 +1,248 @@ +/**************************************************************************** + * net/local/local_recvpacket.c + * + * Copyright (C) 2015 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> +#if defined(CONFIG_NET) && defined(CONFIG_NET_LOCAL) + +#include <sys/types.h> +#include <stdint.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <assert.h> +#include <debug.h> + +#include "local/local.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: local_fifo_read + * + * Description: + * Read a data from the read-only FIFO. + * + * Parameters: + * fd - File descriptor of read-only FIFO. + * buf - Local to store the received data + * len - Length of data to receive [in] + * Length of data actually received [out] + * + * Return: + * Zero is returned on success; a negated errno value is returned on any + * failure. If -ECONNRESET is received, then the sending side has closed + * the FIFO. In this case, the returned data may still be valid (if the + * returned len > 0). + * + ****************************************************************************/ + +int local_fifo_read(int fd, FAR uint8_t *buf, size_t *len) +{ + ssize_t total; + ssize_t nread; + int ret; + + DEBUGASSERT(buf && len); + + total = 0; + while (len > 0) + { + nread = read(fd, buf, *len); + if (nread < 0) + { + int errcode = errno; + DEBUGASSERT(errcode > 0); + + if (errcode != EINTR) + { + ndbg("ERROR: Read failed: %d\n", errcode); + ret = -errcode; + goto errout; + } + + nvdbg("Ignoring signal\n"); + } + else if (nread == 0) + { + /* The FIFO returns zero if the sending side of the connection + * has closed the FIFO. + */ + + ret = -ECONNRESET; + goto errout; + } + else + { + DEBUGASSERT(nread <= len); + len -= nread; + buf += nread; + } + } + + ret = OK; + +errout: + *len = total; + return ret; +} + +/**************************************************************************** + * Name: local_sync + * + * Description: + * Read a sync bytes until the start of the packet is found. + * + * Parameters: + * fd - File descriptor of read-only FIFO. + * + * Return: + * The non-zero size of the following packet is returned on success; a + * negated errno value is returned on any failure. + * + ****************************************************************************/ + +int local_sync(int fd) +{ + size_t readlen; + uint16_t pktlen; + uint8_t sync; + int ret; + + /* Loop until a valid pre-amble is encountered: SYNC bytes followed + * by one END byte. + */ + + do + { + /* Read until we encounter a sync byte */ + + do + { + readlen = sizeof(uint8_t); + ret = local_fifo_read(fd, &sync, &readlen); + if (ret < 0) + { + ndbg("ERROR: Failed to read sync bytes: %d\n", ret); + return ret; + } + } + while (sync != LOCAL_SYNC_BYTE); + + /* Then read to the end of the SYNC sequence */ + + do + { + readlen = sizeof(uint8_t); + ret = local_fifo_read(fd, &sync, &readlen); + if (ret < 0) + { + ndbg("ERROR: Failed to read sync bytes: %d\n", ret); + return ret; + } + } + while (sync == LOCAL_SYNC_BYTE); + } + while (sync != LOCAL_END_BYTE); + + /* Then read the packet length */ + + readlen = sizeof(uint16_t); + ret = local_fifo_read(fd, (FAR uint8_t *)&pktlen, &readlen); + return ret < 0 ? ret : pktlen; +} + +/**************************************************************************** + * Name: local_getaddr + * + * Description: + * Return the Unix domain address of a connection. + * + * Parameters: + * conn - The connection + * addr - The location to return the address + * addrlen - The size of the memory allocated by the caller to receive the + * address. + * + * Return: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int local_getaddr(FAR struct local_conn_s *conn, FAR struct sockaddr *addr, + FAR socklen_t *addrlen) +{ + FAR struct sockaddr_un *unaddr; + int totlen; + int pathlen; + + DEBUGASSERT(conn && addr && addrlen && *addrlen >= sizeof(sa_family_t)); + + /* Get the length of the path (minus the NUL terminator) and the length + * of the whole Unix domain address. + */ + + pathlen = strnlen(conn->lc_path, UNIX_PATH_MAX-1); + totlen = sizeof(sa_family_t) + pathlen + 1; + + /* If the length of the whole Unix domain address is larger than the + * buffer provided by the caller, then truncate the address to fit. + */ + + if (totlen > *addrlen) + { + pathlen -= (totlen - *addrlen); + totlen = *addrlen; + } + + /* Copy the Unix domain address */ + + unaddr = (FAR struct sockaddr_un *)addr; + unaddr->sun_family = AF_LOCAL; + memcpy(unaddr->sun_path, conn->lc_path, pathlen); + unaddr->sun_path[pathlen] = '\0'; + + /* Return the Unix domain address size */ + + *addrlen = totlen; + return OK; +} + +#endif /* CONFIG_NET && CONFIG_NET_LOCAL */ diff --git a/nuttx/net/local/local_release.c b/nuttx/net/local/local_release.c new file mode 100644 index 000000000..e9b9d0c76 --- /dev/null +++ b/nuttx/net/local/local_release.c @@ -0,0 +1,129 @@ +/**************************************************************************** + * net/local/local_release.c + * + * Copyright (C) 2015 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> +#if defined(CONFIG_NET) && defined(CONFIG_NET_LOCAL) + +#include <semaphore.h> +#include <errno.h> +#include <queue.h> +#include <assert.h> + +#include <nuttx/net/net.h> + +#include "local/local.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: local_release + * + * Description: + * If the local, Unix domain socket is in the connected state, then + * disconnect it. Release the local connection structure in any event + * + * Input Parameters: + * conn - A reference to local connection structure + * + ****************************************************************************/ + +int local_release(FAR struct local_conn_s *conn) +{ + net_lock_t state; + + /* There should be no references on this structure */ + + DEBUGASSERT(conn->lc_crefs == 0); + state = net_lock(); + + /* We should not bet here with state LOCAL_STATE_ACCEPT. That is an + * internal state that should be atomic with respect to socket operations. + */ + + DEBUGASSERT(conn->lc_state != LOCAL_STATE_ACCEPT); + + /* If the socket is connected (SOCK_STREAM client), then disconnect it */ + + if (conn->lc_state == LOCAL_STATE_CONNECTED || + conn->lc_state == LOCAL_STATE_DISCONNECTED) + { + DEBUGASSERT(conn->lc_proto == SOCK_STREAM); + + /* Just free the connection structure */ + } + + /* Is the socket is listening socket (SOCK_STREAM server) */ + + else if (conn->lc_state == LOCAL_STATE_LISTENING) + { + FAR struct local_conn_s *client; + + DEBUGASSERT(conn->lc_proto == SOCK_STREAM); + + /* Are there still clients waiting for a connection to the server? */ + + for (client = (FAR struct local_conn_s *)conn->u.server.lc_waiters.head; + client; + client = (FAR struct local_conn_s *)dq_next(&client->lc_node)) + { + client->u.client.lc_result = -ENOTCONN; + sem_post(&client->lc_waitsem); + } + + conn->u.server.lc_pending = 0; + + /* Remove the server from the list of listeners. */ + + dq_rem(&conn->lc_node, &g_local_listeners); + } + + /* For the remaining states (LOCAL_STATE_UNBOUND and LOCAL_STATE_UNBOUND), + * we simply free the connection structure. + */ + + /* Free the connection structure */ + + local_free(conn); + net_unlock(state); + return OK; +} + +#endif /* CONFIG_NET && CONFIG_NET_LOCAL */ diff --git a/nuttx/net/local/local_send.c b/nuttx/net/local/local_send.c new file mode 100644 index 000000000..74bf7f0a4 --- /dev/null +++ b/nuttx/net/local/local_send.c @@ -0,0 +1,97 @@ +/**************************************************************************** + * net/local/local_send.c + * + * Copyright (C) 2015 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> +#if defined(CONFIG_NET) && defined(CONFIG_NET_LOCAL) + +#include <sys/types.h> +#include <errno.h> +#include <assert.h> +#include <debug.h> + +#include <nuttx/net/net.h> + +#include "local/local.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: psock_local_send + * + * Description: + * Send a local packet as a stream. + * + * Parameters: + * psock An instance of the internal socket structure. + * buf Data to send + * len Length of data to send + * flags Send flags (ignored for now) + * + * Return: + * On success, returns the number of characters sent. On error, + * -1 is returned, and errno is set appropriately (see send() for the + * list of errno numbers). + * + ****************************************************************************/ + +ssize_t psock_local_send(FAR struct socket *psock, FAR const void *buf, + size_t len, int flags) +{ + FAR struct local_conn_s *peer; + + DEBUGASSERT(psock && psock->s_conn && buf); + peer = (FAR struct local_conn_s *)psock->s_conn; + + /* Verify that this is a connected peer socket and that it has opened the + * outgoing FIFO for write-only access. + */ + + if (peer->lc_type != LOCAL_STATE_CONNECTED || + peer->lc_outfd < 0) + { + ndbg("ERROR: not connected\n"); + return -ENOTCONN; + } + + return local_send_packet(peer->lc_outfd, (FAR uint8_t *)buf, len); +} + +#endif /* CONFIG_NET && CONFIG_NET_LOCAL */ diff --git a/nuttx/net/local/local_sendpacket.c b/nuttx/net/local/local_sendpacket.c new file mode 100644 index 000000000..3658175d6 --- /dev/null +++ b/nuttx/net/local/local_sendpacket.c @@ -0,0 +1,166 @@ +/**************************************************************************** + * net/local/local_sendpacket.c + * + * Copyright (C) 2015 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> +#if defined(CONFIG_NET) && defined(CONFIG_NET_LOCAL) + +#include <sys/types.h> +#include <stdint.h> +#include <unistd.h> +#include <errno.h> +#include <assert.h> +#include <debug.h> + +#include "local/local.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define LOCAL_PREAMBLE_SIZE 8 + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const uint8_t g_preamble[LOCAL_PREAMBLE_SIZE] = +{ + LOCAL_SYNC_BYTE, LOCAL_SYNC_BYTE, LOCAL_SYNC_BYTE, LOCAL_SYNC_BYTE, + LOCAL_SYNC_BYTE, LOCAL_SYNC_BYTE, LOCAL_SYNC_BYTE, LOCAL_END_BYTE +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: local_fifo_write + * + * Description: + * Write a data on the write-only FIFO. + * + * Parameters: + * fd File descriptor of write-only FIFO. + * buf Data to send + * len Length of data to send + * + * Return: + * Zero is returned on success; a negated errno value is returned on any + * failure. + * + ****************************************************************************/ + +static int local_fifo_write(int fd, FAR const uint8_t *buf, size_t len) +{ + ssize_t nwritten; + + while (len > 0) + { + nwritten = write(fd, buf, len); + if (nwritten < 0) + { + int errcode = errno; + DEBUGASSERT(errcode > 0); + + if (errcode != EINTR) + { + ndbg("ERROR: Write failed: %d\n", errcode); + return -errcode; + } + + nvdbg("Ignoring signal\n"); + } + else + { + DEBUGASSERT(nwritten > 0 && nwritten <= len); + len -= nwritten; + buf += nwritten; + } + } + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: local_send_packet + * + * Description: + * Send a packet on the write-only FIFO. + * + * Parameters: + * fd File descriptor of write-only FIFO. + * buf Data to send + * len Length of data to send + * + * Return: + * Zero is returned on success; a negated errno value is returned on any + * failure. + * + ****************************************************************************/ + +int local_send_packet(int fd, FAR const uint8_t *buf, size_t len) +{ + uint16_t len16; + int ret; + + /* Send the packet preamble */ + + ret = local_fifo_write(fd, g_preamble, LOCAL_PREAMBLE_SIZE); + if (ret == OK) + { + /* Send the packet length */ + + len16 = len; + ret = local_fifo_write(fd, (FAR const uint8_t *)&len16, sizeof(uint16_t)); + if(ret == OK) + { + /* Send the packet data */ + + ret = local_fifo_write(fd, buf, len); + } + } + + return ret; +} + +#endif /* CONFIG_NET && CONFIG_NET_LOCAL */ diff --git a/nuttx/net/local/local_sendto.c b/nuttx/net/local/local_sendto.c new file mode 100644 index 000000000..a44333d6f --- /dev/null +++ b/nuttx/net/local/local_sendto.c @@ -0,0 +1,84 @@ +/**************************************************************************** + * net/local/local_sendto.c + * + * Copyright (C) 2015 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> +#if defined(CONFIG_NET) && defined(CONFIG_NET_LOCAL) + +#include <sys/types.h> +#include <sys/socket.h> +#include <errno.h> + +#include <nuttx/net/net.h> + +#include "local/local.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: psock_sendto + * + * Description: + * Send a local packet as a datagram. + * + * 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, + * -1 is returned, and errno is set appropriately (see sendto() for the + * list of errno numbers). + * + ****************************************************************************/ + +ssize_t psock_local_sendto(FAR struct socket *psock, FAR const void *buf, + size_t len, int flags, FAR const struct sockaddr *to, + socklen_t tolen) +{ +#warning Missing logic + return -ENOSYS; +} + +#endif /* CONFIG_NET && CONFIG_NET_LOCAL */ diff --git a/nuttx/net/net_initialize.c b/nuttx/net/net_initialize.c index 371b30987..469270577 100644 --- a/nuttx/net/net_initialize.c +++ b/nuttx/net/net_initialize.c @@ -53,6 +53,7 @@ #include "tcp/tcp.h" #include "udp/udp.h" #include "pkt/pkt.h" +#include "local/local.h" #include "igmp/igmp.h" #include "route/route.h" #include "utils/utils.h" @@ -128,6 +129,12 @@ void net_initialize(void) pkt_initialize(); #endif +#ifdef CONFIG_NET_UDP + /* Initialize the local, "Unix domain" socket support */ + + local_initialize(); +#endif + #ifdef CONFIG_NET_TCP /* Initialize the listening port structures */ diff --git a/nuttx/net/netdev/netdev_register.c b/nuttx/net/netdev/netdev_register.c index 1f9ff501e..a1f5c1251 100644 --- a/nuttx/net/netdev/netdev_register.c +++ b/nuttx/net/netdev/netdev_register.c @@ -65,7 +65,7 @@ #if defined(CONFIG_NET_SLIP) # define NETDEV_DEFAULT_FORMAT NETDEV_SLIP_FORMAT -#elif defined(CONFIG_NET_ETHERNET) +#else /* if defined(CONFIG_NET_ETHERNET) */ # define NETDEV_DEFAULT_FORMAT NETDEV_ETH_FORMAT #endif diff --git a/nuttx/net/pkt/pkt.h b/nuttx/net/pkt/pkt.h index 61fd45387..bf50889d5 100644 --- a/nuttx/net/pkt/pkt.h +++ b/nuttx/net/pkt/pkt.h @@ -100,7 +100,7 @@ extern "C" * * Description: * Initialize the packet socket connection structures. Called once and - * only from the UIP layer. + * only from the network initialization logic. * ****************************************************************************/ diff --git a/nuttx/net/pkt/pkt_conn.c b/nuttx/net/pkt/pkt_conn.c index 50a71c0c8..c47eea2d1 100644 --- a/nuttx/net/pkt/pkt_conn.c +++ b/nuttx/net/pkt/pkt_conn.c @@ -71,7 +71,7 @@ static struct pkt_conn_s g_pkt_connections[CONFIG_NET_PKT_CONNS]; static dq_queue_t g_free_pkt_connections; static sem_t g_free_sem; -/* A list of all allocated packet scoket connections */ +/* A list of all allocated packet socket connections */ static dq_queue_t g_active_pkt_connections; @@ -129,6 +129,7 @@ void pkt_initialize(void) for (i = 0; i < CONFIG_NET_PKT_CONNS; i++) { /* Mark the connection closed and move it to the free list */ + g_pkt_connections[i].ifindex = 0; dq_addlast(&g_pkt_connections[i].node, &g_free_pkt_connections); } diff --git a/nuttx/net/socket/Make.defs b/nuttx/net/socket/Make.defs index 44645261a..0859d28a8 100644 --- a/nuttx/net/socket/Make.defs +++ b/nuttx/net/socket/Make.defs @@ -43,6 +43,13 @@ SOCK_CSRCS += net_clone.c net_poll.c net_vfcntl.c ifeq ($(CONFIG_NET_TCP),y) SOCK_CSRCS += send.c listen.c accept.c net_monitor.c +else + +# Local Unix domain support + +ifeq ($(CONFIG_NET_LOCAL),y) +SOCK_CSRCS += send.c listen.c accept.c +endif endif # Socket options diff --git a/nuttx/net/socket/accept.c b/nuttx/net/socket/accept.c index 1a4dbd04c..65a164434 100644 --- a/nuttx/net/socket/accept.c +++ b/nuttx/net/socket/accept.c @@ -38,166 +38,25 @@ ****************************************************************************/ #include <nuttx/config.h> -#if defined(CONFIG_NET) && CONFIG_NSOCKET_DESCRIPTORS > 0 && defined(CONFIG_NET_TCP) +#if defined(CONFIG_NET) && CONFIG_NSOCKET_DESCRIPTORS > 0 && \ + (defined(CONFIG_NET_TCP) || defined(CONFIG_NET_LOCAL)) #include <sys/types.h> #include <sys/socket.h> -#include <semaphore.h> -#include <string.h> #include <errno.h> #include <assert.h> #include <debug.h> -#include <arch/irq.h> - -#include <nuttx/net/net.h> -#include <nuttx/net/ip.h> - #include "tcp/tcp.h" +#include "local/local.h" #include "socket/socket.h" /**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -struct accept_s -{ - FAR struct socket *acpt_sock; /* The accepting socket */ - sem_t acpt_sem; /* Wait for interrupt event */ - FAR struct sockaddr *acpt_addr; /* Return connection address */ - FAR struct tcp_conn_s *acpt_newconn; /* The accepted connection */ - int acpt_result; /* The result of the wait */ -}; - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** - * Function: accept_tcpsender - * - * Description: - * Get the sender's address from the UDP packet - * - * Parameters: - * psock - The state structure of the accepting socket - * conn - The newly accepted TCP connection - * pstate - the recvfrom state structure - * - * Returned Value: - * None - * - * Assumptions: - * Running at the interrupt level -* - ****************************************************************************/ - -#ifdef CONFIG_NET_TCP -static inline void accept_tcpsender(FAR struct socket *psock, - FAR struct tcp_conn_s *conn, - FAR struct sockaddr *addr) -{ - if (addr) - { -#ifdef CONFIG_NET_IPv4 -#ifdef CONFIG_NET_IPv6 - /* If both IPv4 and IPv6 support are enabled, then we will need to - * select which one to use when obtaining the sender's IP address. - */ - - if (psock->s_domain == PF_INET) -#endif /* CONFIG_NET_IPv6 */ - { - FAR struct sockaddr_in *inaddr = (FAR struct sockaddr_in *)addr; - - inaddr->sin_family = AF_INET; - inaddr->sin_port = conn->rport; - net_ipv4addr_copy(inaddr->sin_addr.s_addr, conn->u.ipv4.raddr); - } -#endif /* CONFIG_NET_IPv4 */ - -#ifdef CONFIG_NET_IPv6 -#ifdef CONFIG_NET_IPv4 - /* Otherwise, this the IPv6 address is needed */ - - else -#endif /* CONFIG_NET_IPv4 */ - { - FAR struct sockaddr_in6 *inaddr = (FAR struct sockaddr_in6 *)addr; - - DEBUGASSERT(psock->s_domain == PF_INET6); - inaddr->sin6_family = AF_INET6; - inaddr->sin6_port = conn->rport; - net_ipv6addr_copy(inaddr->sin6_addr.s6_addr, conn->u.ipv6.raddr); - } -#endif /* CONFIG_NET_IPv6 */ - } -} -#endif /* CONFIG_NET_TCP */ - -/**************************************************************************** - * Function: accept_interrupt - * - * Description: - * Receive interrupt level callbacks when connections occur - * - * Parameters: - * listener The conection stucture of the listener - * conn The connection stucture that was just accepted - * - * Returned Value: - * None - * - * Assumptions: - * Running at the interrupt level - * - ****************************************************************************/ - -static int accept_interrupt(FAR struct tcp_conn_s *listener, - FAR struct tcp_conn_s *conn) -{ - struct accept_s *pstate = (struct accept_s *)listener->accept_private; - int ret = -EINVAL; - - if (pstate) - { - /* Get the connection address */ - - accept_tcpsender(pstate->acpt_sock, conn, pstate->acpt_addr); - - /* Save the connection structure */ - - pstate->acpt_newconn = conn; - pstate->acpt_result = OK; - - /* There should be a reference of one on the new connection */ - - DEBUGASSERT(conn->crefs == 1); - - /* Wake-up the waiting caller thread */ - - sem_post(&pstate->acpt_sem); - - /* Stop any further callbacks */ - - listener->accept_private = NULL; - listener->accept = NULL; - ret = OK; - } - - return ret; -} - -/**************************************************************************** * Public Functions ****************************************************************************/ @@ -229,7 +88,7 @@ static int accept_interrupt(FAR struct tcp_conn_s *listener, * connections are present on the queue, accept returns EAGAIN. * * Parameters: - * sockfd The listening socket descriptior + * sockfd The listening socket descriptor * addr Receives the address of the connecting client * addrlen Input: allocated size of 'addr', Return: returned size of 'addr' * @@ -275,9 +134,6 @@ int accept(int sockfd, FAR struct sockaddr *addr, FAR socklen_t *addrlen) { FAR struct socket *psock = sockfd_socket(sockfd); FAR struct socket *pnewsock; - FAR struct tcp_conn_s *conn; - struct accept_s state; - net_lock_t save; int newfd; int err; int ret; @@ -327,6 +183,12 @@ int accept(int sockfd, FAR struct sockaddr *addr, FAR socklen_t *addrlen) if (addr) { + /* If an address is provided, then the lenght must also be provided. */ + + DEBUGASSERT(addrlen); + + /* A valid length depends on the address domain */ + switch (psock->s_domain) { #ifdef CONFIG_NET_IPv4 @@ -353,6 +215,18 @@ int accept(int sockfd, FAR struct sockaddr *addr, FAR socklen_t *addrlen) break; #endif /* CONFIG_NET_IPv6 */ +#ifdef CONFIG_NET_LOCAL + case PF_LOCAL: + { + if (*addrlen < sizeof(sa_family_t)) + { + err = EBADF; + goto errout; + } + } + break; +#endif /* CONFIG_NET_IPv6 */ + default: DEBUGPANIC(); err = EINVAL; @@ -378,132 +252,60 @@ int accept(int sockfd, FAR struct sockaddr *addr, FAR socklen_t *addrlen) goto errout_with_socket; } - /* Check the backlog to see if there is a connection already pending for - * this listener. - */ + /* Initialize the socket structure and mark the socket as connected. */ - save = net_lock(); - conn = (struct tcp_conn_s *)psock->s_conn; - -#ifdef CONFIG_NET_TCPBACKLOG - state.acpt_newconn = tcp_backlogremove(conn); - if (state.acpt_newconn) - { - /* Yes... get the address of the connected client */ - - nvdbg("Pending conn=%p\n", state.acpt_newconn); - accept_tcpsender(psock, state.acpt_newconn, addr); - } + pnewsock->s_domain = psock->s_domain; + pnewsock->s_type = SOCK_STREAM; + pnewsock->s_flags |= _SF_CONNECTED; + pnewsock->s_flags &= ~_SF_CLOSED; - /* In general, this uIP-based implementation will not support non-blocking - * socket operations... except in a few cases: Here for TCP accept with backlog - * enabled. If this socket is configured as non-blocking then return EAGAIN - * if there is no pending connection in the backlog. - */ + /* Perform the correct accept operation for this address domain */ - else if (_SS_ISNONBLOCK(psock->s_flags)) - { - err = EAGAIN; - goto errout_with_lock; - } - else +#ifdef CONFIG_NET_LOCAL +#ifdef CONFIG_NET_TCP + if (psock->s_domain == PF_LOCAL) #endif { - /* Set the socket state to accepting */ - - psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_ACCEPT); - - /* Perform the TCP accept operation */ - - /* Initialize the state structure. This is done with interrupts - * disabled because we don't want anything to happen until we - * are ready. - */ + /* Perform the local accept operation (with the network unlocked) */ - state.acpt_sock = psock; - state.acpt_addr = addr; - state.acpt_newconn = NULL; - state.acpt_result = OK; - sem_init(&state.acpt_sem, 0, 0); - - /* Set up the callback in the connection */ - - conn->accept_private = (void*)&state; - conn->accept = accept_interrupt; - - /* Wait for the send to complete or an error to occur: NOTES: (1) - * net_lockedwait will also terminate if a signal is received, (2) - * interrupts may be disabled! They will be re-enabled while the - * task sleeps and automatically re-enabled when the task restarts. - */ - - ret = net_lockedwait(&state.acpt_sem); + ret = psock_local_accept(psock, addr, addrlen, &pnewsock->s_conn); if (ret < 0) { - /* The value returned by net_lockedwait() the same as the value - * returned by sem_wait(): Zero (OK) is returned on success; -1 - * (ERROR) is returned on a failure with the errno value set - * appropriately. - * - * We have to preserve the errno value here because it may be - * altered by intervening operations. - */ - - err = get_errno(); + err = -ret; + goto errout_with_socket; } + } +#endif /* CONFIG_NET_LOCAL */ - /* Make sure that no further interrupts are processed */ - - conn->accept_private = NULL; - conn->accept = NULL; - - sem_destroy(&state. acpt_sem); - - /* Set the socket state to idle */ - - psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); +#ifdef CONFIG_NET_TCP +#ifdef CONFIG_NET_LOCAL + else +#endif + { + net_lock_t state; - /* Check for a errors. Errors are signalled by negative errno values - * for the send length. - */ + /* Perform the local accept operation (with the network locked) */ - if (state.acpt_result != 0) + state = net_lock(); + ret = psock_tcp_accept(psock, addr, addrlen, &pnewsock->s_conn); + if (ret < 0) { - err = state.acpt_result; - goto errout_with_lock; + net_unlock(state); + err = -ret; + goto errout_with_socket; } - /* If net_lockedwait failed, then we were probably reawakened by a - * signal. In this case, logic above will have set 'err' to the - * ernno value returned by net_lockedwait(). + /* Begin monitoring for TCP connection events on the newly connected + * socket */ - if (ret < 0) - { - goto errout_with_lock; - } + net_startmonitor(pnewsock); + net_unlock(state); } +#endif /* CONFIG_NET_TCP */ - /* Initialize the socket structure and mark the socket as connected. - * (The reference count on the new connection structure was set in the - * interrupt handler). - */ - - pnewsock->s_domain = psock->s_domain; - pnewsock->s_type = SOCK_STREAM; - pnewsock->s_conn = state.acpt_newconn; - pnewsock->s_flags |= _SF_CONNECTED; - pnewsock->s_flags &= ~_SF_CLOSED; - - /* Begin monitoring for TCP connection events on the newly connected socket */ - - net_startmonitor(pnewsock); - net_unlock(save); return newfd; -errout_with_lock: - net_unlock(save); - errout_with_socket: sockfd_release(newfd); @@ -512,4 +314,4 @@ errout: return ERROR; } -#endif /* CONFIG_NET && CONFIG_NSOCKET_DESCRIPTORS && CONFIG_NET_TCP */ +#endif /* CONFIG_NET && CONFIG_NSOCKET_DESCRIPTORS && (CONFIG_NET_TCP || CONFIG_NET_LOCAL) */ diff --git a/nuttx/net/socket/bind.c b/nuttx/net/socket/bind.c index d905e5aaf..6407c0add 100644 --- a/nuttx/net/socket/bind.c +++ b/nuttx/net/socket/bind.c @@ -1,7 +1,7 @@ /**************************************************************************** * net/socket/bind.c * - * Copyright (C) 2007-2009, 2012, 2014 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2012, 2014-2015 Gregory Nutt. All rights reserved. * Author: Gregory Nutt <gnutt@nuttx.org> * * Redistribution and use in source and binary forms, with or without @@ -42,6 +42,7 @@ #include <sys/types.h> #include <sys/socket.h> +#include <sys/un.h> #include <errno.h> #include <string.h> #include <debug.h> @@ -58,6 +59,7 @@ #include "tcp/tcp.h" #include "udp/udp.h" #include "pkt/pkt.h" +#include "local/local.h" /**************************************************************************** * Private Functions @@ -116,8 +118,8 @@ static int pkt_bind(FAR struct pkt_conn_s *conn, * * Description: * 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 + * '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: @@ -175,6 +177,12 @@ int psock_bind(FAR struct socket *psock, const struct sockaddr *addr, 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); @@ -204,18 +212,87 @@ int psock_bind(FAR struct socket *psock, const struct sockaddr *addr, break; #endif -#ifdef CONFIG_NET_TCP + /* 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) case SOCK_STREAM: - ret = tcp_bind(psock->s_conn, addr); - psock->s_flags |= _SF_BOUND; + { +#ifdef CONFIG_NET_LOCAL +#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 */ + +#ifdef CONFIG_NET_TCP +#ifdef CONFIG_NET_LOCAL + else +#endif + { + /* Bind the TCP/IP connection structure */ + + ret = tcp_bind(psock->s_conn, addr); + } +#endif /* CONFIG_NET_TCP */ + + /* Mark the socket bound */ + + if (ret >= 0) + { + psock->s_flags |= _SF_BOUND; + } + } break; +#endif /* CONFIG_NET_TCP || CONFIG_NET_LOCAL */ + + /* 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) + case SOCK_DGRAM: + { +#ifdef CONFIG_NET_LOCAL +#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 */ #ifdef CONFIG_NET_UDP - case SOCK_DGRAM: - ret = udp_bind(psock->s_conn, addr); - break; +#ifdef CONFIG_NET_LOCAL + else #endif + { + /* Bind the UDPP/IP connection structure */ + + ret = udp_bind(psock->s_conn, addr); + } +#endif /* CONFIG_NET_UDP */ + + /* Mark the socket bound */ + + if (ret >= 0) + { + psock->s_flags |= _SF_BOUND; + } + } + break; +#endif /* CONFIG_NET_UDP || CONFIG_NET_LOCAL */ default: err = EBADF; diff --git a/nuttx/net/socket/connect.c b/nuttx/net/socket/connect.c index e152df888..9830fa55e 100644 --- a/nuttx/net/socket/connect.c +++ b/nuttx/net/socket/connect.c @@ -1,7 +1,7 @@ /**************************************************************************** * net/socket/connect.c * - * Copyright (C) 2007-2012 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2012, 2015 Gregory Nutt. All rights reserved. * Author: Gregory Nutt <gnutt@nuttx.org> * * Redistribution and use in source and binary forms, with or without @@ -45,6 +45,7 @@ #include <stdint.h> #include <errno.h> +#include <assert.h> #include <debug.h> #include <arch/irq.h> @@ -56,6 +57,7 @@ #include "devif/devif.h" #include "tcp/tcp.h" #include "udp/udp.h" +#include "local/local.h" #include "socket/socket.h" /**************************************************************************** @@ -460,7 +462,7 @@ 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) +#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_UDP) || defined(CONFIG_NET_LOCAL) int ret; #endif int err; @@ -501,6 +503,18 @@ int psock_connect(FAR struct socket *psock, FAR const struct sockaddr *addr, break; #endif +#ifdef CONFIG_NET_LOCAL + case AF_LOCAL: + { + if (addrlen < sizeof(sa_family_t)) + { + err = EBADF; + goto errout; + } + } + break; +#endif + default: DEBUGPANIC(); err = EAFNOSUPPORT; @@ -511,7 +525,7 @@ int psock_connect(FAR struct socket *psock, FAR const struct sockaddr *addr, switch (psock->s_type) { -#ifdef CONFIG_NET_TCP +#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_LOCAL) case SOCK_STREAM: { /* Verify that the socket is not already connected */ @@ -522,9 +536,30 @@ int psock_connect(FAR struct socket *psock, FAR const struct sockaddr *addr, goto errout; } - /* Its not ... connect it */ + /* It's not ... connect it */ + +#ifdef CONFIG_NET_LOCAL +#ifdef CONFIG_NET_TCP + if (psock->s_domain == PF_LOCAL) +#endif + { + /* Connect to the local Unix domain server */ + + ret = local_connect(psock->s_conn, addr); + } +#endif /* CONFIG_NET_LOCAL */ + +#ifdef CONFIG_NET_TCP +#ifdef CONFIG_NET_LOCAL + else +#endif + { + /* Connect the TCP/IP socket */ + + ret = psock_tcp_connect(psock, addr); + } +#endif /* CONFIG_NET_TCP */ - ret = psock_tcp_connect(psock, addr); if (ret < 0) { err = -ret; @@ -532,12 +567,31 @@ int psock_connect(FAR struct socket *psock, FAR const struct sockaddr *addr, } } break; -#endif +#endif /* CONFIG_NET_TCP || CONFIG_NET_LOCAL */ -#ifdef CONFIG_NET_UDP +#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_LOCAL) case SOCK_DGRAM: { - ret = udp_connect(psock->s_conn, addr); +#ifdef CONFIG_NET_LOCAL +#ifdef CONFIG_NET_UDP + if (psock->s_domain == PF_LOCAL) +#endif + { + /* Perform the datagram connection logic */ + + ret = local_connect(psock->s_conn, addr); + } +#endif /* CONFIG_NET_LOCAL */ + +#ifdef CONFIG_NET_UDP +#ifdef CONFIG_NET_LOCAL + else +#endif + { + ret = udp_connect(psock->s_conn, addr); + } +#endif /* CONFIG_NET_UDP */ + if (ret < 0) { err = -ret; @@ -545,7 +599,7 @@ int psock_connect(FAR struct socket *psock, FAR const struct sockaddr *addr, } } break; -#endif +#endif /* CONFIG_NET_UDP || CONFIG_NET_LOCAL */ default: err = EBADF; diff --git a/nuttx/net/socket/listen.c b/nuttx/net/socket/listen.c index b9b8d1d5b..cdfc4d9d8 100644 --- a/nuttx/net/socket/listen.c +++ b/nuttx/net/socket/listen.c @@ -1,7 +1,7 @@ /**************************************************************************** * net/socket/listen.c * - * Copyright (C) 2007-2009 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2015 Gregory Nutt. All rights reserved. * Author: Gregory Nutt <gnutt@nuttx.org> * * Redistribution and use in source and binary forms, with or without @@ -45,6 +45,7 @@ #include <debug.h> #include "tcp/tcp.h" +#include "local/local.h" #include "socket/socket.h" /**************************************************************************** @@ -89,7 +90,6 @@ int listen(int sockfd, int backlog) { FAR struct socket *psock = sockfd_socket(sockfd); - struct tcp_conn_s *conn; int err; /* Verify that the sockfd corresponds to valid, allocated socket */ @@ -111,39 +111,73 @@ int listen(int sockfd, int backlog) { err = EBADF; } + goto errout; } /* Verify that the sockfd corresponds to a connected SOCK_STREAM */ - conn = (FAR struct tcp_conn_s *)psock->s_conn; - if (psock->s_type != SOCK_STREAM || !psock->s_conn || conn->lport <= 0) + if (psock->s_type != SOCK_STREAM || !psock->s_conn) { err = EOPNOTSUPP; goto errout; } - /* Set up the backlog for this connection */ - -#ifdef CONFIG_NET_TCPBACKLOG - err = tcp_backlogcreate(conn, backlog); - if (err < 0) +#ifdef CONFIG_NET_LOCAL +#ifdef CONFIG_NET_TCP + if (psock->s_domain == PF_LOCAL) +#endif { - err = -err; - goto errout; + FAR struct local_conn_s *conn = + (FAR struct local_conn_s *)psock->s_conn; + + err = local_listen(conn, backlog); + if (err < 0) + { + err = -err; + goto errout; + } } +#endif /* CONFIG_NET_LOCAL */ + +#ifdef CONFIG_NET_TCP +#ifdef CONFIG_NET_LOCAL + else +#endif + { + FAR struct tcp_conn_s *conn = + (FAR struct tcp_conn_s *)psock->s_conn; + + if (conn->lport <= 0) + { + err = EOPNOTSUPP; + goto errout; + } + + /* Set up the backlog for this connection */ + +#ifdef CONFIG_NET_TCPBACKLOG + err = tcp_backlogcreate(conn, backlog); + if (err < 0) + { + err = -err; + goto errout; + } #endif - /* Start listening to the bound port. This enables callbacks when accept() - * is called and enables poll()/select() logic. - */ + /* Start listening to the bound port. This enables callbacks when + * accept() is called and enables poll()/select() logic. + */ + + tcp_listen(conn); + } +#endif /* CONFIG_NET_TCP */ - tcp_listen(conn); psock->s_flags |= _SF_LISTENING; return OK; errout: - errno = err; + set_errno(err); return ERROR; } diff --git a/nuttx/net/socket/net_close.c b/nuttx/net/socket/net_close.c index a2ef7e91f..e33853fa7 100644 --- a/nuttx/net/socket/net_close.c +++ b/nuttx/net/socket/net_close.c @@ -63,6 +63,7 @@ #include "tcp/tcp.h" #include "udp/udp.h" #include "pkt/pkt.h" +#include "local/local.h" #include "socket/socket.h" /**************************************************************************** @@ -452,6 +453,45 @@ static inline int netclose_disconnect(FAR struct socket *psock) #endif /* CONFIG_NET_TCP */ /**************************************************************************** + * Function: 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 */ + +/**************************************************************************** * Public Functions ****************************************************************************/ @@ -493,71 +533,110 @@ int psock_close(FAR struct socket *psock) switch (psock->s_type) { -#ifdef CONFIG_NET_PKT - case SOCK_RAW: +#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_LOCAL) + case SOCK_STREAM: { - 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) +#ifdef CONFIG_NET_LOCAL +#ifdef CONFIG_NET_TCP + if (psock->s_domain == PF_LOCAL) +#endif { - /* Yes... free the connection structure */ + /* Release our reference to the local connection structure */ - conn->crefs = 0; /* No more references on the connection */ - pkt_free(psock->s_conn); /* Free uIP resources */ + local_close(psock); } +#endif /* CONFIG_NET_LOCAL */ + +#ifdef CONFIG_NET_TCP +#ifdef CONFIG_NET_LOCAL else +#endif { - /* No.. Just decrement the reference count */ + FAR struct tcp_conn_s *conn = psock->s_conn; - conn->crefs--; + /* 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 */ + + err = netclose_disconnect(psock); + if (err < 0) + { + /* This would normally occur only if there is a + * timeout from a lingering close. + */ + + goto errout_with_psock; + } + } + else + { + /* No.. Just decrement the reference count */ + + conn->crefs--; + } } +#endif /* CONFIG_NET_TCP */ } break; #endif -#ifdef CONFIG_NET_TCP - case SOCK_STREAM: +#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_LOCAL) + case SOCK_DGRAM: { - FAR struct tcp_conn_s *conn = psock->s_conn; +#ifdef CONFIG_NET_LOCAL +#ifdef CONFIG_NET_UDP + if (psock->s_domain == PF_LOCAL) +#endif + { + /* Release our reference to the local connection structure */ - /* Is this the last reference to the connection structure (there - * could be more if the socket was dup'ed). - */ + local_close(psock); + } +#endif /* CONFIG_NET_LOCAL */ - if (conn->crefs <= 1) +#ifdef CONFIG_NET_UDP +#ifdef CONFIG_NET_LOCAL + else +#endif { - /* Yes... then perform the disconnection now */ + 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). + */ - tcp_unlisten(conn); /* No longer accepting connections */ - conn->crefs = 0; /* Discard our reference to the connection */ - err = netclose_disconnect(psock); /* Break any current connections */ - if (err < 0) + if (conn->crefs <= 1) { - /* This would normally occur only if there is a timeout - * from a lingering close. - */ + /* Yes... free the connection structure */ - goto errout_with_psock; + conn->crefs = 0; + udp_free(psock->s_conn); } - } - else - { - /* No.. Just decrement the reference count */ + else + { + /* No.. Just decrement the reference count */ - conn->crefs--; + conn->crefs--; + } } +#endif /* CONFIG_NET_UDP */ } break; #endif -#ifdef CONFIG_NET_UDP - case SOCK_DGRAM: +#ifdef CONFIG_NET_PKT + case SOCK_RAW: { - FAR struct udp_conn_s *conn = psock->s_conn; + 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). @@ -568,7 +647,7 @@ int psock_close(FAR struct socket *psock) /* Yes... free the connection structure */ conn->crefs = 0; /* No more references on the connection */ - udp_free(psock->s_conn); /* Free uIP resources */ + pkt_free(psock->s_conn); /* Free uIP resources */ } else { diff --git a/nuttx/net/socket/recvfrom.c b/nuttx/net/socket/recvfrom.c index e8994ff01..8e38d7881 100644 --- a/nuttx/net/socket/recvfrom.c +++ b/nuttx/net/socket/recvfrom.c @@ -68,6 +68,7 @@ #include "tcp/tcp.h" #include "udp/udp.h" #include "pkt/pkt.h" +#include "local/local.h" #include "socket/socket.h" /**************************************************************************** @@ -1580,7 +1581,7 @@ static ssize_t tcp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, ****************************************************************************/ ssize_t psock_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, - int flags,FAR struct sockaddr *from, + int flags, FAR struct sockaddr *from, FAR socklen_t *fromlen) { ssize_t ret; @@ -1614,23 +1615,37 @@ ssize_t psock_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, /* Get the minimum socket length */ + switch (psock->s_domain) + { #ifdef CONFIG_NET_IPv4 -#ifdef CONFIG_NET_IPv6 - if (psock->s_domain == PF_INET) + case PF_INET: + { + minlen = sizeof(struct sockaddr_in); + } + break; #endif - { - minlen = sizeof(struct sockaddr_in); - } -#endif /*CONFIG_NET_IPv4 */ #ifdef CONFIG_NET_IPv6 -#ifdef CONFIG_NET_IPv4 - else + case PF_INET6: + { + minlen = sizeof(struct sockaddr_in6); + } + break; #endif - { - minlen = sizeof(struct sockaddr_in6); + +#ifdef CONFIG_NET_LOCAL + case PF_LOCAL: + { + minlen = sizeof(sa_family_t); + } + break; +#endif + + default: + DEBUGPANIC(); + err = EINVAL; + goto errout; } -#endif /*CONFIG_NET_IPv6 */ if (*fromlen < minlen) { @@ -1646,30 +1661,72 @@ ssize_t psock_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, /* Read from the network interface driver buffer */ /* Or perform the TCP/IP or UDP recv() operation */ -#if defined(CONFIG_NET_PKT) - if (psock->s_type == SOCK_RAW) + switch (psock->s_type) { - ret = pkt_recvfrom(psock, buf, len, from); - } - else +#ifdef CONFIG_NET_PKT + case SOCK_RAW: + { + ret = pkt_recvfrom(psock, buf, len, from); + } + break; +#endif /* CONFIG_NET_PKT */ + +#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_LOCAL) + case SOCK_STREAM: + { +#ifdef CONFIG_NET_LOCAL +#ifdef CONFIG_NET_TCP + if (psock->s_domain == PF_LOCAL) #endif -#if defined(CONFIG_NET_TCP) - if (psock->s_type == SOCK_STREAM) - { - ret = tcp_recvfrom(psock, buf, len, from); - } - else + { + ret = psock_local_recvfrom(psock, buf, len, flags, + from, fromlen); + } +#endif /* CONFIG_NET_LOCAL */ + +#ifdef CONFIG_NET_TCP +#ifdef CONFIG_NET_LOCAL + else #endif -#if defined(CONFIG_NET_UDP) - if (psock->s_type == SOCK_DGRAM) - { - ret = udp_recvfrom(psock, buf, len, from); - } - else + { + ret = tcp_recvfrom(psock, buf, len, from); + } +#endif /* CONFIG_NET_TCP */ + } + break; +#endif /* CONFIG_NET_TCP || CONFIG_NET_LOCAL */ + +#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_LOCAL) + case SOCK_DGRAM: + { +#ifdef CONFIG_NET_LOCAL +#ifdef CONFIG_NET_UDP + if (psock->s_domain == PF_LOCAL) #endif - { - ndbg("ERROR: Unsupported socket type: %d\n", psock->s_type); - ret = -ENOSYS; + { + ret = psock_local_recvfrom(psock, buf, len, flags, + from, fromlen); + } +#endif /* CONFIG_NET_LOCAL */ + +#ifdef CONFIG_NET_UDP +#ifdef CONFIG_NET_LOCAL + else +#endif + { + ret = udp_recvfrom(psock, buf, len, from); + } +#endif /* CONFIG_NET_UDP */ + } + break; +#endif /* CONFIG_NET_UDP || CONFIG_NET_LOCAL */ + + default: + { + ndbg("ERROR: Unsupported socket type: %d\n", psock->s_type); + ret = -ENOSYS; + } + break; } /* Set the socket state to idle */ diff --git a/nuttx/net/socket/send.c b/nuttx/net/socket/send.c index 1b7358481..ddcc97ea3 100644 --- a/nuttx/net/socket/send.c +++ b/nuttx/net/socket/send.c @@ -45,6 +45,7 @@ #include "tcp/tcp.h" #include "pkt/pkt.h" +#include "local/local.h" #include "socket/socket.h" /**************************************************************************** @@ -138,17 +139,31 @@ ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len, case SOCK_RAW: { ret = psock_pkt_send(psock, buf, len); - break; } + break; #endif -#if defined(CONFIG_NET_TCP) case SOCK_STREAM: { - ret = psock_tcp_send(psock, buf, len); - break; - } +#ifdef CONFIG_NET_LOCAL +#ifdef CONFIG_NET_TCP + if (psock->s_domain == PF_LOCAL) +#endif + { + ret = psock_local_send(psock, buf, len, flags); + } +#endif /* CONFIG_NET_LOCAL */ + +#ifdef CONFIG_NET_TCP +#ifdef CONFIG_NET_LOCAL + else #endif + { + ret = psock_tcp_send(psock, buf, len); + } +#endif /* CONFIG_NET_TCP */ + } + break; default: { diff --git a/nuttx/net/socket/sendto.c b/nuttx/net/socket/sendto.c index 0134bde3c..85ce83f31 100644 --- a/nuttx/net/socket/sendto.c +++ b/nuttx/net/socket/sendto.c @@ -467,6 +467,12 @@ ssize_t psock_sendto(FAR struct socket *psock, FAR const void *buf, break; #endif +#ifdef CONFIG_NET_IPv6 + case AF_LOCAL: + minlen = sizeof(sa_family_t); + break; +#endif + default: ndbg("ERROR: Unrecognized address family: %d\n", to->sa_family); err = EAFNOSUPPORT; @@ -511,9 +517,13 @@ ssize_t psock_sendto(FAR struct socket *psock, FAR const void *buf, } #endif - /* Perform the UDP sendto operation */ +#ifdef CONFIG_NET_LOCAL + /* Perform the Unix domain sendto operation */ +# warning Missing logic +#endif #ifdef CONFIG_NET_UDP + /* Perform the UDP sendto operation */ /* Set the socket state to sending */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND); diff --git a/nuttx/net/socket/socket.c b/nuttx/net/socket/socket.c index 1ce2e0890..7cec99427 100644 --- a/nuttx/net/socket/socket.c +++ b/nuttx/net/socket/socket.c @@ -51,6 +51,153 @@ #include "tcp/tcp.h" #include "udp/udp.h" #include "pkt/pkt.h" +#include "local/local.h" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: psock_tcp_alloc + * + * Description: + * Allocate and attach a TCP connection structure. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_TCP +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 /* CONFIG_NET_TCP */ + +/**************************************************************************** + * Name: psock_udp_alloc + * + * Description: + * Allocate and attach a UDP connection structure. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_UDP +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 /* CONFIG_NET_UDP */ + +/**************************************************************************** + * 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 */ /**************************************************************************** * Public Functions @@ -96,7 +243,11 @@ 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; int err; /* Only PF_INET, PF_INET6 or PF_PACKET domains supported */ @@ -105,13 +256,25 @@ int psock_socket(int domain, int type, int protocol, FAR struct socket *psock) { #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 @@ -129,31 +292,71 @@ int psock_socket(int domain, int type, int protocol, FAR struct socket *psock) switch (type) { -#ifdef CONFIG_NET_TCP +#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_LOCAL) case SOCK_STREAM: - if ((protocol != 0 && protocol != IPPROTO_TCP) || !ipdomain) +#ifdef CONFIG_NET_TCP +#ifdef CONFIG_NET_LOCAL + if (ipdomain) +#endif { - err = EPROTONOSUPPORT; - goto errout; + if ((protocol != 0 && protocol != IPPROTO_TCP) || !dgramok) + { + err = EPROTONOSUPPORT; + goto errout; + } + } +#endif /* CONFIG_NET_TCP */ + +#ifdef CONFIG_NET_LOCAL +#ifdef CONFIG_NET_TCP + else +#endif + { + if (protocol != 0 || !dgramok) + { + err = EPROTONOSUPPORT; + goto errout; + } } +#endif /* CONFIG_NET_LOCAL */ break; +#endif /* CONFIG_NET_TCP || CONFIG_NET_LOCAL */ + +#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_LOCAL) + case SOCK_DGRAM: +#ifdef CONFIG_NET_UDP +#ifdef CONFIG_NET_LOCAL + if (ipdomain) #endif + { + if ((protocol != 0 && protocol != IPPROTO_UDP) || !dgramok) + { + err = EPROTONOSUPPORT; + goto errout; + } + } +#endif /* CONFIG_NET_UDP */ +#ifdef CONFIG_NET_LOCAL #ifdef CONFIG_NET_UDP - case SOCK_DGRAM: - if ((protocol != 0 && protocol != IPPROTO_UDP) || !ipdomain) + else +#endif { - err = EPROTONOSUPPORT; - goto errout; + if (protocol != 0 || !dgramok) + { + err = EPROTONOSUPPORT; + goto errout; + } } +#endif /* CONFIG_NET_LOCAL */ break; -#endif +#endif /* CONFIG_NET_UDP || CONFIG_NET_LOCAL */ #ifdef CONFIG_NET_PKT case SOCK_RAW: - if (ipdomain) + if (dgramok) { err = EPROTONOSUPPORT; goto errout; @@ -185,56 +388,78 @@ int psock_socket(int domain, int type, int protocol, FAR struct socket *psock) err = ENOMEM; /* Assume failure to allocate connection instance */ switch (type) { -#ifdef CONFIG_NET_TCP +#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_LOCAL) case SOCK_STREAM: { - /* Allocate the TCP connection structure and save in the new - * socket instance. - */ +#ifdef CONFIG_NET_TCP +#ifdef CONFIG_NET_LOCAL + if (ipdomain) +#endif + { + /* Allocate and attach the TCP connection structure */ + + ret = psock_tcp_alloc(psock); + } +#endif /* CONFIG_NET_TCP */ - FAR struct tcp_conn_s *conn = tcp_alloc(domain); - if (!conn) +#ifdef CONFIG_NET_LOCAL +#ifdef CONFIG_NET_TCP + else +#endif { - /* Failed to reserve a connection structure */ + /* Allocate and attach the local connection structure */ - goto errout; /* With err == ENFILE or ENOMEM */ + ret = psock_local_alloc(psock); } +#endif /* CONFIG_NET_LOCAL */ - /* Set the reference count on the connection structure. This - * reference count will be increment only if the socket is - * dup'ed - */ + /* Check for failures to allocate the connection structure. */ - DEBUGASSERT(conn->crefs == 0); - psock->s_conn = conn; - conn->crefs = 1; + if (ret < 0) + { + /* Failed to reserve a connection structure */ + + err = -ret; + goto errout; + } } break; #endif -#ifdef CONFIG_NET_UDP +#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_LOCAL) case SOCK_DGRAM: { - /* Allocate the UDP connection structure and save in the new - * socket instance. - */ +#ifdef CONFIG_NET_UDP +#ifdef CONFIG_NET_LOCAL + if (ipdomain) +#endif + { + /* Allocate and attach the UDP connection structure */ - FAR struct udp_conn_s *conn = udp_alloc(domain); - if (!conn) + ret = psock_udp_alloc(psock); + } +#endif /* CONFIG_NET_UDP */ + +#ifdef CONFIG_NET_LOCAL +#ifdef CONFIG_NET_UDP + else +#endif { - /* Failed to reserve a connection structure */ + /* Allocate and attach the local connection structure */ - goto errout; /* With err == ENFILE or ENOMEM */ + ret = psock_local_alloc(psock); } +#endif /* CONFIG_NET_LOCAL */ - /* Set the reference count on the connection structure. This - * reference count will be increment only if the socket is - * dup'ed - */ + /* Check for failures to allocate the connection structure. */ - DEBUGASSERT(conn->crefs == 0); - psock->s_conn = conn; - conn->crefs = 1; + if (ret < 0) + { + /* Failed to reserve a connection structure */ + + err = -ret; + goto errout; + } } break; #endif @@ -242,26 +467,14 @@ int psock_socket(int domain, int type, int protocol, FAR struct socket *psock) #ifdef CONFIG_NET_PKT case SOCK_RAW: { - /* Allocate the packet socket connection structure and save - * in the new socket instance. - */ - - FAR struct pkt_conn_s *conn = pkt_alloc(); - if (!conn) + ret = psock_pkt_alloc(FAR struct socket *psock) + if (ret < 0) { /* Failed to reserve a connection structure */ + err = -ret; goto errout; } - - /* Set the reference count on the connection structure. This - * reference count will be increment only if the socket is - * dup'ed - */ - - DEBUGASSERT(conn->crefs == 0); - psock->s_conn = conn; - conn->crefs = 1; } break; #endif diff --git a/nuttx/net/tcp/Make.defs b/nuttx/net/tcp/Make.defs index d213960b7..41a03469e 100644 --- a/nuttx/net/tcp/Make.defs +++ b/nuttx/net/tcp/Make.defs @@ -39,6 +39,8 @@ ifeq ($(CONFIG_NET_TCP),y) # Socket layer +SOCK_CSRCS += tcp_accept.c + ifeq ($(CONFIG_NET_TCP_WRITE_BUFFERS),y) SOCK_CSRCS += tcp_send_buffered.c else diff --git a/nuttx/net/tcp/tcp.h b/nuttx/net/tcp/tcp.h index 1d6e78e8c..010b00989 100644 --- a/nuttx/net/tcp/tcp.h +++ b/nuttx/net/tcp/tcp.h @@ -267,9 +267,8 @@ extern "C" * Public Function Prototypes ****************************************************************************/ -/* Defined in tcp_conn.c ****************************************************/ - -struct sockaddr; /* Forward reference */ +struct sockaddr; /* Forward reference */ +struct socket; /* Forward reference */ /**************************************************************************** * Name: tcp_initialize @@ -389,7 +388,6 @@ int tcp_bind(FAR struct tcp_conn_s *conn, FAR const struct sockaddr *addr); int tcp_connect(FAR struct tcp_conn_s *conn, FAR const struct sockaddr *addr); -/* Defined in tcp_ipselect.c ************************************************/ /**************************************************************************** * Function: tcp_ipv4_select * @@ -414,7 +412,6 @@ void tcp_ipv4_select(FAR struct net_driver_s *dev); void tcp_ipv6_select(FAR struct net_driver_s *dev); #endif -/* Defined in tcp_seqno.c ***************************************************/ /**************************************************************************** * Name: tcp_setsequence * @@ -481,7 +478,6 @@ void tcp_initsequence(FAR uint8_t *seqno); void tcp_nextsequence(void); -/* Defined in tcp_poll.c ****************************************************/ /**************************************************************************** * Name: tcp_poll * @@ -502,7 +498,6 @@ void tcp_nextsequence(void); void tcp_poll(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn); -/* Defined in tcp_timer.c ***************************************************/ /**************************************************************************** * Name: tcp_timer * @@ -525,7 +520,6 @@ void tcp_poll(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn); void tcp_timer(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn, int hsec); -/* Defined in tcp_listen.c **************************************************/ /**************************************************************************** * Function: tcp_listen_initialize * @@ -593,7 +587,6 @@ bool tcp_islistener(uint16_t portno); int tcp_accept_connection(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn, uint16_t portno); -/* Defined in tcp_send.c ****************************************************/ /**************************************************************************** * Name: tcp_send * @@ -658,7 +651,6 @@ void tcp_reset(FAR struct net_driver_s *dev); void tcp_ack(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn, uint8_t ack); -/* Defined in tcp_appsend.c *************************************************/ /**************************************************************************** * Name: tcp_appsend * @@ -705,7 +697,6 @@ void tcp_appsend(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn, void tcp_rexmit(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn, uint16_t result); -/* Defined in tcp_input.c ***************************************************/ /**************************************************************************** * Name: tcp_ipv4_input * @@ -748,7 +739,6 @@ void tcp_ipv4_input(FAR struct net_driver_s *dev); void tcp_ipv6_input(FAR struct net_driver_s *dev); #endif -/* Defined in tcp_callback.c ************************************************/ /**************************************************************************** * Function: tcp_callback * @@ -794,7 +784,6 @@ uint16_t tcp_datahandler(FAR struct tcp_conn_s *conn, FAR uint8_t *buffer, uint16_t nbytes); #endif -/* Defined in tcp_backlog.c *************************************************/ /**************************************************************************** * Function: tcp_backlogcreate * @@ -910,7 +899,32 @@ int tcp_backlogdelete(FAR struct tcp_conn_s *conn, # define tcp_backlogdelete(c,b) (-ENOSYS) #endif -/* Defined in tcp_send_buffered.c or tcp_send_unbuffered.c ******************/ +/**************************************************************************** + * Function: tcp_accept + * + * Description: + * This function implements accept() for TCP/IP sockets. See the + * description of accept() for further information. + * + * Parameters: + * psock The listening TCP socket structure + * addr Receives the address of the connecting client + * addrlen Input: allocated size of 'addr', Return: returned size of 'addr' + * newconn The new, accepted TCP connection structure + * + * Returned Value: + * Returns zero (OK) on success or a negated errno value on failure. + * See the description of accept of the possible errno values in the + * description of accept(). + * + * Assumptions: + * Network is locked. + * + ****************************************************************************/ + +int psock_tcp_accept(FAR struct socket *psock, FAR struct sockaddr *addr, + FAR socklen_t *addrlen, FAR void **newconn); + /**************************************************************************** * Function: psock_tcp_send * @@ -972,7 +986,6 @@ struct socket; ssize_t psock_tcp_send(FAR struct socket *psock, FAR const void *buf, size_t len); -/* Defined in tcp_wrbuffer.c ************************************************/ /**************************************************************************** * Function: tcp_wrbuffer_initialize * diff --git a/nuttx/net/tcp/tcp_accept.c b/nuttx/net/tcp/tcp_accept.c new file mode 100644 index 000000000..86e4e8bc0 --- /dev/null +++ b/nuttx/net/tcp/tcp_accept.c @@ -0,0 +1,359 @@ +/**************************************************************************** + * net/tcp/tcp_accept.c + * + * Copyright (C) 2007-2012, 2015 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> +#if defined(CONFIG_NET) && CONFIG_NSOCKET_DESCRIPTORS > 0 && defined(CONFIG_NET_TCP) + +#include <sys/types.h> +#include <sys/socket.h> + +#include <semaphore.h> +#include <string.h> +#include <errno.h> +#include <assert.h> +#include <debug.h> + +#include <nuttx/net/net.h> + +#include "socket/socket.h" +#include "tcp/tcp.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct accept_s +{ + FAR struct socket *acpt_sock; /* The accepting socket */ + sem_t acpt_sem; /* Wait for interrupt event */ + FAR struct sockaddr *acpt_addr; /* Return connection address */ + FAR socklen_t *acpt_addrlen; /* Return length of address */ + FAR struct tcp_conn_s *acpt_newconn; /* The accepted connection */ + int acpt_result; /* The result of the wait */ +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: accept_tcpsender + * + * Description: + * Get the sender's address from the UDP packet + * + * Parameters: + * psock - The state structure of the accepting socket + * conn - The newly accepted TCP connection + * pstate - the recvfrom state structure + * + * Returned Value: + * None + * + * Assumptions: + * Running at the interrupt level +* + ****************************************************************************/ + +#ifdef CONFIG_NET_TCP +static inline void accept_tcpsender(FAR struct socket *psock, + FAR struct tcp_conn_s *conn, + FAR struct sockaddr *addr, + socklen_t *addrlen) +{ + if (addr) + { + /* If an address is provided, then the length must also be provided. */ + + DEBUGASSERT(addrlen); + +#ifdef CONFIG_NET_IPv4 +#ifdef CONFIG_NET_IPv6 + /* If both IPv4 and IPv6 support are enabled, then we will need to + * select which one to use when obtaining the sender's IP address. + */ + + if (psock->s_domain == PF_INET) +#endif /* CONFIG_NET_IPv6 */ + { + FAR struct sockaddr_in *inaddr = (FAR struct sockaddr_in *)addr; + + inaddr->sin_family = AF_INET; + inaddr->sin_port = conn->rport; + net_ipv4addr_copy(inaddr->sin_addr.s_addr, conn->u.ipv4.raddr); + + *addrlen = sizeof(struct sockaddr_in); + } +#endif /* CONFIG_NET_IPv4 */ + +#ifdef CONFIG_NET_IPv6 +#ifdef CONFIG_NET_IPv4 + /* Otherwise, this the IPv6 address is needed */ + + else +#endif /* CONFIG_NET_IPv4 */ + { + FAR struct sockaddr_in6 *inaddr = (FAR struct sockaddr_in6 *)addr; + + DEBUGASSERT(psock->s_domain == PF_INET6); + inaddr->sin6_family = AF_INET6; + inaddr->sin6_port = conn->rport; + net_ipv6addr_copy(inaddr->sin6_addr.s6_addr, conn->u.ipv6.raddr); + + *addrlen = sizeof(struct sockaddr_in6); + } +#endif /* CONFIG_NET_IPv6 */ + } +} +#endif /* CONFIG_NET_TCP */ + +/**************************************************************************** + * Function: accept_interrupt + * + * Description: + * Receive interrupt level callbacks when connections occur + * + * Parameters: + * listener The connection structure of the listener + * conn The connection structure that was just accepted + * + * Returned Value: + * None + * + * Assumptions: + * Running at the interrupt level + * + ****************************************************************************/ + +static int accept_interrupt(FAR struct tcp_conn_s *listener, + FAR struct tcp_conn_s *conn) +{ + struct accept_s *pstate = (struct accept_s *)listener->accept_private; + int ret = -EINVAL; + + if (pstate) + { + /* Get the connection address */ + + accept_tcpsender(pstate->acpt_sock, conn, pstate->acpt_addr, + pstate->acpt_addrlen); + + /* Save the connection structure */ + + pstate->acpt_newconn = conn; + pstate->acpt_result = OK; + + /* There should be a reference of one on the new connection */ + + DEBUGASSERT(conn->crefs == 1); + + /* Wake-up the waiting caller thread */ + + sem_post(&pstate->acpt_sem); + + /* Stop any further callbacks */ + + listener->accept_private = NULL; + listener->accept = NULL; + ret = OK; + } + + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: tcp_accept + * + * Description: + * This function implements accept() for TCP/IP sockets. See the + * description of accept() for further information. + * + * Parameters: + * psock The listening TCP socket structure + * addr Receives the address of the connecting client + * addrlen Input: allocated size of 'addr', Return: returned size of 'addr' + * newconn The new, accepted TCP connection structure + * + * Returned Value: + * Returns zero (OK) on success or a negated errno value on failure. + * See the description of accept of the possible errno values in the + * description of accept(). + * + * Assumptions: + * Network is locked. + * + ****************************************************************************/ + +int psock_tcp_accept(FAR struct socket *psock, FAR struct sockaddr *addr, + FAR socklen_t *addrlen, FAR void **newconn) +{ + FAR struct tcp_conn_s *conn; + struct accept_s state; + int err; + int ret; + + DEBUGASSERT(psock && newconn); + + /* Check the backlog to see if there is a connection already pending for + * this listener. + */ + + conn = (FAR struct tcp_conn_s *)psock->s_conn; + +#ifdef CONFIG_NET_TCPBACKLOG + state.acpt_newconn = tcp_backlogremove(conn); + if (state.acpt_newconn) + { + /* Yes... get the address of the connected client */ + + nvdbg("Pending conn=%p\n", state.acpt_newconn); + accept_tcpsender(psock, state.acpt_newconn, addr, addrlen); + } + + /* In general, this uIP-based implementation will not support non-blocking + * socket operations... except in a few cases: Here for TCP accept with backlog + * enabled. If this socket is configured as non-blocking then return EAGAIN + * if there is no pending connection in the backlog. + */ + + else if (_SS_ISNONBLOCK(psock->s_flags)) + { + err = EAGAIN; + goto errout; + } + else +#endif + { + /* Set the socket state to accepting */ + + psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_ACCEPT); + + /* Perform the TCP accept operation */ + + /* Initialize the state structure. This is done with interrupts + * disabled because we don't want anything to happen until we + * are ready. + */ + + state.acpt_sock = psock; + state.acpt_addr = addr; + state.acpt_addrlen = addrlen; + state.acpt_newconn = NULL; + state.acpt_result = OK; + sem_init(&state.acpt_sem, 0, 0); + + /* Set up the callback in the connection */ + + conn->accept_private = (void*)&state; + conn->accept = accept_interrupt; + + /* Wait for the send to complete or an error to occur: NOTES: (1) + * net_lockedwait will also terminate if a signal is received, (2) + * interrupts may be disabled! They will be re-enabled while the + * task sleeps and automatically re-enabled when the task restarts. + */ + + ret = net_lockedwait(&state.acpt_sem); + if (ret < 0) + { + /* The value returned by net_lockedwait() the same as the value + * returned by sem_wait(): Zero (OK) is returned on success; -1 + * (ERROR) is returned on a failure with the errno value set + * appropriately. + * + * We have to preserve the errno value here because it may be + * altered by intervening operations. + */ + + err = get_errno(); + } + + /* Make sure that no further interrupts are processed */ + + conn->accept_private = NULL; + conn->accept = NULL; + + sem_destroy(&state. acpt_sem); + + /* Set the socket state to idle */ + + psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); + + /* Check for a errors. Errors are signalled by negative errno values + * for the send length. + */ + + if (state.acpt_result != 0) + { + err = state.acpt_result; + goto errout; + } + + /* If net_lockedwait failed, then we were probably reawakened by a + * signal. In this case, logic above will have set 'err' to the + * ernno value returned by net_lockedwait(). + */ + + if (ret < 0) + { + goto errout; + } + } + + *newconn = (FAR void *)state.acpt_newconn; + return OK; + +errout: + set_errno(err); + return ERROR; +} + +#endif /* CONFIG_NET && CONFIG_NSOCKET_DESCRIPTORS && CONFIG_NET_TCP */ |