-
Notifications
You must be signed in to change notification settings - Fork 7.6k
net: BSD Sockets like API initial implementation #498
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
4d35a4d
4f76622
ecc4c38
ae9b7f7
dbf743a
f164d9f
49f8888
7c9b057
8958d1f
9ddd43a
75d822d
30a5792
c2a3d86
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
/* | ||
* Copyright (c) 2017 Linaro Limited | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
#ifndef __NET_SOCKET_H | ||
#define __NET_SOCKET_H | ||
|
||
#include <sys/types.h> | ||
#include <zephyr/types.h> | ||
#include <net/net_ip.h> | ||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
int zsock_socket(int family, int type, int proto); | ||
int zsock_close(int sock); | ||
int zsock_bind(int sock, const struct sockaddr *addr, socklen_t addrlen); | ||
int zsock_connect(int sock, const struct sockaddr *addr, socklen_t addrlen); | ||
int zsock_listen(int sock, int backlog); | ||
int zsock_accept(int sock, struct sockaddr *addr, socklen_t *addrlen); | ||
ssize_t zsock_send(int sock, const void *buf, size_t len, int flags); | ||
ssize_t zsock_recv(int sock, void *buf, size_t max_len, int flags); | ||
|
||
#if defined(CONFIG_NET_SOCKETS_POSIX_NAMES) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. then could do here: |
||
#define socket zsock_socket | ||
#define close zsock_close | ||
#define bind zsock_bind | ||
#define connect zsock_connect | ||
#define listen zsock_listen | ||
#define accept zsock_accept | ||
#define send zsock_send | ||
#define recv zsock_recv | ||
|
||
#define inet_ntop net_addr_ntop | ||
#define inet_pton net_addr_pton | ||
#endif | ||
|
||
#ifdef __cplusplus | ||
} | ||
#endif | ||
|
||
#endif /* __NET_SOCKET_H */ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# Makefile - simple socket-based echo server | ||
|
||
# | ||
# Copyright (c) 2017 Linaro Limited | ||
# | ||
# SPDX-License-Identifier: Apache-2.0 | ||
# | ||
|
||
BOARD ?= qemu_x86 | ||
CONF_FILE ?= prj_$(BOARD).conf | ||
|
||
include $(ZEPHYR_BASE)/Makefile.inc | ||
|
||
ifeq ($(CONFIG_NET_L2_BLUETOOTH), y) | ||
QEMU_EXTRA_FLAGS = -serial unix:/tmp/bt-server-bredr | ||
else | ||
include $(ZEPHYR_BASE)/samples/net/common/Makefile.ipstack | ||
endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# This makefile builds socket_echo sample for POSIX system, like Linux | ||
|
||
socket_echo: src/socket_echo.c | ||
$(CC) $^ -o $@ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# General config | ||
CONFIG_NEWLIB_LIBC=y | ||
|
||
# Networking config | ||
CONFIG_NETWORKING=y | ||
CONFIG_NET_IPV4=y | ||
CONFIG_NET_IPV6=n | ||
CONFIG_NET_TCP=y | ||
CONFIG_NET_SOCKETS=y | ||
CONFIG_NET_SOCKETS_POSIX_NAMES=y | ||
|
||
# Network driver config | ||
CONFIG_NET_SLIP_TAP=y | ||
CONFIG_TEST_RANDOM_GENERATOR=y | ||
|
||
# Without CONFIG_NET_BUF_LOG printf() doesn't work | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I do not really understand how net_buf logging could affect printf(), could you elaborate the issue more. BTW, typically I have this setting in my prj.conf files CONFIG_NET_LOG=y and then setting relevant net debug options to "y" and increasing CONFIG_SYS_LOG_NET_LEVEL to 4, will then start to print debug output. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I don't understand either, and yet it's like that - w/o CONFIG_NET_BUF_LOG=y, printf() output is not shown (network echo works). I did 10-15 mins of "genetic algorithm" debugging, semi-randomly trying other logging and output options and only CONFIG_NET_BUF_LOG looked like a culprit. Didn't debug further, as you may imagine, that can be quite a timesink ;-) |
||
CONFIG_NET_BUF_LOG=y | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Normally one does not need to enable this unless one is debugging the actual net_buf implementation. |
||
|
||
# Network address config | ||
CONFIG_NET_APP_SETTINGS=y | ||
CONFIG_NET_APP_MY_IPV4_ADDR="192.0.2.1" | ||
CONFIG_NET_APP_PEER_IPV4_ADDR="192.0.2.2" | ||
|
||
# Network debug config | ||
#CONFIG_NET_DEBUG_SOCKETS=y | ||
CONFIG_SYS_LOG_NET_LEVEL=2 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
include $(ZEPHYR_BASE)/samples/net/common/Makefile.common | ||
|
||
obj-y += socket_echo.o |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
/* | ||
* Copyright (c) 2017 Linaro Limited | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
#include <stdio.h> | ||
|
||
#ifndef __ZEPHYR__ | ||
|
||
#include <netinet/in.h> | ||
#include <sys/socket.h> | ||
#include <arpa/inet.h> | ||
#include <unistd.h> | ||
|
||
#define init_net() | ||
|
||
#else | ||
|
||
#include <net/socket.h> | ||
#include <kernel.h> | ||
#include <net_sample_app.h> | ||
|
||
void init_net(void) | ||
{ | ||
int ret = net_sample_app_init("socket_echo", NET_SAMPLE_NEED_IPV4, | ||
K_SECONDS(3)); | ||
|
||
if (ret < 0) { | ||
printf("Application init failed\n"); | ||
k_panic(); | ||
} | ||
} | ||
|
||
#endif | ||
|
||
int main(void) | ||
{ | ||
int serv; | ||
struct sockaddr_in bind_addr; | ||
|
||
init_net(); | ||
|
||
serv = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); | ||
|
||
bind_addr.sin_family = AF_INET; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be nice if this app would support also IPv6. This can be enabled later, if no time to do that now. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So (also partially answering @lpereira's comment below), the primary purpose of this sample was to show that the same code (modulo includes of course) can be used both on POSIX and Zephyr. Turns out, I missed to include "Makefile.posix" to make that obvious, I'll add it. Then, Linux for example supports "dual stack" sockets which can be accessed via IPv4 or IPv6, but I don't think we have that feature in Zephyr. Otherwise, to support IPv4 and IPv6 at the same time, there would be needed 2 sockets, and poll()/select(), which are scheduled so "stage 3" of Sockets implementation (this patch being stage 1). Perhaps you mean either IPv4 or IPv6? That can be done, though again, the idea was to show how sockets can be portable between POSIX and Zephyr, without extra #ifdef noise. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I meant having dual IPv4 and IPv6 at the same time. But it requires two sockets at the moment and support for poll/select as you said, so we can postpone this for later stage. |
||
bind_addr.sin_addr.s_addr = htonl(INADDR_ANY); | ||
bind_addr.sin_port = htons(4242); | ||
bind(serv, (struct sockaddr *)&bind_addr, sizeof(bind_addr)); | ||
|
||
listen(serv, 5); | ||
|
||
while (1) { | ||
struct sockaddr_in client_addr; | ||
socklen_t client_addr_len = sizeof(client_addr); | ||
char addr_str[32]; | ||
int client = accept(serv, (struct sockaddr *)&client_addr, | ||
&client_addr_len); | ||
inet_ntop(client_addr.sin_family, &client_addr.sin_addr, | ||
addr_str, sizeof(addr_str)); | ||
printf("Connection from %s\n", addr_str); | ||
|
||
while (1) { | ||
char buf[128]; | ||
int len = recv(client, buf, sizeof(buf), 0); | ||
|
||
if (len == 0) { | ||
break; | ||
} | ||
send(client, buf, len, 0); | ||
} | ||
|
||
close(client); | ||
printf("Connection from %s closed\n", addr_str); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
obj-$(CONFIG_NET_SOCKETS) += sockets/ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Then, maybe the subdirectory should be zsocket/ or zsock/ instead of sockets/? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure, why? There're dns, http on the same level, not zdns, zhttp. (There's zoap, yeah, but it's an exception.) |
||
obj-$(CONFIG_ZOAP) += zoap/ | ||
obj-$(CONFIG_DNS_RESOLVER) += dns/ | ||
obj-$(CONFIG_MQTT_LIB) += mqtt/ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
# Kconfig - BSD Sockets like API | ||
|
||
# | ||
# Copyright (c) 2017 Linaro Limited. | ||
# | ||
# SPDX-License-Identifier: Apache-2.0 | ||
# | ||
|
||
menuconfig NET_SOCKETS | ||
bool "BSD Sockets like API" | ||
default n | ||
help | ||
Provide BSD Sockets like API on top of native Zephyr networking API. | ||
|
||
if NET_SOCKETS | ||
|
||
config NET_SOCKETS_POSIX_NAMES | ||
bool "Standard POSIX names for Sockets API" | ||
default n | ||
help | ||
By default, Sockets API function are prefixed with `zsock_` to avoid | ||
namespacing issues. If this option is enabled, they will be provided | ||
with standard POSIX names like socket(), recv(), and close(), to help | ||
with porting existing code. Note that close() may require a special | ||
attention, as in POSIX it closes any file descriptor, while with this | ||
option enaled, it will still apply only to sockets. | ||
|
||
config NET_DEBUG_SOCKETS | ||
bool "Debug BSD Sockets like API calls" | ||
default n | ||
help | ||
Enables logging for sockets code. (Logging level is defined by | ||
SYS_LOG_NET_LEVEL setting). | ||
|
||
endif # NET_SOCKETS |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
ccflags-y += -I$(srctree)/subsys/net/lib/sockets | ||
|
||
obj-$(CONFIG_NET_SOCKETS) += sockets.o |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be logical to place these definitions in a zsocket.h header, to be included by Zephyr applications wanting to use the native Zephyr socket symbols, and leave socket.h to define the POSIX only symbols, as below?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know, this turns one header into two, and reading literally, puts a networking-related header outside net/. Why would this be better? As it stands now, everything socket-related is in one header, but apps can configure subset of the functionality needed, like with the rest of subsystems in Zephyr.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few reasons:
I assumed zsocket.h would also go into net/.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, that's actually mu biggest concern - if I'd see
socket.h
, I would never think there's alsozsocket.h
, or vice-versa. Zephyr doesn't split IPv4 and IPv6 headers. lwIP defines both native prefixed functions (lwip_recv(), etc.) and POSIXy macros in the same header, sockets.h. And in this case, it's also the single module, it just defines 2 API sets, one being alias of another (but it's the same API).Well, there're no "true POSIX APIs", only "BSD Sockets like API" ("like" is important). True POSIX APIs live in <sys/socket.h>, Zephyr's BSD Sockets like API lives in <net/socket.h>.
Ok, this finally explains why you suggest this change! But why do you want to do it this way? I imagined it would be done just the same way as offloading already implemented in net_context - that each individual zsock_*() will be the place of switching, and that offloading will be supported per netif.
You instead seem to propose that socket offloading will be global, not per netif. Rereading https://jira.zephyrproject.org/browse/ZEP-2271?focusedCommentId=19002&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-19002 , that seems to be what's written in the user story, but if you don't mind, I'd like to get an ack form @jukkar and @tbursztyka that it's ok to proceed with such design right away (vs further discuss it), as it leaves many questions open, e.g. why we have 2 inconsistently implemented offloading mechanisms. Thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Independent of where socket offloading occurs, it just seems it would be logical and future-proof to have zsocket.h defining native zsock functions, and socket.h declaring the socket functions, mapping to zsock. Anyways, just an opinion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gil, I appreciate the idea, but after additional checking, I don't see such pattern of splitting the same API across 2+ headers to be used in Zephyr. And as I mentioned above, these are indeed intended to be 2 facets of the same API, not 2 different APIs. I'll be happy to make such a change however is there will be 2nd vote for it. Otherwise, well, if it proves to be useful/need, we may need to do such a refactor in the future (e.g. when we'll have better defined POSIX API layer). Thanks for understanding.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Understood.