diff options
author | sharath <sharathkumarboyanapally@gmail.com> | 2018-08-13 19:28:26 +0530 |
---|---|---|
committer | sharath <sharathkumarboyanapally@gmail.com> | 2018-08-13 19:29:13 +0530 |
commit | 7b1e219c80f5fe44a8f015a369e57ba7d2bc39cc (patch) | |
tree | 9fa3ee1ce324478711dfce73425e16e6bcb429a9 /stacks/lwip_stack/lwip_src/socket | |
parent | bd6e75c243db1b384ba0882ecaf9063ec4cd70bd (diff) |
Feat : LWIP integration part2
Change-Id: I2431581d611659beb9b9b4d6d95d6985e53a8061
Signed-off-by: sharath <sharathkumarboyanapally@gmail.com>
Diffstat (limited to 'stacks/lwip_stack/lwip_src/socket')
18 files changed, 5837 insertions, 0 deletions
diff --git a/stacks/lwip_stack/lwip_src/socket/CMakeLists.txt b/stacks/lwip_stack/lwip_src/socket/CMakeLists.txt new file mode 100644 index 0000000..e7915d2 --- /dev/null +++ b/stacks/lwip_stack/lwip_src/socket/CMakeLists.txt @@ -0,0 +1,76 @@ +######################################################################### +# +# Copyright (c) 2018 Huawei Technologies Co.,Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +######################################################################### + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2 -g -fPIE -pie -fPIC -m64 -mssse3 -std=gnu89") +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror -Wshadow -Wfloat-equal -Wformat=2") +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector -fstack-protector-all") +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,-z,relro,-z,now -Wl,--disable-new-dtags") +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,-z,noexecstack -mcmodel=medium") + +SET(ADAPT_DIRECTORIES "${PROJECT_SOURCE_DIR}/src/adapt/") +#SET(DMM_API "${PROJECT_SOURCE_DIR}/src/nSocket/include/") + +ADD_DEFINITIONS(-D_GNU_SOURCE -D_FORTIFY_SOURCE=2) +ADD_DEFINITIONS(-DDPDK_MODULE=0) +if(WITH_HAL_LIB) +SET(RTP_CONFIG ${CMAKE_CURRENT_LIST_DIR}/../../../src/include/rtp_config.h) +else() + SET(PAL_H_DIRECTORIES "/usr/include/dpdk/") + SET(RTP_CONFIG ${PROJECT_SOURCE_DIR}/../../src/framework/common/base/include/common/common_sys_config.h) + INCLUDE_DIRECTORIES( + ${PAL_H_DIRECTORIES} + ${ADAPT_DIRECTORIES} +# ${DMM_API} + ) +endif() +SET(COMPLE_CONFIG ${CMAKE_CURRENT_LIST_DIR}/../../src/include/compile_config.h) +#SET(MGR_COM ${PROJECT_SOURCE_DIR}/src/framework/ipc/mgr_com/mgr_com.h) +SET(MGR_COM ${CMAKE_CURRENT_LIST_DIR}/../../src/include/mgr_com.h) +ADD_DEFINITIONS(-include ${RTP_CONFIG}) +ADD_DEFINITIONS(-include ${COMPLE_CONFIG}) +ADD_DEFINITIONS(-include ${MGR_COM}) +if(WITH_SECUREC_LIB) +LINK_LIBRARIES(pthread rt securec) +else() +LINK_LIBRARIES(pthread rt) +endif() +LINK_DIRECTORIES(${LIB_PATH_SHARED} ${LIB_PATH_STATIC}) +INCLUDE_DIRECTORIES( + ${CMAKE_CURRENT_LIST_DIR}/../../../../thirdparty/json/json-c-0.12.1/ + ${CMAKE_CURRENT_LIST_DIR}/../../../../thirdparty/glog/glog-0.3.4/src/ + ${CMAKE_CURRENT_LIST_DIR}/../../src/include/ +# ${PROJECT_SOURCE_DIR}/src/framework/include/ +# ${PROJECT_SOURCE_DIR}/src/framework/common/include/ +# ${ADAPT_DIRECTORIES} +# ${DMM_API} +) + +FILE(GLOB COMMON ../common/*.c) +FILE(GLOB SOCKET ./*.c) +ADD_LIBRARY(socket STATIC ${COMMON} ${SOCKET}) +ADD_DEPENDENCIES(socket JSON GLOG DPDK) +TARGET_INCLUDE_DIRECTORIES( + socket + PRIVATE + ../common/ + ./ + ${CMAKE_CURRENT_LIST_DIR}/../../src/sbr/ + ${CMAKE_CURRENT_LIST_DIR}/../../src/include/ +# ${PROJECT_SOURCE_DIR}/src/framework/include/ +# ${PROJECT_SOURCE_DIR}/src/framework/common/include/ +# ${ADAPT_DIRECTORIES} +# ${DMM_API} +) diff --git a/stacks/lwip_stack/lwip_src/socket/stackx_cfg.h b/stacks/lwip_stack/lwip_src/socket/stackx_cfg.h new file mode 100644 index 0000000..4f4749d --- /dev/null +++ b/stacks/lwip_stack/lwip_src/socket/stackx_cfg.h @@ -0,0 +1,54 @@ +/* +* +* Copyright (c) 2018 Huawei Technologies Co.,Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at: +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#ifndef STACKX_CONTAINER_CFG_H +#define STACKX_CONTAINER_CFG_H +#include "types.h" + +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + +#define SBR_MAX_CFG_PATH_LEN 256 +#define SBR_MAX_CONTAINER_IP_NUM 1024 +#define SBR_MAX_CFG_FILE_SIZE (1 * 1024 * 1024) + +typedef struct +{ + u32 ip; + u32 mask_len; +} sbr_container_ip; + +typedef struct +{ + sbr_container_ip ip_array[SBR_MAX_CONTAINER_IP_NUM]; + u32 ip_num; +} sbr_container_ip_group; + +extern sbr_container_ip_group g_container_ip_group; + +int sbr_init_cfg (); +int sbr_get_src_ip (u32 dst_ip, u32 * src_ip); + +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + +#endif diff --git a/stacks/lwip_stack/lwip_src/socket/stackx_container_cfg.c b/stacks/lwip_stack/lwip_src/socket/stackx_container_cfg.c new file mode 100644 index 0000000..b6580ed --- /dev/null +++ b/stacks/lwip_stack/lwip_src/socket/stackx_container_cfg.c @@ -0,0 +1,332 @@ +/* +* +* Copyright (c) 2018 Huawei Technologies Co.,Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at: +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <arpa/inet.h> +#include "stackx_cfg.h" +#include "json.h" +#include "nstack_log.h" +#include "spl_def.h" +#include "nstack_securec.h" +#include "stackx_ip_addr.h" + +sbr_container_ip_group g_container_ip_group; + +/***************************************************************************** +* Prototype : sbr_parse_container_ip_json +* Description : parse port json +* Input : char* param +* Output : None +* Return Value : static void +* Calls : +* Called By : +* +*****************************************************************************/ +static void +sbr_parse_container_ip_json (char *param) +{ + int retval; + struct json_object *obj = json_tokener_parse (param); + struct json_object *container_id_obj = NULL; + struct json_object *ports_list_obj = NULL; + struct json_object *ip_cidr_list_obj = NULL; + + if (!obj) + { + NSSBR_LOGERR ("json_tokener_parse failed"); + return; + } + + json_object_object_get_ex (obj, "containerID", &container_id_obj); + if (!container_id_obj) + { + NSSBR_LOGERR ("can't get containerID"); + goto RETURN_ERROR; + } + + json_object_object_get_ex (obj, "ports_list", &ports_list_obj); + if (ports_list_obj) + { + int i; + int port_num = json_object_array_length (ports_list_obj); + + if (0 == port_num) + { + NSSBR_LOGERR ("port num is 0"); + goto RETURN_ERROR; + } + + for (i = 0; i < port_num; i++) + { + struct json_object *port_obj = + json_object_array_get_idx (ports_list_obj, i); + json_object_object_get_ex (port_obj, "ip_cidr", &ip_cidr_list_obj); + if (ip_cidr_list_obj) + { + int j; + int ip_cidr_num = json_object_array_length (ip_cidr_list_obj); + for (j = 0; j < ip_cidr_num; ++j) + { + struct json_object *ip_cidr_obj = + json_object_array_get_idx (ip_cidr_list_obj, j); + if (ip_cidr_obj) + { + char tmp[32] = { 0 }; + const char *ip_cidr = + json_object_get_string (ip_cidr_obj); + if ((NULL == ip_cidr) || (ip_cidr[0] == 0)) + { + NSSBR_LOGERR ("ip is empty"); + goto RETURN_ERROR; + } + + const char *sub = strstr (ip_cidr, "/"); + if ((NULL == sub) + || (sizeof (tmp) - 1 < + (unsigned int) (sub - ip_cidr)) + || (strlen (sub) > sizeof (tmp) - 1)) + { + NSSBR_LOGERR ("ip format is not ok"); + goto RETURN_ERROR; + } + + retval = + STRNCPY_S (tmp, sizeof (tmp), ip_cidr, + (size_t) (sub - ip_cidr)); + if (EOK != retval) + { + NSSBR_LOGERR ("STRNCPY_S failed]ret=%d", retval); + goto RETURN_ERROR; + } + + struct in_addr addr; + retval = + MEMSET_S (&addr, sizeof (addr), 0, sizeof (addr)); + if (EOK != retval) + { + NSSBR_LOGERR ("MEMSET_S failed]ret=%d", retval); + goto RETURN_ERROR; + } + + retval = spl_inet_aton (tmp, &addr); + if (0 == retval) + { + NSSBR_LOGERR ("spl_inet_aton failed]ret=%d", + retval); + goto RETURN_ERROR; + } + + g_container_ip_group. + ip_array[g_container_ip_group.ip_num].ip = + addr.s_addr; + int mask_len = atoi (sub + 1); + if ((mask_len <= 0) || (mask_len > 32)) + { + NSSBR_LOGERR ("mask len is not ok"); + goto RETURN_ERROR; + } + + g_container_ip_group. + ip_array[g_container_ip_group.ip_num].mask_len = + (u32) mask_len; + g_container_ip_group.ip_num++; + + if (g_container_ip_group.ip_num >= + SBR_MAX_CONTAINER_IP_NUM) + { + NSSBR_LOGWAR ("container ip num is full]ip_num=%u", + g_container_ip_group.ip_num); + goto RETURN_OK; + } + } + } + } + } + } + else + { + NSSBR_LOGERR ("can't get ports_list"); + goto RETURN_ERROR; + } + +RETURN_OK: + json_object_put (obj); + NSSBR_LOGINF ("container ip num is %u", g_container_ip_group.ip_num); + u32 idx; + for (idx = 0; idx < g_container_ip_group.ip_num; ++idx) + { + NSSBR_LOGDBG ("container ip=0x%08x", + g_container_ip_group.ip_array[idx].ip); + } + return; + +RETURN_ERROR: + json_object_put (obj); + if (MEMSET_S + (&g_container_ip_group, sizeof (sbr_container_ip_group), 0, + sizeof (sbr_container_ip_group)) != EOK) + { + NSSBR_LOGERR ("MEMSET_S failed"); + } +} + +/***************************************************************************** +* Prototype : sbr_get_cfg_path +* Description : get cfg path +* Input : None +* Output : None +* Return Value : NSTACK_STATIC const char* +* Calls : +* Called By : +* +*****************************************************************************/ +NSTACK_STATIC const char * +sbr_get_cfg_path () +{ + static char cfg_file[SBR_MAX_CFG_PATH_LEN] = "/canal/output/portinfo.json"; + return cfg_file; +} + +/***************************************************************************** +* Prototype : sbr_init_cfg +* Description : init cfg from file +* Input : None +* Output : None +* Return Value : int +* Calls : +* Called By : +* +*****************************************************************************/ +int +sbr_init_cfg () +{ + int ret; + off_t file_len = 0; + off_t buff_len = 0; + char *buff = NULL; + const char *cfg_file = sbr_get_cfg_path (); /* no need check ret */ + + int fp = open (cfg_file, O_RDONLY); + + if (fp < 0) + { + NSSBR_LOGWAR ("failed to open file]file name=%s", cfg_file); + goto RETURN_ERROR; + } + + file_len = lseek (fp, 0, SEEK_END); + if (file_len <= 0) + { + NSSBR_LOGWAR ("failed to get file len]file name=%s", cfg_file); + goto RETURN_ERROR; + } + + if (file_len > SBR_MAX_CFG_FILE_SIZE) + { + NSSBR_LOGWAR + ("file len is too big]file len=%d, max len=%d, file name=%s", + file_len, SBR_MAX_CFG_FILE_SIZE, cfg_file); + goto RETURN_ERROR; + } + + ret = lseek (fp, 0, SEEK_SET); + if (ret < 0) + { + NSSBR_LOGWAR ("seek to start failed]file name=%s", cfg_file); + goto RETURN_ERROR; + } + + buff_len = file_len + 1; + buff = (char *) malloc (buff_len); + if (!buff) + { + NSSBR_LOGWAR ("malloc buff failed]buff_len=%d", buff_len); + goto RETURN_ERROR; + } + + ret = MEMSET_S (buff, buff_len, 0, buff_len); + if (EOK != ret) + { + NSSBR_LOGWAR ("MEMSET_S failed]ret=%d.", ret); + goto RETURN_ERROR; + } + + ret = read (fp, buff, buff_len - 1); + if (ret <= 0) + { + NSSBR_LOGWAR ("read failed]ret=%d", ret); + goto RETURN_ERROR; + } + + sbr_parse_container_ip_json (buff); + close (fp); + free (buff); + return 0; + +RETURN_ERROR: + if (fp >= 0) + { + close (fp); + } + + if (buff) + { + free (buff); + } + + return -1; +} + +/***************************************************************************** +* Prototype : sbr_get_src_ip +* Description : get src ip from cfg +* Input : u32 dst_ip +* u32* src_ip +* Output : None +* Return Value : int +* Calls : +* Called By : +* +*****************************************************************************/ +int +sbr_get_src_ip (u32 dst_ip, u32 * src_ip) +{ + if (!src_ip) + { + NSSBR_LOGERR ("src_ip is NULL"); + return -1; + } + + u32 i; + for (i = 0; i < g_container_ip_group.ip_num; ++i) + { + unsigned int mask = ~0; + mask = (mask << (32 - g_container_ip_group.ip_array[i].mask_len)); + mask = htonl (mask); + if ((dst_ip & mask) == (g_container_ip_group.ip_array[i].ip & mask)) + { + *src_ip = g_container_ip_group.ip_array[i].ip; + NSSBR_LOGDBG ("find src ip]container_ip=0x%08x,dest_ip=0x%08x", + *src_ip, dst_ip); + return 0; + } + } + + NSSBR_LOGDBG ("can't find src ip]dest_ip=0x%08x", dst_ip); + return -1; +} diff --git a/stacks/lwip_stack/lwip_src/socket/stackx_epoll_api.c b/stacks/lwip_stack/lwip_src/socket/stackx_epoll_api.c new file mode 100644 index 0000000..0223ac9 --- /dev/null +++ b/stacks/lwip_stack/lwip_src/socket/stackx_epoll_api.c @@ -0,0 +1,150 @@ +/* +* +* Copyright (c) 2018 Huawei Technologies Co.,Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at: +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "stackx_epoll_api.h" +#include "stackx_spl_share.h" +#include "common_pal_bitwide_adjust.h" +#include "nstack_dmm_adpt.h" +#include "nstack_dmm_api.h" + +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif /* _cplusplus */ + +void +epoll_triggle_event_from_api (sbr_socket_t * sock, int op) +{ + struct spl_netconn *conn = sbr_get_conn (sock); + void *epInfo = ADDR_SHTOL (conn->epInfo); + //NSPOL_LOGDBG(SOCKETS_DEBUG, "enter]fd=%d,op=%d", sock, op); + switch (op) + { + case EPOLL_API_OP_RECV: + break; + case EPOLL_API_OP_SEND: + if (conn->epoll_flag && epInfo) + { + nstack_event_callback (epInfo, EPOLLOUT); + } + break; + case EPOLL_API_OP_STACK_RECV: + if (conn->epoll_flag && epInfo) + { + nstack_event_callback (epInfo, EPOLLIN); + } + break; + default: + break; + } + return; +} + +/* + * This function will be registed to application + * The context will be in the application + */ +unsigned int +stackx_eventpoll_triggle (sbr_socket_t * sock, int triggle_ops, + struct epoll_event *pevent, void *pdata) +{ + struct spl_netconn *conn = sbr_get_conn (sock); + unsigned int events = 0; + if (!conn) + { + NSPOL_LOGINF (SOCKETS_DEBUG, "get socket failed]fd=%d", sock->fd); + return -1; + } + + NSPOL_LOGINF (SOCKETS_DEBUG, + "]fd=%d,triggle_ops=%d conn=%p event:%d pdata=%p", sock->fd, + triggle_ops, conn, pevent->events, pdata); + /* + * sock->epoll_flag must be set before sock->rcvevent check. + * Consider this Scenario : 1) network stack has got one packet, but event_callback not called yet + * 2) Do epoll ctl add, then stackx triggle will check event, it will get 0 + * 3) network stack call event_callback , it will check epoll_flag + * So, if epoll_flag not set before sock->rcvent check, neither of network stack and stackx triggle + * will add this event to epoll. because : for network stack, event_callback check epoll_flag fail + * for stackx triggle, event check fail. + */ + if (nstack_ep_triggle_add == triggle_ops) + { + /*log info */ + conn->epInfo = pdata; + __sync_fetch_and_add (&conn->epoll_flag, 1); + } + + if ((pevent->events & EPOLLIN) + && + (!((conn->rcvevent == 0) && (sbr_get_fd_share (sock)->lastdata == 0) + && (sbr_get_fd_share (sock)->lastoffset == 0)))) + events |= EPOLLIN; + if ((pevent->events & EPOLLOUT) && conn->sendevent) + events |= EPOLLOUT; + if (conn->errevent) + events |= pevent->events & (conn->errevent); + + switch (triggle_ops) + { + case nstack_ep_triggle_add: + break; + case nstack_ep_triggle_mod: + break; + case nstack_ep_triggle_del: + if (conn->epoll_flag > 0) + { + __sync_fetch_and_sub (&conn->epoll_flag, 1); + } + events = 0; + break; + default: + return -1; + } + return events; +} + +/* + * This function will be registed to application + * The context will be in the application + * RETURN VALUE : Event exists in current protocol + */ +unsigned int +stackx_eventpoll_getEvt (sbr_socket_t * sock, unsigned int events) +{ + struct spl_netconn *conn = sbr_get_conn (sock); + unsigned int tevent = 0; + if ((events & EPOLLIN) + && + (!((conn->rcvevent == 0) && (sbr_get_fd_share (sock)->lastdata == 0) + && (sbr_get_fd_share (sock)->lastoffset == 0)))) + { + tevent |= EPOLLIN; + } + + if ((events & EPOLLOUT) && conn->sendevent) + { + tevent |= EPOLLOUT; + } + return tevent; +} + +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif /* _cplusplus */ diff --git a/stacks/lwip_stack/lwip_src/socket/stackx_epoll_api.h b/stacks/lwip_stack/lwip_src/socket/stackx_epoll_api.h new file mode 100644 index 0000000..59a1d21 --- /dev/null +++ b/stacks/lwip_stack/lwip_src/socket/stackx_epoll_api.h @@ -0,0 +1,48 @@ +/* +* +* Copyright (c) 2018 Huawei Technologies Co.,Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at: +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#ifndef STACKX_EPOLL_API_H +#define STACKX_EPOLL_API_H +#include "stackx_socket.h" + +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + +typedef enum +{ + EPOLL_API_OP_RECV, + EPOLL_API_OP_SEND, + EPOLL_API_OP_STACK_RECV +} EPOLL_TRIGGLE_EVENT_API_OPS_T; + +extern void epoll_triggle_event_from_api (sbr_socket_t * sock, int op); +extern unsigned int stackx_eventpoll_getEvt (sbr_socket_t * sock, + unsigned int events); +extern unsigned int stackx_eventpoll_triggle (sbr_socket_t * sock, + int triggle_ops, + struct epoll_event *pevent, + void *pdata); + +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + +#endif diff --git a/stacks/lwip_stack/lwip_src/socket/stackx_event.c b/stacks/lwip_stack/lwip_src/socket/stackx_event.c new file mode 100644 index 0000000..93e47a3 --- /dev/null +++ b/stacks/lwip_stack/lwip_src/socket/stackx_event.c @@ -0,0 +1,29 @@ +/* +* +* Copyright (c) 2018 Huawei Technologies Co.,Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at: +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "stackx_spl_share.h" +#include "common_pal_bitwide_adjust.h" +#include "stackx_event.h" +#include <netinet/in.h> + +#define FREE_FD_SET(readfd, writefd, exceptfd) {\ + if(readfd)\ + free(readfd);\ + if(writefd)\ + free(writefd);\ + if(exceptfd)\ + free(exceptfd);\ +} diff --git a/stacks/lwip_stack/lwip_src/socket/stackx_event.h b/stacks/lwip_stack/lwip_src/socket/stackx_event.h new file mode 100644 index 0000000..f95b370 --- /dev/null +++ b/stacks/lwip_stack/lwip_src/socket/stackx_event.h @@ -0,0 +1,46 @@ +/* +* +* Copyright (c) 2018 Huawei Technologies Co.,Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at: +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#ifndef __STACKX_EVENT_H__ +#define __STACKX_EVENT_H__ + +#include <sys/types.h> +#include <sys/time.h> +#include <stdio.h> +#include <unistd.h> +#include "stackx_socket.h" +#include "nstack_securec.h" +#include "sbr_res_mgr.h" +#include "sbr_index_ring.h" +#define NSTACK_SETSIZE SBR_MAX_FD_NUM + +typedef struct +{ + unsigned char fds_bits[(NSTACK_SETSIZE + 7) / 8]; +} __attribute__ ((packed)) nstack_fd_set; + +#define NSTACK_FD_SET(n, p) ((p)->fds_bits[(n)/8]|=1U<<((n)&0x07)) +#define NSTACK_FD_ISSET(n,p) (((p)->fds_bits[(n)/8]&(1U<<((n)&0x07)))?1:0) +#define NSTACK_FD_CLR(n,p) ((p)->fds_bits[(n)/8]&=~(1U<<((n)&0x07))) +#define NSTACK_FD_ZERO(p) (MEMSET_S((void *)(p), sizeof(*(p)),0,sizeof(*(p)))) +#define NSTACK_FD_OR(p1 ,p2) {\ + int i;\ + for(i = 0; i < (NSTACK_SETSIZE+7)/8; i++){\ + (p1)->fds_bits[i] |= (p2)->fds_bits[i];\ + }\ +} + +#endif /* __STACKX_EVENT_H__ */ diff --git a/stacks/lwip_stack/lwip_src/socket/stackx_macro.h b/stacks/lwip_stack/lwip_src/socket/stackx_macro.h new file mode 100644 index 0000000..96a0b91 --- /dev/null +++ b/stacks/lwip_stack/lwip_src/socket/stackx_macro.h @@ -0,0 +1,24 @@ +/* +* +* Copyright (c) 2018 Huawei Technologies Co.,Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at: +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#ifndef STACKX_MACRO_H +#define STACKX_MACRO_H + +#ifndef SBR_USE_LOCK +#define SBR_USE_LOCK +#endif + +#endif diff --git a/stacks/lwip_stack/lwip_src/socket/stackx_msg_handler.c b/stacks/lwip_stack/lwip_src/socket/stackx_msg_handler.c new file mode 100644 index 0000000..6fcde44 --- /dev/null +++ b/stacks/lwip_stack/lwip_src/socket/stackx_msg_handler.c @@ -0,0 +1,775 @@ +/* +* +* Copyright (c) 2018 Huawei Technologies Co.,Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at: +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "stackx_msg_handler.h" +#include "stackx_spl_share.h" +#include "stackx_spl_msg.h" +#include "nsfw_msg_api.h" +#include "common_pal_bitwide_adjust.h" +#include "stackx_res_mgr.h" +#include "stackx_prot_com.h" +#include "nstack_securec.h" +//#include "stackx_dfx_api.h" + +#define SBR_MSG_MALLOC(sk) msg_malloc(ss_get_msg_pool(sbr_get_conn(sk))) +#define SBR_MSG_FREE(msg) msg_free(msg) + +#define SBR_MSG_POST(msg, ring) \ + do { \ + if (MSG_ASYN_POST == msg->param.op_type)\ + {\ + if (msg_post(msg, ring) < 0)\ + {\ + SBR_MSG_FREE(msg); \ + NSSBR_LOGERR("msg_post failed]major=%u,minor=%u,type=%u", \ + msg->param.major_type, msg->param.minor_type, msg->param.op_type); \ + }\ + } \ + else \ + {\ + if (msg_post(msg, ring) < 0)\ + {\ + msg->param.err = ECONNABORTED; \ + NSSBR_LOGERR("msg_post_with_ref failed]major=%u,minor=%u,type=%u", \ + msg->param.major_type, msg->param.minor_type, msg->param.op_type); \ + }\ + } \ + } while (0) + +#define SBR_MSG_POST_RET(msg, ring, ret) \ + do { \ + if (MSG_ASYN_POST == msg->param.op_type)\ + {\ + if ((ret = msg_post(msg, ring)) < 0)\ + {\ + SBR_MSG_FREE(msg); \ + NSSBR_LOGERR("msg_post failed]major=%u,minor=%u,type=%u", \ + msg->param.major_type, msg->param.minor_type, msg->param.op_type); \ + }\ + } \ + else \ + {\ + if ((ret = msg_post(msg, ring)) < 0)\ + {\ + msg->param.err = ECONNABORTED; \ + NSSBR_LOGERR("msg_post_with_ref failed]major=%u,minor=%u,type=%u", \ + msg->param.major_type, msg->param.minor_type, msg->param.op_type); \ + }\ + } \ + } while (0) + +NSTACK_STATIC inline void +_sbr_construct_msg (data_com_msg * m, u16 major_type, u16 minor_type, + u16 type, sbr_socket_t * sk) +{ + m->param.module_type = MSG_MODULE_SBR; + m->param.major_type = major_type; + m->param.minor_type = minor_type; + m->param.err = 0; + m->param.op_type = type; + sys_sem_init (&m->param.op_completed); + m->param.receiver = ss_get_recv_obj (sbr_get_conn (sk)); + m->param.comm_receiver = ss_get_comm_private_data (sbr_get_conn (sk)); + m->param.extend_member_bit = 0; +} + +#define sbr_construct_msg(m, major_type, minor_type, type, sk) { \ + _sbr_construct_msg(m, major_type, minor_type, type, sk); \ + NSSBR_LOGINF("fd=%d,conn=%p,private_data=%p", sk->fd, sbr_get_conn(sk), ss_get_private_data(sbr_get_conn(sk))); \ + } + +#define sbr_construct_msg_dbg(m, major_type, minor_type, type, sk) { \ + _sbr_construct_msg(m, major_type, minor_type, type, sk); \ + NSSBR_LOGDBG("fd=%d,conn=%p,private_data=%p", sk->fd, sbr_get_conn(sk), ss_get_private_data(sbr_get_conn(sk))); \ + } + +/***************************************************************************** +* Prototype : sbr_attach_msg +* Description : use buf's msg first +* Input : sbr_socket_t * sk +* struct pbuf* buf +* Output : None +* Return Value : static inline data_com_msg* +* Calls : +* Called By : +* +*****************************************************************************/ +static inline data_com_msg * +sbr_attach_msg (sbr_socket_t * sk, struct spl_pbuf *buf) +{ + data_com_msg *m = NULL; + if (!sk) + { + return m; + } + + if (buf && buf->msg) + { + m = (data_com_msg *) ADDR_SHTOL (buf->msg); + } + else + { + m = SBR_MSG_MALLOC (sk); + } + + return m; +} + +/***************************************************************************** +* Prototype : sbr_handle_socket +* Description : create socket +* Input : sbr_socket_t * sk +* netconn_type_t type +* u8 proto +* Output : None +* Return Value : int +* Calls : +* Called By : +* +*****************************************************************************/ +int +sbr_handle_socket (sbr_socket_t * sk, spl_netconn_type_t type, u8 proto) +{ + data_com_msg *m = SBR_MSG_MALLOC (sk); + + if (!m) + { + NSSBR_LOGERR ("malloc msg failed]fd=%d", sk->fd); + sbr_set_sk_errno (sk, ENOMEM); + return -1; + } + + sbr_construct_msg (m, SPL_TCPIP_NEW_MSG_API, SPL_API_DO_NEWCONN, + MSG_SYN_POST, sk); + msg_new_netconn *p = (msg_new_netconn *) m->buffer; + p->conn = (spl_netconn_t *) ADDR_LTOSH (sbr_get_conn (sk)); + p->type = type; + p->proto = proto; + p->socket = sk->fd; + p->extend_member_bit = 0; + SBR_MSG_POST (m, sbr_get_msg_box (sk)); + int err = sbr_spl_err_to_errno (m->param.err); + SBR_MSG_FREE (m); + if (err != 0) + { + NSSBR_LOGERR ("handle socket failed]fd=%d,type=%d,proto=%u,err=%d", + sk->fd, type, proto, err); + sbr_set_sk_errno (sk, err); + return -1; + } + + return 0; +} + +/***************************************************************************** +* Prototype : sbr_handle_bind +* Description : bind +* Input : sbr_socket_t * sk +* spl_ip_addr_t * addr +* u16 port +* Output : None +* Return Value : int +* Calls : +* Called By : +* +*****************************************************************************/ +int +sbr_handle_bind (sbr_socket_t * sk, spl_ip_addr_t * addr, u16 port) +{ + data_com_msg *m = SBR_MSG_MALLOC (sk); + + if (!m) + { + NSSBR_LOGERR ("malloc msg failed]fd=%d", sk->fd); + sbr_set_sk_errno (sk, ENOMEM); + return -1; + } + + sbr_construct_msg (m, SPL_TCPIP_NEW_MSG_API, SPL_API_DO_BIND, MSG_SYN_POST, + sk); + msg_bind *p = (msg_bind *) m->buffer; + p->ipaddr = *addr; + p->port = port; + p->extend_member_bit = 0; + SBR_MSG_POST (m, sbr_get_msg_box (sk)); + int err = sbr_spl_err_to_errno (m->param.err); + SBR_MSG_FREE (m); + if (err != 0) + { + NSSBR_LOGERR ("handle bind failed]fd=%d,err=%d", sk->fd, err); + sbr_set_sk_errno (sk, err); + return -1; + } + + return 0; +} + +int +sbr_handle_listen (sbr_socket_t * sk, int backlog) +{ + data_com_msg *m = SBR_MSG_MALLOC (sk); + + if (!m) + { + sbr_set_sk_errno (sk, ENOMEM); + return -1; + } + + sbr_construct_msg (m, SPL_TCPIP_NEW_MSG_API, SPL_API_DO_LISTEN, + MSG_SYN_POST, sk); + msg_listen *p = (msg_listen *) m->buffer; + p->conn_pool = sbr_get_conn_pool (); + p->backlog = backlog; + p->extend_member_bit = 0; + SBR_MSG_POST (m, sbr_get_msg_box (sk)); + int err = sbr_spl_err_to_errno (m->param.err); + SBR_MSG_FREE (m); + if (err != 0) + { + NSSBR_LOGERR ("handle listen failed]fd=%d,err=%d", sk->fd, err); + sbr_set_sk_errno (sk, err); + return -1; + } + + return 0; +} + +/***************************************************************************** +* Prototype : sbr_handle_connect +* Description : connect +* Input : sbr_socket_t * sk +* spl_ip_addr_t * addr +* u16 port +* spl_ip_addr_t* local_ip +* Output : None +* Return Value : int +* Calls : +* Called By : +* +*****************************************************************************/ +int +sbr_handle_connect (sbr_socket_t * sk, spl_ip_addr_t * addr, u16 port, + spl_ip_addr_t * local_ip) +{ + data_com_msg *m = SBR_MSG_MALLOC (sk); + + if (!m) + { + NSSBR_LOGERR ("malloc msg failed]fd=%d", sk->fd); + sbr_set_sk_errno (sk, ENOMEM); + return -1; + } + + sbr_construct_msg (m, SPL_TCPIP_NEW_MSG_API, SPL_API_DO_CONNECT, + MSG_SYN_POST, sk); + msg_connect *p = (msg_connect *) m->buffer; + p->local_ip = *local_ip; + p->ipaddr = *addr; + p->port = port; + p->extend_member_bit = 0; + SBR_MSG_POST (m, sbr_get_msg_box (sk)); + int err = sbr_spl_err_to_errno (m->param.err); + SBR_MSG_FREE (m); + if (err != 0) + { + NSSBR_LOGERR ("handle connect failed]fd=%d,err=%d", sk->fd, err); + sbr_set_sk_errno (sk, err); + return -1; + } + + return 0; +} + +/***************************************************************************** +* Prototype : sbr_handle_get_name +* Description : get name +* Input : sbr_socket_t * sk +* struct sockaddr * name +* socklen_t * namelen +* u8 cmd +* Output : None +* Return Value : int +* Calls : +* Called By : +* +*****************************************************************************/ +int +sbr_handle_get_name (sbr_socket_t * sk, struct sockaddr *name, + socklen_t * namelen, u8 cmd) +{ + data_com_msg *m = SBR_MSG_MALLOC (sk); + + if (!m) + { + NSSBR_LOGERR ("malloc msg failed]fd=%d", sk->fd); + sbr_set_sk_errno (sk, ENOMEM); + return -1; + } + + sbr_construct_msg (m, SPL_TCPIP_NEW_MSG_API, SPL_API_DO_GETSOCK_NAME, + MSG_SYN_POST, sk); + msg_getaddrname *p = (msg_getaddrname *) m->buffer; + p->cmd = cmd; + p->extend_member_bit = 0; + SBR_MSG_POST (m, sbr_get_msg_box (sk)); + int err = sbr_spl_err_to_errno (m->param.err); + if (err != 0) + { + NSSBR_LOGERR ("handle get name failed]fd=%d,err=%d", sk->fd, err); + goto error; + } + else + { + if (*namelen > sizeof (p->sock_addr)) + { + *namelen = sizeof (p->sock_addr); + } + + int ret = MEMCPY_S (name, *namelen, &p->sock_addr, *namelen); + if (0 != ret) + { + NSSBR_LOGERR ("MEMCPY_S failed]fd=%d,ret=%d", sk->fd, ret); + err = EINVAL; + goto error; + } + + *namelen = sizeof (p->sock_addr); + } + + SBR_MSG_FREE (m); + return 0; + +error: + sbr_set_sk_errno (sk, err); + SBR_MSG_FREE (m); + return -1; +} + +/***************************************************************************** +* Prototype : sbr_handle_setsockopt +* Description : msg box will changed in IP_TOS +* Input : sbr_socket_t * sk +* int level +* int optname +* const void *optval +* socklen_t optlen +* Output : None +* Return Value : int +* Calls : +* Called By : +* +*****************************************************************************/ +int +sbr_handle_setsockopt (sbr_socket_t * sk, int level, int optname, + const void *optval, socklen_t optlen) +{ + data_com_msg *m = SBR_MSG_MALLOC (sk); + + if (!m) + { + NSSBR_LOGERR ("malloc msg failed]fd=%d", sk->fd); + sbr_set_sk_errno (sk, ENOMEM); + return -1; + } + + sbr_construct_msg (m, SPL_TCPIP_NEW_MSG_API, SPL_API_DO_SET_SOCK_OPT, + MSG_SYN_POST, sk); + msg_setgetsockopt *p = (msg_setgetsockopt *) m->buffer; + p->extend_member_bit = 0; + p->level = level; + p->optname = optname; + p->msg_box = NULL; /* init the value to avoid unexpected consequences */ + + if (optlen > sizeof (p->optval)) + { + optlen = sizeof (p->optval); + } + + p->optlen = optlen; + int err; + int ret = MEMCPY_S (&p->optval, sizeof (p->optval), optval, optlen); + if (0 != ret) + { + NSSBR_LOGERR ("MEMCPY_S failed]fd=%d,ret=%d", sk->fd, ret); + err = EINVAL; + goto error; + } + + SBR_MSG_POST (m, sbr_get_msg_box (sk)); + err = sbr_spl_err_to_errno (m->param.err); + if (err != 0) + { + NSSBR_LOGERR ("handle setsockopt failed]fd=%d,err=%d", sk->fd, err); + goto error; + } + + if (IPPROTO_IP == level && IP_TOS == optname && p->msg_box) + { + ss_set_msg_box (sbr_get_conn (sk), + (mring_handle) ADDR_SHTOL (p->msg_box)); + } + + SBR_MSG_FREE (m); + return 0; + +error: + sbr_set_sk_errno (sk, err); + SBR_MSG_FREE (m); + return -1; +} + +/***************************************************************************** +* Prototype : sbr_handle_getsockopt +* Description : get sockopt +* Input : sbr_socket_t * sk +* int level +* int optname +* void *optval +* socklen_t* optlen +* Output : None +* Return Value : int +* Calls : +* Called By : +* +*****************************************************************************/ +int +sbr_handle_getsockopt (sbr_socket_t * sk, int level, int optname, + void *optval, socklen_t * optlen) +{ + data_com_msg *m = SBR_MSG_MALLOC (sk); + + if (!m) + { + NSSBR_LOGERR ("malloc msg failed]fd=%d", sk->fd); + sbr_set_sk_errno (sk, ENOMEM); + return -1; + } + + sbr_construct_msg (m, SPL_TCPIP_NEW_MSG_API, SPL_API_DO_GET_SOCK_OPT, + MSG_SYN_POST, sk); + msg_setgetsockopt *p = (msg_setgetsockopt *) m->buffer; + p->extend_member_bit = 0; + p->level = level; + p->optname = optname; + + if (*optlen > sizeof (p->optval)) + { + *optlen = sizeof (p->optval); + } + + p->optlen = *optlen; + int err; + int ret = MEMCPY_S (&p->optval, sizeof (p->optval), optval, *optlen); + if (0 != ret) + { + NSSBR_LOGERR ("MEMCPY_S failed]fd=%d,ret=%d", sk->fd, ret); + err = EINVAL; + goto error; + } + + SBR_MSG_POST (m, sbr_get_msg_box (sk)); + + err = sbr_spl_err_to_errno (m->param.err); + if (err != 0) + { + NSSBR_LOGERR ("handle getsockopt failed]fd=%d,err=%d", sk->fd, err); + goto error; + } + + ret = MEMCPY_S (optval, *optlen, &p->optval.int_optval, *optlen); + if (0 != ret) + { + NSSBR_LOGERR ("MEMCPY_S failed]fd=%d,ret=%d", sk->fd, ret); + err = EINVAL; + goto error; + } + + SBR_MSG_FREE (m); + return 0; + +error: + sbr_set_sk_errno (sk, err); + SBR_MSG_FREE (m); + return -1; +} + +/***************************************************************************** +* Prototype : sbr_handle_close +* Description : need care msg_box_ref,make sure to finalize this message +* Input : sbr_socket_t * sk +* u8 how +* Output : None +* Return Value : int +* Calls : +* Called By : +* +*****************************************************************************/ +int +sbr_handle_close (sbr_socket_t * sk, u8 how) +{ + data_com_msg *m = sbr_attach_msg (sk, + (struct spl_pbuf *) + ADDR_SHTOL (sbr_get_fd_share + (sk)->recoder.head)); + + if (!m) + { + NSSBR_LOGERR ("attach msg failed]fd=%d", sk->fd); + sbr_set_sk_errno (sk, ENOMEM); + return -1; + } + + sbr_construct_msg (m, SPL_TCPIP_NEW_MSG_API, SPL_API_DO_DELCON, + MSG_ASYN_POST, sk); + msg_delete_netconn *p = (msg_delete_netconn *) m->buffer; + p->extend_member_bit = 0; + p->buf = NULL; + p->time_started = sys_now (); + p->shut = how; + p->pid = get_sys_pid (); + p->conn = (spl_netconn_t *) ADDR_LTOSH (sbr_get_conn (sk)); + p->notify_omc = FALSE; + p->msg_box_ref = SPL_MSG_BOX_NUM; + + /* to ensure that the last deal with SPL_API_DO_DELCON message */ + int i; + for (i = 0; i < SPL_MSG_BOX_NUM; ++i) + { + SBR_MSG_POST (m, + ss_get_instance_msg_box (ss_get_bind_thread_index + (sbr_get_conn (sk)), i)); + } + + return 0; +} + +/***************************************************************************** +* Prototype : sbr_handle_udp_send +* Description : udp send +* Input : sbr_socket_t * sk +* struct netbuf *buf +* spl_ip_addr_t* local_ip +* Output : None +* Return Value : int +* Calls : +* Called By : +* +*****************************************************************************/ +int +sbr_handle_udp_send (sbr_socket_t * sk, struct spl_netbuf *buf, + spl_ip_addr_t * local_ip) +{ + data_com_msg *m = + sbr_attach_msg (sk, (struct spl_pbuf *) ADDR_SHTOL (buf->p)); + + if (!m) + { + NSSBR_LOGERR ("attach msg failed]fd=%d", sk->fd); + sbr_set_sk_io_errno (sk, ENOMEM); + return -1; + } + + sbr_construct_msg_dbg (m, SPL_TCPIP_NEW_MSG_API, SPL_API_DO_SEND, + MSG_ASYN_POST, sk); + msg_send_buf *p = (msg_send_buf *) m->buffer; + p->local_ip.addr = local_ip->addr; + int ret = MEMCPY_S (&p->addr, sizeof (spl_ip_addr_t), &buf->addr, + sizeof (spl_ip_addr_t)); + if (ret != 0) + { + NSSBR_LOGERR ("MEMCPY_S failed]fd=%d,ret=%d", sk->fd, ret); + sbr_set_sk_io_errno (sk, EINVAL); + SBR_MSG_FREE (m); + return -1; + } + + p->p = buf->p; + p->port = buf->port; + p->extend_member_bit = 0; + SBR_MSG_POST_RET (m, sbr_get_msg_box (sk), ret); + + if (0 == ret) + { + return 0; + } + else + { + NSSBR_LOGERR ("post msg failed]fd=%d", sk->fd); + sbr_set_sk_io_errno (sk, EAGAIN); + return -1; + } +} + +/***************************************************************************** +* Prototype : sbr_handle_free_recv_buf +* Description : free recv buf,can't free buf in app +* Input : sbr_socket_t * sk +* Output : None +* Return Value : void +* Calls : +* Called By : +* +*****************************************************************************/ +void +sbr_handle_free_recv_buf (sbr_socket_t * sk) +{ + data_com_msg *m = sbr_attach_msg (sk, + (struct spl_pbuf *) + ADDR_SHTOL (sbr_get_fd_share + (sk)->recoder.head)); + + if (!m) + { + NSSBR_LOGERR ("attach msg failed]fd=%d", sk->fd); + return; + } + + sbr_construct_msg_dbg (m, SPL_TCPIP_NEW_MSG_API, SPL_API_DO_PBUF_FREE, + MSG_ASYN_POST, sk); + msg_free_buf *p = (msg_free_buf *) m->buffer; + p->extend_member_bit = 0; + p->buf = sbr_get_fd_share (sk)->recoder.head; + sbr_get_fd_share (sk)->recoder.head = NULL; + sbr_get_fd_share (sk)->recoder.tail = NULL; + sbr_get_fd_share (sk)->recoder.totalLen = 0; + SBR_MSG_POST (m, sbr_get_msg_box (sk)); +} + +void +sbr_handle_free_send_buf (sbr_socket_t * sk, struct spl_pbuf *buf) +{ + if (buf != NULL) + { + data_com_msg *m = sbr_attach_msg (sk, buf); + + if (!m) + { + NSSBR_LOGERR ("attach msg failed]fd=%d", sk->fd); + return; + } + + sbr_construct_msg_dbg (m, SPL_TCPIP_NEW_MSG_API, SPL_API_DO_PBUF_FREE, + MSG_ASYN_POST, sk); + msg_free_buf *p = (msg_free_buf *) m->buffer; + p->extend_member_bit = 0; + p->buf = (struct spl_pbuf *) ADDR_LTOSH (buf); + SBR_MSG_POST (m, sbr_get_msg_box (sk)); + } +} + +/***************************************************************************** +* Prototype : sbr_handle_shutdown +* Description : shut down +* Input : sbr_socket_t * sk +* u8 how +* Output : None +* Return Value : int +* Calls : +* Called By : +* +*****************************************************************************/ +int +sbr_handle_shutdown (sbr_socket_t * sk, u8 how) +{ + int err; + data_com_msg *m = SBR_MSG_MALLOC (sk); + + if (!m) + { + NSSBR_LOGERR ("malloc msg failed]fd=%d", sk->fd); + sbr_set_sk_errno (sk, ENOMEM); + return -1; + } + + sbr_construct_msg (m, SPL_TCPIP_NEW_MSG_API, SPL_API_DO_CLOSE, MSG_SYN_POST, + sk); + msg_close *p = (msg_close *) m->buffer; + p->extend_member_bit = 0; + p->time_started = sys_now (); + p->shut = how; + SBR_MSG_POST (m, sbr_get_msg_box (sk)); + err = sbr_spl_err_to_errno (m->param.err); + SBR_MSG_FREE (m); + if (err != 0) + { + NSSBR_LOGERR ("handle getsockopt failed]fd=%d,err=%d", sk->fd, err); + sbr_set_sk_errno (sk, err); + return -1; + } + + return 0; +} + +void +sbr_handle_tcp_recv (sbr_socket_t * sk, u32 len, struct spl_pbuf *buf) +{ + data_com_msg *m = sbr_attach_msg (sk, buf); + + if (!m) + { + NSSBR_LOGERR ("attach msg failed]fd=%d", sk->fd); + return; + } + + sbr_construct_msg_dbg (m, SPL_TCPIP_NEW_MSG_API, SPL_API_DO_RECV, + MSG_ASYN_POST, sk); + msg_recv_buf *p = (msg_recv_buf *) m->buffer; + p->extend_member_bit = 0; + p->len = len; + p->p = (struct spl_pbuf *) ADDR_LTOSH (buf); + SBR_MSG_POST (m, sbr_get_msg_box (sk)); +} + +int +sbr_handle_tcp_send (sbr_socket_t * sk, size_t size, struct spl_pbuf *buf, + u8 api_flag) +{ + int ret; + data_com_msg *m = sbr_attach_msg (sk, buf); + + if (!m) + { + NSSBR_LOGERR ("attach msg failed]fd=%d", sk->fd); + sbr_set_sk_io_errno (sk, ENOMEM); + return -1; + } + + sbr_construct_msg_dbg (m, SPL_TCPIP_NEW_MSG_API, SPL_API_DO_WRITE, + MSG_ASYN_POST, sk); + msg_write_buf *p = (msg_write_buf *) m->buffer; + p->extend_member_bit = 0; + p->len = size; + p->p = (struct spl_pbuf *) ADDR_LTOSH (buf); + p->apiflags = api_flag; + SBR_MSG_POST_RET (m, sbr_get_msg_box (sk), ret); + + if (0 == ret) + { + return 0; + } + else + { + NSSBR_LOGERR ("post msg failed]fd=%d", sk->fd); + sbr_set_sk_io_errno (sk, EAGAIN); + return -1; + } +} + +/* need delete sbr_handle_app_touch */ +void +sbr_handle_app_touch (void) +{ +} diff --git a/stacks/lwip_stack/lwip_src/socket/stackx_msg_handler.h b/stacks/lwip_stack/lwip_src/socket/stackx_msg_handler.h new file mode 100644 index 0000000..a52d026 --- /dev/null +++ b/stacks/lwip_stack/lwip_src/socket/stackx_msg_handler.h @@ -0,0 +1,78 @@ +/* +* +* Copyright (c) 2018 Huawei Technologies Co.,Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at: +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#ifndef STACKX_MSG_HANDLER_H +#define STACKX_MSG_HANDLER_H +#include "stackx_socket.h" +#include "stackx_ip_addr.h" +#include "stackx_netbuf.h" +#include "stackx_spl_share.h" + +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + +#define SBR_GET_SOCK_NAME 1 +#define SBR_GET_PEER_NAME 0 + +int sbr_handle_socket (sbr_socket_t * sk, spl_netconn_type_t type, u8 proto); + +int sbr_handle_bind (sbr_socket_t * sk, spl_ip_addr_t * addr, u16 port); + +int sbr_handle_listen (sbr_socket_t * sk, int backlog); + +int sbr_handle_connect (sbr_socket_t * sk, spl_ip_addr_t * addr, u16 port, + spl_ip_addr_t * local_ip); + +int sbr_handle_get_name (sbr_socket_t * sk, struct sockaddr *name, + socklen_t * namelen, u8 cmd); + +int sbr_handle_setsockopt (sbr_socket_t * sk, int level, int optname, + const void *optval, socklen_t optlen); + +int sbr_handle_getsockopt (sbr_socket_t * sk, int level, int optname, + void *optval, socklen_t * optlen); + +int sbr_handle_close (sbr_socket_t * sk, u8 how); + +int sbr_handle_udp_send (sbr_socket_t * sk, struct spl_netbuf *buf, + spl_ip_addr_t * local_ip); + +void sbr_handle_free_recv_buf (sbr_socket_t * sk); + +void sbr_handle_free_send_buf (sbr_socket_t * sk, struct spl_pbuf *buf); + +int sbr_handle_shutdown (sbr_socket_t * sk, u8 how); + +void sbr_handle_tcp_recv (sbr_socket_t * sk, u32 len, struct spl_pbuf *buf); + +int sbr_handle_tcp_send (sbr_socket_t * sk, size_t size, struct spl_pbuf *buf, + u8 api_flag); + +int sbr_handle_custom_send (sbr_socket_t * sk, struct spl_pbuf *buf, + spl_ip_addr_t * src, spl_ip_addr_t * dst, u8 tos); + +int sbr_handle_custom_close (sbr_socket_t * sk, spl_ip_addr_t * addr); + +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + +#endif diff --git a/stacks/lwip_stack/lwip_src/socket/stackx_prot_com.c b/stacks/lwip_stack/lwip_src/socket/stackx_prot_com.c new file mode 100644 index 0000000..6af2a77 --- /dev/null +++ b/stacks/lwip_stack/lwip_src/socket/stackx_prot_com.c @@ -0,0 +1,651 @@ +/* +* +* Copyright (c) 2018 Huawei Technologies Co.,Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at: +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include "stackx_msg_handler.h" +#include "stackx_prot_com.h" +#include "common_pal_bitwide_adjust.h" +#include "stackx_err.h" +#include "nstack_securec.h" +#include "nsfw_rti.h" +//#include "stackx_custom.h" + +#define FAST_SLEEP_TIME 10000 +#define FAST_RETRY_COUNT 100 +#define MAX_WAIT_TIMEOUT 0x7FFFFFFF + +/***************************************************************************** +* Prototype : sbr_getsockopt_sol_socket +* Description : get sol socket +* Input : sbr_socket_t * sk +* int optname +* void * optval +* socklen_t optlen +* Output : None +* Return Value : int +* Calls : +* Called By : +* +*****************************************************************************/ +int +sbr_getsockopt_sol_socket (sbr_socket_t * sk, int optname, void *optval, + socklen_t optlen) +{ + int err = 0; + + switch (optname) + { + case SO_ERROR: + { + if (optlen < sizeof (int)) + { + return EINVAL; + } + + /* only overwrite ERR_OK or tempoary errors */ + err = sbr_get_sk_errno (sk); + + if ((0 == err) || (EINPROGRESS == err)) + { + err = + sbr_spl_err_to_errno (ss_get_last_errno (sbr_get_conn (sk))); + sbr_set_sk_errno (sk, err); + } + else + { + sbr_set_sk_errno (sk, 0); + } + + *(int *) optval = sbr_get_sk_errno (sk); + + return 0; + } + case SO_BROADCAST: + case SO_KEEPALIVE: + case SO_RCVBUF: + case SO_SNDBUF: + case SO_REUSEADDR: + if (optlen < sizeof (int)) + { + err = EINVAL; + } + + break; + case SO_RCVTIMEO: + case SO_SNDTIMEO: + if (optlen < sizeof (struct timeval)) + { + err = EINVAL; + } + + break; + case SO_LINGER: + if (optlen < sizeof (struct linger)) + { + err = EINVAL; + } + + break; + default: + err = ENOPROTOOPT; + break; + } + + return err; +} + +/***************************************************************************** +* Prototype : sbr_getsockopt_ipproto_ip +* Description : get ipproto ip +* Input : int optname +* void * optval +* socklen_t optlen +* Output : None +* Return Value : int +* Calls : +* Called By : +* +*****************************************************************************/ +int +sbr_getsockopt_ipproto_ip (int optname, void *optval, socklen_t optlen) +{ + int err = 0; + + switch (optname) + { + case IP_TOS: + if (optlen < sizeof (u8)) + { + err = EINVAL; + } + + break; + default: + err = ENOPROTOOPT; + break; + } + + return err; +} + +/***************************************************************************** +* Prototype : sbr_pick_timeout +* Description : pick time +* Input : const void * optval +* socklen_t optlen +* i32* timeout +* Output : None +* Return Value : static inline int +* Calls : +* Called By : +* +*****************************************************************************/ +static inline int +sbr_pick_timeout (const void *optval, socklen_t optlen, i32 * timeout) +{ + if (optlen < sizeof (struct timeval)) + { + return EINVAL; + } + + struct timeval *time_val = (struct timeval *) optval; + if ((time_val->tv_usec < 0) || (time_val->tv_usec > USEC_TO_SEC)) + { + return EDOM; + } + else + { + if (time_val->tv_sec < 0) + { + *timeout = 0; + } + else + { + *timeout = MAX_WAIT_TIMEOUT; + if ((time_val->tv_sec != 0) || (time_val->tv_usec != 0)) + { + if (time_val->tv_sec < ((MAX_WAIT_TIMEOUT / 1000) - 1)) + { + *timeout = + time_val->tv_sec * 1000 + time_val->tv_usec / 1000; + } + } + } + } + + return 0; +} + +/***************************************************************************** +* Prototype : sbr_setsockopt_sol_socket +* Description : set sol socket +* Input : sbr_socket_t * sk +* int optname +* const void * optval +* socklen_t optlen +* netconn_type_t type +* Output : None +* Return Value : int +* Calls : +* Called By : +* +*****************************************************************************/ +int +sbr_setsockopt_sol_socket (sbr_socket_t * sk, int optname, const void *optval, + socklen_t optlen, spl_netconn_type_t type) +{ + int err = 0; + + switch (optname) + { + case SO_REUSEADDR: + case SO_BROADCAST: + case SO_KEEPALIVE: + case SO_RCVBUF: + case SO_SNDBUF: + if (optlen < sizeof (int)) + { + err = EINVAL; + } + + break; + case SO_RCVTIMEO: + err = + sbr_pick_timeout (optval, optlen, + &sbr_get_fd_share (sk)->recv_timeout); + break; + case SO_SNDTIMEO: + err = + sbr_pick_timeout (optval, optlen, + &sbr_get_fd_share (sk)->send_timeout); + break; + case SO_LINGER: + if (optlen < sizeof (struct linger)) + { + err = EINVAL; + } + + break; + default: + err = ENOPROTOOPT; + break; + } + + return err; +} + +/***************************************************************************** +* Prototype : sbr_setsockopt_ipproto_ip +* Description : set ipproto ip +* Input : int optname +* const void * optval +* socklen_t optlen +* netconn_type_t type +* Output : None +* Return Value : int +* Calls : +* Called By : +* +*****************************************************************************/ +int +sbr_setsockopt_ipproto_ip (int optname, const void *optval, socklen_t optlen, + spl_netconn_type_t type) +{ + int err = 0; + + switch (optname) + { + case IP_TOS: + if (optlen < sizeof (u8)) + { + err = EINVAL; + } + + break; + case IP_MULTICAST_TTL: + if (optlen < sizeof (u8)) + { + err = EINVAL; + break; + } + + if (type != SPL_NETCONN_UDP) + { + err = EAFNOSUPPORT; + break; + } + + break; + case IP_MULTICAST_IF: + if (optlen < sizeof (struct in_addr)) + { + err = EINVAL; + break; + } + + if (type != SPL_NETCONN_UDP) + { + err = EAFNOSUPPORT; + break; + } + + break; + case IP_MULTICAST_LOOP: + if (optlen < sizeof (u8)) + { + err = EINVAL; + break; + } + + if (type != SPL_NETCONN_UDP) + { + err = EAFNOSUPPORT; + break; + } + + break; + default: + err = ENOPROTOOPT; + break; + } + + return err; +} + +/***************************************************************************** +* Prototype : sbr_dequeue_buf +* Description : dequeue buf +* Input : sbr_socket_t * sk +* void **buf +* i32 timeout +* u8 use_l4_ring +* Output : None +* Return Value : int +* Calls : +* Called By : +* +*****************************************************************************/ +int +sbr_dequeue_buf (sbr_socket_t * sk, void **buf, i32 timeout) +{ + mring_handle ring = ss_get_recv_ring (sbr_get_conn (sk)); + + struct timespec start, end; + long timediff; + long timediff_sec; + long timeout_sec = (long) (timeout / 1000); + unsigned int retry_count = 0; + + if (timeout > 0) + { + if (unlikely (0 != clock_gettime (CLOCK_MONOTONIC, &start))) + { + NSSBR_LOGERR ("Failed to get time, errno = %d", errno); + } + } + + if (!ss_recv_ring_valid (sbr_get_conn (sk))) + { + NSSBR_LOGDBG ("ring is invalid]fd=%d", sk->fd); + sbr_set_sk_io_errno (sk, ENOTCONN); + return -1; + } + + int dequeue_ret = 0; + pid_t pid = get_sys_pid (); + + while (1) + { + if (ss_is_shut_rd (sbr_get_conn (sk))) + { + NSSBR_LOGDBG ("is shut rd]fd=%d", sk->fd); + sbr_set_sk_io_errno (sk, EINVAL); + return -1; + } + + dequeue_ret = nsfw_mem_ring_dequeue (ring, buf); + if (1 == dequeue_ret) + { + pbuf_set_recycle_flg ((struct spl_pbuf *) *buf, pid); /*release buf hold by app on abnormal exit */ + return 0; + } + else if (0 == dequeue_ret) + { + /*If the peer reset connect, try to receive data only once */ + if (ss_can_not_recv (sbr_get_conn (sk))) + { + NS_LOG_CTRL (LOG_CTRL_RECV_QUEUE_FULL, LOGSBR, "NSSBR", + NSLOG_WAR, "try to fetch one more time]fd=%d", + sk->fd); + /** + * l4_ring will not be processed here as can_not_recv flag is + * set by TCP only. + */ + if (1 == nsfw_mem_ring_dequeue (ring, buf)) + { + pbuf_set_recycle_flg ((struct spl_pbuf *) *buf, pid); + return 0; + } + + sbr_set_sk_io_errno (sk, ENOTCONN); + return -1; + } + + int err = ss_get_last_errno (sbr_get_conn (sk)); + if (SPL_ERR_IS_FATAL (err) || err == ERR_TIMEOUT) /* have to handle ERR_TIMEOUT here, when TCP keepalive timeout. */ + { + NS_LOG_CTRL (LOG_CTRL_RECV_QUEUE_FULL, LOGSBR, "NSSBR", + NSLOG_ERR, "connection fatal error!err=%d", err); + + /* l4_ring need to be handled in the future */ + if (1 == nsfw_mem_ring_dequeue (ring, buf)) + { + pbuf_set_recycle_flg ((struct spl_pbuf *) *buf, pid); + return 0; + } + + sbr_set_sk_io_errno (sk, sbr_spl_err_to_errno (err)); + return -1; + } + + if (0 > timeout) + { + sbr_set_sk_io_errno (sk, EWOULDBLOCK); + return -1; + } + + if (retry_count < FAST_RETRY_COUNT) + { + sys_sleep_ns (0, FAST_SLEEP_TIME); + retry_count++; + } + else + { + sys_sleep_ns (0, sbr_get_fd_share (sk)->block_polling_time); + } + + if (timeout > 0) + { + if (unlikely (0 != clock_gettime (CLOCK_MONOTONIC, &end))) + { + NSSBR_LOGERR ("Failed to get time, errno = %d", errno); + } + timediff_sec = end.tv_sec - start.tv_sec; + if (timediff_sec >= timeout_sec) + { + timediff = end.tv_nsec > start.tv_nsec ? + (timediff_sec * 1000) + (end.tv_nsec - + start.tv_nsec) / + USEC_TO_SEC : (timediff_sec * 1000) - + ((start.tv_nsec - end.tv_nsec) / USEC_TO_SEC); + if (timediff > timeout) + { + NSSBR_LOGDBG ("recv timeout]fd=%d", sk->fd); + sbr_set_sk_io_errno (sk, EWOULDBLOCK); + return -1; + } + } + } + } + else + { + NSSBR_LOGERR ("dequeue failed]fd=%d", sk->fd); + sbr_set_sk_io_errno (sk, EINVAL); + return -1; + } + } +} + +int +sbr_com_peak (sbr_socket_t * sk) +{ + NSSBR_LOGERR ("not implement]fd=%d", sk->fd); + return -1; +} + +/***************************************************************************** +* Prototype : sbr_com_try_lock_recv +* Description : try lock recv +* Input : sbr_socket_t * sk +* Output : None +* Return Value : int +* Calls : +* Called By : +* +*****************************************************************************/ +int +sbr_com_try_lock_recv (sbr_socket_t * sk) +{ +#ifdef SBR_USE_LOCK + return common_spinlock_try_lock_with_pid (&sbr_get_fd_share (sk)->recv_lock, + get_sys_pid ()); +#else + return 1; +#endif +} + +/***************************************************************************** +* Prototype : sbr_com_lock_common +* Description : lock common +* Input : sbr_socket_t * sk +* Output : None +* Return Value : void +* Calls : +* Called By : +* +*****************************************************************************/ +void +sbr_com_lock_common (sbr_socket_t * sk) +{ +#ifdef SBR_USE_LOCK + while (!common_spinlock_try_lock_with_pid + (&sbr_get_fd_share (sk)->common_lock, get_sys_pid ())) + { + sys_sleep_ns (0, 0); + } +#endif + +} + +/***************************************************************************** +* Prototype : sbr_com_unlock_common +* Description : unlock common +* Input : sbr_socket_t * sk +* Output : None +* Return Value : void +* Calls : +* Called By : +* +*****************************************************************************/ +void +sbr_com_unlock_common (sbr_socket_t * sk) +{ +#ifdef SBR_USE_LOCK + common_spinlock_unlock (&sbr_get_fd_share (sk)->common_lock); +#endif +} + +/***************************************************************************** +* Prototype : sbr_com_free_recv_buf +* Description : free recv buf,can't free buf in app +* Input : sbr_socket_t * sk +* struct spl_pbuf *p +* Output : None +* Return Value : void +* Calls : +* Called By : +* +*****************************************************************************/ +void +sbr_com_free_recv_buf (sbr_socket_t * sk, struct spl_pbuf *p) +{ + struct spl_pbuf *p_orig = p; + if (p) + { + p->freeNext = NULL; + p = (struct spl_pbuf *) ADDR_LTOSH (p); + + if (sbr_get_fd_share (sk)->recoder.totalLen > 0) + { + ((struct spl_pbuf *) + ADDR_SHTOL (sbr_get_fd_share (sk)->recoder.tail))->freeNext = p; + sbr_get_fd_share (sk)->recoder.tail = p; + } + else + { + sbr_get_fd_share (sk)->recoder.head = p; + sbr_get_fd_share (sk)->recoder.tail = p; + } + + sbr_get_fd_share (sk)->recoder.totalLen++; + } + + /* send MSG only if it's a big packet or number of packets larger than 32 */ + if ((p_orig && p_orig->tot_len > MAX_RECV_FREE_LEN) || + (sbr_get_fd_share (sk)->recoder.totalLen >= MAX_RECV_FREE_BUF)) + { + sbr_handle_free_recv_buf (sk); + } + +} + +/***************************************************************************** +* Prototype : sbr_get_sockaddr_and_len +* Description : get addr and len +* Input : u16 port +* spl_ip_addr_t * ipaddr +* struct sockaddr * addr +* socklen_t * addrlen +* Output : None +* Return Value : int +* Calls : +* Called By : +* +*****************************************************************************/ +int +sbr_get_sockaddr_and_len (u16 port, spl_ip_addr_t * ipaddr, + struct sockaddr *addr, socklen_t * addrlen) +{ + int ret; + struct sockaddr_in sin; + + ret = MEMSET_S (&sin, sizeof (sin), 0, sizeof (sin)); + if (0 != ret) + { + NSSBR_LOGERR ("MEMSET_S failed]ret=%d.", ret); + return -1; + } + + sin.sin_family = AF_INET; + sin.sin_port = htons (port); + inet_addr_from_ipaddr (&sin.sin_addr, ipaddr); + if (*addrlen > sizeof (struct sockaddr)) + { + *addrlen = sizeof (struct sockaddr); + } + + if (*addrlen > 0) + { + ret = MEMCPY_S (addr, sizeof (struct sockaddr), &sin, *addrlen); + if (0 != ret) + { + NSSBR_LOGERR ("MEMCPY_S failed]ret=%d", ret); + + return -1; + } + } + + return 0; +} + +/***************************************************************************** +* Prototype : sbr_com_set_app_info +* Description : set app info to netconn +* Input : sbr_socket_t * sk +* void* appinfo +* Output : None +* Return Value : void +* Calls : +* Called By : +* +*****************************************************************************/ +void +sbr_com_set_app_info (sbr_socket_t * sk, void *appinfo) +{ + return; +} diff --git a/stacks/lwip_stack/lwip_src/socket/stackx_prot_com.h b/stacks/lwip_stack/lwip_src/socket/stackx_prot_com.h new file mode 100644 index 0000000..054393b --- /dev/null +++ b/stacks/lwip_stack/lwip_src/socket/stackx_prot_com.h @@ -0,0 +1,159 @@ +/* +* +* Copyright (c) 2018 Huawei Technologies Co.,Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at: +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#ifndef STACKX_PROT_COM_H +#define STACKX_PROT_COM_H +#include "stackx_socket.h" +#include "stackx_ip_addr.h" +#include "stackx_res_mgr.h" +#include "stackx_pbuf.h" +#include "stackx_macro.h" + +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + +#define MAX_RECV_FREE_BUF 32 +#define MAX_RECV_FREE_LEN (SPL_FRAME_MTU - SPL_IP_HLEN) +#define USEC_TO_SEC 1000000 + +#ifndef NSTACK_SOCKOPT_CHECK +#define NSTACK_SOCKOPT_CHECK +/* setsockopt level type*/ +enum +{ + NSTACK_SOCKOPT = 0xff02 +}; +/*setsockopt optname type*/ +enum +{ + NSTACK_SEM_SLEEP = 0X001 +}; +#endif + +#define sbr_malloc_tx_pbuf(len, offset) sbr_malloc_pbuf(sbr_get_tx_pool(), len, TX_MBUF_MAX_LEN, offset) + +static inline int +sbr_spl_err_to_errno (i32 err) +{ + static int table[] = { + 0, /* ERR_OK 0 No error, everything OK. */ + ENOMEM, /* ERR_MEM -1 Out of memory error. */ + ENOBUFS, /* ERR_BUF -2 Buffer error. */ + ETIMEDOUT, /* ERR_TIMEOUT -3 Timeout */ + EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */ + EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */ + EINVAL, /* ERR_VAL -6 Illegal value. */ + EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */ + EADDRINUSE, /* ERR_USE -8 Address in use. */ + EISCONN, /* ERR_ISCONN -9 Already connected. */ + ECONNABORTED, /* ERR_ABRT -10 Connection aborted. */ + ECONNRESET, /* ERR_RST -11 Connection reset. */ + ENOTCONN, /* ERR_CLSD -12 Connection closed. */ + ENOTCONN, /* ERR_CONN -13 Not connected. */ + EIO, /* ERR_ARG -14 Illegal argument. */ + -1, /* ERR_IF -15 Low-level netif error */ + EALREADY, /*ERR_ALREADY -16 previous connect attemt has not yet completed */ + EPROTOTYPE, /*ERR_PROTOTYPE -17 prototype error or some other generic error. + the operation is not allowed on current socket */ + EINVAL, /* ERR_CALLBACK -18 callback error */ + EADDRNOTAVAIL, /* ERR_CANTASSIGNADDR -19 Cannot assign requested address */ + EIO, /* ERR_CONTAINER_ID -20 Illegal container id */ + ENOTSOCK, /*ERR_NOTSOCK -21 not a socket */ + -1, /* ERR_CLOSE_WAIT -22 closed in established state */ + EPROTONOSUPPORT, /* ERR_EPROTONOSUPPORT -23 Protocol not supported */ + ECONNABORTED /* ERR_FAULTRECOVERY -24 SPL just recovered from a fatal fault */ + }; + + if (((-(err)) >= 0) + && (-(err)) < (i32) (sizeof (table) / sizeof (table[0]))) + { + return table[-(err)]; + } + else + { + return EIO; + } +} + +int sbr_getsockopt_sol_socket (sbr_socket_t * sk, int optname, void *optval, + socklen_t optlen); +int sbr_getsockopt_ipproto_ip (int optname, void *optval, socklen_t optlen); +int sbr_setsockopt_sol_socket (sbr_socket_t * sk, int optname, + const void *optval, socklen_t optlen, + spl_netconn_type_t type); +int sbr_setsockopt_ipproto_ip (int optname, const void *optval, + socklen_t optlen, spl_netconn_type_t type); +int sbr_dequeue_buf (sbr_socket_t * sk, void **buf, i32 timeout); +int sbr_com_peak (sbr_socket_t * sk); +int sbr_com_try_lock_recv (sbr_socket_t * sk); +/***************************************************************************** +* Prototype : sbr_com_lock_recv +* Description : lock recv +* Input : sbr_socket_t * sk +* Output : None +* Return Value : void +* Calls : +* Called By : +* +*****************************************************************************/ +static inline void +sbr_com_lock_recv (sbr_socket_t * sk) +{ +#ifdef SBR_USE_LOCK + while (!common_spinlock_try_lock_with_pid + (&sbr_get_fd_share (sk)->recv_lock, get_sys_pid ())) + { + sys_sleep_ns (0, 0); + } +#endif + +} + +/***************************************************************************** +* Prototype : sbr_com_unlock_recv +* Description : unlock recv +* Input : sbr_socket_t * sk +* Output : None +* Return Value : void +* Calls : +* Called By : +* +*****************************************************************************/ +static inline void +sbr_com_unlock_recv (sbr_socket_t * sk) +{ +#ifdef SBR_USE_LOCK + common_spinlock_unlock (&sbr_get_fd_share (sk)->recv_lock); +#endif +} + +void sbr_com_lock_common (sbr_socket_t * sk); +void sbr_com_unlock_common (sbr_socket_t * sk); +void sbr_com_free_recv_buf (sbr_socket_t * sk, struct spl_pbuf *p); +int sbr_get_sockaddr_and_len (u16 port, spl_ip_addr_t * ip_addr, + struct sockaddr *addr, socklen_t * addrlen); +void sbr_com_set_app_info (sbr_socket_t * sk, void *appinfo); + +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + +#endif diff --git a/stacks/lwip_stack/lwip_src/socket/stackx_protocol_api.c b/stacks/lwip_stack/lwip_src/socket/stackx_protocol_api.c new file mode 100644 index 0000000..94ef483 --- /dev/null +++ b/stacks/lwip_stack/lwip_src/socket/stackx_protocol_api.c @@ -0,0 +1,94 @@ +/* +* +* Copyright (c) 2018 Huawei Technologies Co.,Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at: +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "sbr_protocol_api.h" +#include "stackx_epoll_api.h" +#include "stackx_socket.h" +#include "stackx_res_mgr.h" +#include "stackx_common_opt.h" +#include "common_mem_api.h" +#include "stackx_event.h" + +extern sbr_fdopt tcp_fdopt; +extern sbr_fdopt udp_fdopt; +extern sbr_fdopt raw_fdopt; +extern sbr_fdopt custom_fdopt; + +/***************************************************************************** +* Prototype : sbr_init_protocol +* Description : init protocol +* Input : None +* Output : None +* Return Value : int +* Calls : +* Called By : +* +*****************************************************************************/ +int +sbr_init_protocol () +{ + return sbr_init_stackx (); +} + +/***************************************************************************** +* Prototype : sbr_get_fdopt +* Description : get fdopt by domain type protocol +* Input : int domain +* int type +* int protocol +* Output : None +* Return Value : sbr_fdopt* +* Calls : +* Called By : +* +*****************************************************************************/ +sbr_fdopt * +sbr_get_fdopt (int domain, int type, int protocol) +{ + if (domain != AF_INET) + { + NSSBR_LOGERR ("domain is not AF_INET]domain=%d", domain); + sbr_set_errno (EAFNOSUPPORT); + return NULL; + } + + sbr_fdopt *fdopt = NULL; + + switch (type & (~(O_NONBLOCK | SOCK_CLOEXEC))) + { + case SOCK_DGRAM: + fdopt = &udp_fdopt; + break; + case SOCK_STREAM: + fdopt = &tcp_fdopt; + break; + + default: + NSSBR_LOGDBG ("type is unknown]type=%d", type); + sbr_set_errno (ESOCKTNOSUPPORT); + return NULL; + } + + return fdopt; +} + +/* app send its version info to nStackMain */ +extern void sbr_handle_app_touch (void); +void +sbr_app_touch_in (void) +{ + sbr_handle_app_touch (); +} diff --git a/stacks/lwip_stack/lwip_src/socket/stackx_res_mgr.c b/stacks/lwip_stack/lwip_src/socket/stackx_res_mgr.c new file mode 100644 index 0000000..331eee1 --- /dev/null +++ b/stacks/lwip_stack/lwip_src/socket/stackx_res_mgr.c @@ -0,0 +1,246 @@ +/* +* +* Copyright (c) 2018 Huawei Technologies Co.,Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at: +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "stackx_res_mgr.h" +#include "stackx_common.h" +#include "nstack_securec.h" +#include "nsfw_msg.h" +#include "stackx_common.h" +#include "nsfw_mgr_com_api.h" +#include "stackx_cfg.h" +#include "nsfw_maintain_api.h" +//#include "stackx_dfx_api.h" +#include "stackx_app_res.h" + +sbr_share_group g_share_group = { 0 }; + +#define SLOW_SLEEP_TIME 500000 + +NSTACK_STATIC inline void +sbr_reset_fd_share (sbr_fd_share * fd_share) +{ + common_mem_spinlock_init (&fd_share->recv_lock); + common_mem_spinlock_init (&fd_share->common_lock); + fd_share->err = 0; + fd_share->lastoffset = 0; + fd_share->lastdata = NULL; + fd_share->recoder.head = NULL; + fd_share->recoder.tail = NULL; + fd_share->recoder.totalLen = 0; + fd_share->recv_timeout = 0; + fd_share->send_timeout = 0; + fd_share->rcvlowat = 1; + fd_share->block_polling_time = SLOW_SLEEP_TIME; +} + +/***************************************************************************** +* Prototype : sbr_init_tx_pool +* Description : get tx buf pool +* Input : None +* Output : None +* Return Value : static int +* Calls : +* Called By : +* +*****************************************************************************/ +NSTACK_STATIC int +sbr_init_tx_pool () +{ + mpool_handle pool[1]; + pool[0] = NULL; + + (void) sbr_malloc_tx_pool (get_sys_pid (), pool, 1); + if (pool[0]) + { + g_share_group.tx_pool = pool[0]; + return 0; + } + + return -1; +} + +/***************************************************************************** +* Prototype : sbr_init_app_res +* Description : get msg, conn pool +* Input : None +* Output : None +* Return Value : static int +* Calls : +* Called By : +* +*****************************************************************************/ +NSTACK_STATIC int +sbr_init_app_res () +{ + g_share_group.conn_pool = sbr_get_instance_conn_pool (0); + if (!g_share_group.conn_pool) + { + return -1; + } + + return 0; +} + +/*=========== get share config for app =============*/ +NSTACK_STATIC inline int +get_share_config () +{ + static nsfw_mem_name g_cfg_mem_info = + { NSFW_SHMEM, NSFW_PROC_MAIN, NSTACK_SHARE_CONFIG }; + + mzone_handle base_cfg_mem = nsfw_mem_zone_lookup (&g_cfg_mem_info); + if (NULL == base_cfg_mem) + { + NSSOC_LOGERR ("get config share mem failed."); + return -1; + } + + if (get_share_cfg_from_mem (base_cfg_mem) < 0) + { + NSSOC_LOGERR ("get share config failed."); + return -1; + } + + NSSOC_LOGDBG ("get share config success."); + return 0; +} + +int +nstack_set_share_config () +{ + return 0; +} + +/***************************************************************************** +* Prototype : sbr_init_stackx +* Description : init stackx res +* Input : None +* Output : None +* Return Value : int +* Calls : +* Called By : +* +*****************************************************************************/ +int +sbr_init_stackx () +{ + sbr_init_cfg (); + if (get_share_config () < 0) + { + NSSBR_LOGERR ("get_share_config failed"); + return -1; + } + + if (sbr_attach_group_array () != 0) + { + NSSBR_LOGERR ("sbr_attach_group_array failed"); + return -1; + } + + NSSBR_LOGDBG ("sbr_attach_group_array ok"); + + if (sbr_init_tx_pool () != 0) + { + NSSBR_LOGERR ("init tx pool failed"); + return -1; + } + + NSSBR_LOGDBG ("init tx pool ok"); + + if (sbr_init_app_res () != 0) + { + NSSBR_LOGERR ("sbr_init_app_res failed"); + return -1; + } + + NSSBR_LOGDBG ("sbr_init_app_res ok"); + NSSBR_LOGDBG ("sbr_init_stackx ok"); + return 0; +} + +/***************************************************************************** +* Prototype : sbr_malloc_conn_for_sk +* Description : malloc netconn for sk,need add pid +* Input : sbr_socket_t* sk +* netconn_type_t type +* Output : None +* Return Value : int +* Calls : +* Called By : +* +*****************************************************************************/ +int +sbr_malloc_conn_for_sk (sbr_socket_t * sk, spl_netconn_type_t type) +{ + spl_netconn_t *conn = ss_malloc_conn_app (g_share_group.conn_pool, type); + + if (!conn) + { + NSSBR_LOGERR ("malloc conn failed]fd=%d", sk->fd); + sbr_set_errno (ENOBUFS); + return -1; + } + + NSSBR_LOGINF ("malloc conn ok]fd=%d,conn=%p", sk->fd, conn); + + u16 thread_index = 0; + ss_set_bind_thread_index (conn, thread_index); + ss_set_msg_box (conn, ss_get_instance_msg_box (thread_index, 0)); + + sbr_fd_share *fd_share = (sbr_fd_share *) ((char *) conn + SS_NETCONN_SIZE); + sbr_reset_fd_share (fd_share); + + sk->stack_obj = (void *) conn; + sk->sk_obj = (void *) fd_share; + return 0; +} + +int +sbr_init_conn_for_accept (sbr_socket_t * sk, spl_netconn_t * conn) +{ + if (!conn) + { + sbr_set_sk_errno (sk, ENOBUFS); + return -1; + } + + NSSBR_LOGINF ("accept conn ok]fd=%d,conn=%p,private_data=%p", sk->fd, conn, + conn->private_data); + + if (ss_add_pid (conn, get_sys_pid ()) < 0) + { + NSSBR_LOGERR ("ss_add_pid failed]fd=%d", sk->fd); + } + + ss_set_accept_from (conn, NULL); /* need clear flag */ + + sbr_fd_share *fd_share = (sbr_fd_share *) ((char *) conn + SS_NETCONN_SIZE); + sbr_reset_fd_share (fd_share); + + sk->stack_obj = (void *) conn; + sk->sk_obj = (void *) fd_share; + + return 0; +} + +void +sbr_free_conn_from_sk (sbr_socket_t * sk) +{ + ss_free_conn (sbr_get_conn (sk)); + sk->stack_obj = NULL; + sk->sk_obj = NULL; + NSSBR_LOGDBG ("free conn ok]fd=%d", sk->fd); +} diff --git a/stacks/lwip_stack/lwip_src/socket/stackx_res_mgr.h b/stacks/lwip_stack/lwip_src/socket/stackx_res_mgr.h new file mode 100644 index 0000000..e139644 --- /dev/null +++ b/stacks/lwip_stack/lwip_src/socket/stackx_res_mgr.h @@ -0,0 +1,69 @@ +/* +* +* Copyright (c) 2018 Huawei Technologies Co.,Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at: +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#ifndef STACKX_RES_MGR_H +#define STACKX_RES_MGR_H +#include "stackx_socket.h" +#include "stackx_ip_tos.h" +#include "stackx_tx_box.h" +#include "stackx_app_res.h" + +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + +typedef struct +{ + mring_handle conn_pool; + mpool_handle tx_pool; +} sbr_share_group; + +extern sbr_share_group g_share_group; + +static inline mpool_handle +sbr_get_tx_pool () +{ + return g_share_group.tx_pool; +} + +static inline mring_handle +sbr_get_conn_pool () +{ + return (mring_handle) ADDR_LTOSH (g_share_group.conn_pool); +} + +static inline mring_handle +sbr_get_spl_msg_box (sbr_socket_t * sk, u8 tos) +{ + return + ss_get_instance_msg_box (ss_get_bind_thread_index (sbr_get_conn (sk)), + stackx_get_prio (tos)); +} + +int sbr_init_stackx (); +int sbr_malloc_conn_for_sk (sbr_socket_t * sk, spl_netconn_type_t type); +int sbr_init_conn_for_accept (sbr_socket_t * sk, spl_netconn_t * conn); +void sbr_free_conn_from_sk (sbr_socket_t * sk); + +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + +#endif diff --git a/stacks/lwip_stack/lwip_src/socket/stackx_socket.h b/stacks/lwip_stack/lwip_src/socket/stackx_socket.h new file mode 100644 index 0000000..e344535 --- /dev/null +++ b/stacks/lwip_stack/lwip_src/socket/stackx_socket.h @@ -0,0 +1,141 @@ +/* +* +* Copyright (c) 2018 Huawei Technologies Co.,Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at: +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#ifndef STACKX_SOCKET_H +#define STACKX_SOCKET_H +#include "sbr_protocol_api.h" +#include "stackx_spl_share.h" +#include "nstack_log.h" +#include "stackx_pbuf.h" +#include "common_mem_spinlock.h" + +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + +typedef struct +{ + PRIMARY_ADDR struct spl_pbuf *head; + PRIMARY_ADDR struct spl_pbuf *tail; + int totalLen; +} sbr_recvbuf_recoder; + +/* need fork and recycle */ +typedef struct +{ + common_mem_spinlock_t recv_lock; + common_mem_spinlock_t common_lock; + PRIMARY_ADDR void *lastdata; + u32 lastoffset; + sbr_recvbuf_recoder recoder; + i32 recv_timeout; + i32 send_timeout; + i32 rcvlowat; + int err; + u64 block_polling_time; + i64 extend_member_bit; +} sbr_fd_share; + +/* check sbr_fd_share size */ +SIZE_OF_TYPE_NOT_LARGER_THAN (sbr_fd_share, SBR_FD_SIZE); + +#define sbr_get_fd_share(sk) ((sbr_fd_share*)sk->sk_obj) + +#define sbr_get_conn(sk) ((spl_netconn_t*)sk->stack_obj) + +#define sbr_get_msg_box(sk) ss_get_msg_box(sbr_get_conn(sk)) + +/***************************************************************************** +* Prototype : sbr_set_sk_errno +* Description : set errno for sk +* Input : sbr_socket_t * sk +* int err +* Output : None +* Return Value : static inline void +* Calls : +* Called By : +* +*****************************************************************************/ +static inline void +sbr_set_sk_errno (sbr_socket_t * sk, int err) +{ + sbr_get_fd_share (sk)->err = err; + if (err != 0) + { + if (sbr_get_conn (sk)) + { + NSSBR_LOGERR ("fd=%d,errno=%d,conn=%p,private_data=%p", sk->fd, err, + sbr_get_conn (sk), + ss_get_private_data (sbr_get_conn (sk))); + } + + sbr_set_errno (err); + } +} + +/***************************************************************************** +* Prototype : sbr_set_sk_io_errno +* Description : set errno for sk in send/recv func, in case of too many logs +* Input : sbr_socket_t * sk +* int err +* Output : None +* Return Value : static inline void +* Calls : +* Called By : +* +*****************************************************************************/ +static inline void +sbr_set_sk_io_errno (sbr_socket_t * sk, int err) +{ + sbr_get_fd_share (sk)->err = err; + if (err != 0) + { + if (sbr_get_conn (sk)) + { + NSSBR_LOGDBG ("fd=%d,errno=%d,conn=%p,private_data=%p", sk->fd, err, + sbr_get_conn (sk), + ss_get_private_data (sbr_get_conn (sk))); + } + + sbr_set_errno (err); + } +} + +/***************************************************************************** +* Prototype : sbr_get_sk_errno +* Description : get sk's errno +* Input : sbr_socket_t * sk +* Output : None +* Return Value : static inline int +* Calls : +* Called By : +* +*****************************************************************************/ +static inline int +sbr_get_sk_errno (sbr_socket_t * sk) +{ + return sbr_get_fd_share (sk)->err; +} + +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + +#endif diff --git a/stacks/lwip_stack/lwip_src/socket/stackx_tcp.c b/stacks/lwip_stack/lwip_src/socket/stackx_tcp.c new file mode 100644 index 0000000..c64dc7b --- /dev/null +++ b/stacks/lwip_stack/lwip_src/socket/stackx_tcp.c @@ -0,0 +1,1696 @@ +/* +* +* Copyright (c) 2018 Huawei Technologies Co.,Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at: +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "stackx_prot_com.h" +#include "stackx_msg_handler.h" +#include "stackx_pbuf.h" +#include "stackx_epoll_api.h" +#include "nstack_securec.h" +#include "common_pal_bitwide_adjust.h" +#include "common_mem_mbuf.h" +#include "stackx_spl_share.h" +#include "stackx_err.h" +#include "stackx_cfg.h" +#include "spl_opt.h" +//#include "stackx_tcp_sctl.h" +#include "stackx_tcp_opt.h" +//#include "stackx_dfx_api.h" +#include "stackx_spl_msg.h" +#ifdef HAL_LIB +#else +#include "rte_memcpy.h" +#endif + +static void +sbr_tcp_init_conn (spl_netconn_t * conn) +{ + conn->tcp_sndbuf = CONN_TCP_MEM_DEF_LINE; + conn->conn_pool = sbr_get_conn_pool (); +} + +/* need close after accept failed */ +static void +sbr_tcp_accept_failed (sbr_socket_t * sk) +{ + (void) sbr_handle_close (sk, 0); + sk->stack_obj = NULL; + sk->sk_obj = NULL; +} + +NSTACK_STATIC int +sbr_tcp_socket (sbr_socket_t * sk, int domain, int type, int protocol) +{ + int err = 0; + + if (sbr_malloc_conn_for_sk (sk, SPL_NETCONN_TCP) != 0) + { + return -1; + } + + sbr_tcp_init_conn (sbr_get_conn (sk)); + + err = sbr_handle_socket (sk, SPL_NETCONN_TCP, 0); + if (0 == err) + { + /* Prevent automatic window updates, we do this on our own! */ + ss_set_noautorecved_flag (sbr_get_conn (sk), 1); + + ss_set_nonblock_flag (sbr_get_conn (sk), (type & O_NONBLOCK)); + + ss_add_recv_event (sbr_get_conn (sk)); + + ss_set_send_event (sbr_get_conn (sk), 1); + + NSSBR_LOGINF ("add write and read events]fd=%d", sk->fd); + + return 0; + } + else + { + sbr_free_conn_from_sk (sk); + return err; + } +} + +NSTACK_STATIC int +sbr_tcp_bind (sbr_socket_t * sk, const struct sockaddr *name, + socklen_t namelen) +{ + const struct sockaddr_in *addr_in = (const struct sockaddr_in *) name; + NSSBR_LOGINF ("fd=%d,addr=%s,port=%d,conn=%p,private_data=%p", sk->fd, + spl_inet_ntoa (addr_in->sin_addr), ntohs (addr_in->sin_port), + sbr_get_conn (sk), ss_get_private_data (sbr_get_conn (sk))); + spl_ip_addr_t local_addr; + inet_addr_to_ipaddr (&local_addr, &addr_in->sin_addr); + u16 local_port = addr_in->sin_port; + return sbr_handle_bind (sk, &local_addr, ntohs (local_port)); +} + +NSTACK_STATIC int +sbr_tcp_listen (sbr_socket_t * sk, int backlog) +{ + ss_set_is_listen_conn (sbr_get_conn (sk), 1); + return sbr_handle_listen (sk, backlog); +} + +static inline int +sbr_tcp_recv_is_timeout (sbr_socket_t * sk, struct timespec *starttm) +{ + struct timespec currtm; + i64 timediff_ms, timediff_sec; + i64 timeout_thr_ms, timeout_thr_sec; + + timeout_thr_ms = sbr_get_fd_share (sk)->recv_timeout; + if (0 == timeout_thr_ms) + { + return ERR_OK; + } + + timeout_thr_sec = (i64) (timeout_thr_ms / 1000); + + /* Handle system time change side-effects */ + if (unlikely (0 != clock_gettime (CLOCK_MONOTONIC, &currtm))) + { + NSSBR_LOGERR ("Failed to get time, errno = %d", errno); + } + + timediff_sec = currtm.tv_sec - starttm->tv_sec; + if (timediff_sec >= timeout_thr_sec) + { + timediff_ms = currtm.tv_nsec > starttm->tv_nsec ? + (timediff_sec * 1000) + (currtm.tv_nsec - + starttm->tv_nsec) / + USEC_TO_SEC : (timediff_sec * 1000) - + ((starttm->tv_nsec - currtm.tv_nsec) / USEC_TO_SEC); + + /*NOTE: if user configured the timeout as say 0.5 ms, then timediff value + will be negetive if still 0.5 ms is not elapsed. this is intended and we should + not typecast to any unsigned type during this below if check */ + if (timediff_ms > timeout_thr_ms) + { + sbr_set_sk_errno (sk, ETIMEDOUT); + return ETIMEDOUT; + } + } + + return ERR_OK; +} + +static inline int +sbr_tcp_wait_new_conn (sbr_socket_t * sk, void **new_buf) +{ + int ret = 0; + int elem_num; + u32 timeout_thr_sec; + struct timespec starttm = { 0, 0 }; + unsigned int retry_count = 0; + mring_handle ring = NULL; + +#define FAST_SLEEP_TIME 10000 +#define SLOW_SLEEP_TIME 500000 +#define FAST_RETRY_COUNT 100 + + ring = ss_get_recv_ring (sbr_get_conn (sk)); //clear codeDEX warning , CID:24284 + timeout_thr_sec = sbr_get_fd_share (sk)->recv_timeout / 1000; + if (0 != timeout_thr_sec) + { + if (unlikely (0 != clock_gettime (CLOCK_MONOTONIC, &starttm))) + { + NSSBR_LOGERR ("Failed to get time, errno = %d", errno); + } + } + + while (1) + { + if (ss_is_shut_rd (sbr_get_conn (sk))) + { + sbr_set_sk_errno (sk, EINVAL); + ret = EINVAL; + break; + } + + elem_num = nsfw_mem_ring_dequeue (ring, new_buf); + if (1 == elem_num) + { + break; + } + else if (0 == elem_num) + { + ret = sbr_tcp_recv_is_timeout (sk, &starttm); + if (0 != ret) + { + break; + } + + /* reduce CPU usage in blocking mode- Begin */ + if (retry_count < FAST_RETRY_COUNT) + { + sys_sleep_ns (0, FAST_SLEEP_TIME); + retry_count++; + } + else + { + sys_sleep_ns (0, sbr_get_fd_share (sk)->block_polling_time); + } + + continue; + } + else + { + sbr_set_sk_errno (sk, EINVAL); + ret = EINVAL; + break; + } + } + + return ret; +} + +NSTACK_STATIC inline int +sbr_tcp_get_sockaddr (sbr_socket_t * sk, struct sockaddr *addr, + socklen_t * addrlen) +{ + int ret; + spl_netconn_t *conn = sbr_get_conn (sk); + + ret = (addr + && addrlen) ? sbr_get_sockaddr_and_len (ss_get_remote_port (conn), + ss_get_remote_ip (conn), + addr, addrlen) : 0; + if (0 != ret) + { + sbr_set_sk_io_errno (sk, EINVAL); + NSSBR_LOGERR ("sbr_tcp_get_sockaddr]fd=%d", sk->fd); + return -1; + } + + return 0; +} + +static int +sbr_tcp_accept_socket (sbr_socket_t * sk, sbr_socket_t * new_sk, + struct sockaddr *addr, socklen_t * addrlen) +{ + int err; + spl_netconn_t *newconn = NULL; + + err = sbr_tcp_wait_new_conn (sk, (void **) &newconn); + if (ERR_OK != err) + { + return err; + } + + err = sbr_init_conn_for_accept (new_sk, newconn); + if (ERR_OK != err) + { + /*When conn is null, return err; then do not need to free conn */ + return err; + } + + err = sbr_tcp_get_sockaddr (new_sk, addr, addrlen); + if (ERR_OK != err) + { + NSSBR_LOGERR ("sbr_get_sockaddr_and_socklen]ret=%d.", err); + sbr_tcp_accept_failed (new_sk); + return -1; + } + + NSSBR_LOGINF + ("return]listen fd=%d,listen conn=%p,listen private_data=%p,accept fd=%d,accept conn=%p,accept private_data=%p", + sk->fd, sbr_get_conn (sk), ss_get_private_data (sbr_get_conn (sk)), + new_sk->fd, sbr_get_conn (new_sk), + ss_get_private_data (sbr_get_conn (new_sk))); + + //ip_addr_info_print(SOCKETS_DEBUG, &sbr_get_conn(new_sk)->share_remote_ip); + + /* test_epollCtl_003_001: Accept a conn. Add epoll_ctl with IN event and + send a msg from peer. The event will be given once epoll_wait is called. + Now, modify to IN|OUT. Calling epoll_event should return immediately since + the socket is writable. Currently, returns 0 events. + This issue is fixed here + */ + + /* Prevent automatic window updates, we do this on our own! */ + ss_set_noautorecved_flag (sbr_get_conn (new_sk), 1); + + ss_set_send_event (sbr_get_conn (new_sk), 1); + + /* don't set conn->last_err: it's only ERR_OK, anyway */ + return ERR_OK; +} + +NSTACK_STATIC int +sbr_tcp_accept (sbr_socket_t * sk, sbr_socket_t * new_sk, + struct sockaddr *addr, socklen_t * addrlen) +{ + int err; + + /* If conn is not in listen state then return failure with error code: EINVAL(22) */ + if (!ss_is_listen_state (sbr_get_conn (sk))) + { + NSSBR_LOGERR ("fd is not listening for connections]fd=%d,err=%d", + sk->fd, EINVAL); + sbr_set_sk_errno (sk, EINVAL); + + return -1; + } + + if (ss_is_nonblock_flag (sbr_get_conn (sk)) + && (0 >= ss_get_recv_event (sbr_get_conn (sk)))) + { + NSSBR_LOGERR ("fd is nonblocking and rcvevent<=0]fd=%d,err=%d", sk->fd, + EWOULDBLOCK); + sbr_set_sk_errno (sk, EWOULDBLOCK); + + return -1; + } + + err = ss_get_last_errno (sbr_get_conn (sk)); + if (SPL_ERR_IS_FATAL (err)) + { + /* don't recv on fatal errors: this might block the application task + waiting on acceptmbox forever! */ + sbr_set_sk_errno (sk, sbr_spl_err_to_errno (err)); + + return -1; + } + + /* wait for a new connection */ + err = sbr_tcp_accept_socket (sk, new_sk, addr, addrlen); + if (ERR_OK != err) + { + NSSBR_LOGERR ("sbr_tcp_accept_socket failed]fd=%d,err=%d", sk->fd, err); + + return -1; + } + + /* Prevent automatic window updates, we do this on our own! */ + ss_sub_recv_event (sbr_get_conn (sk)); + + sbr_set_sk_errno (sk, ERR_OK); + + /* test_epollCtl_003_001: Accept a conn. Add epoll_ctl with IN event and + send a msg from peer. The event will be given once epoll_wait is called. + Now, modify to IN|OUT. Calling epoll_event should return immediately since + the socket is writable. Currently, returns 0 events. + This issue is fixed here + */ + + ss_set_send_event (sbr_get_conn (new_sk), 1); + + return new_sk->fd; +} + +NSTACK_STATIC int +sbr_tcp_accept4 (sbr_socket_t * sk, sbr_socket_t * new_sk, + struct sockaddr *addr, socklen_t * addrlen, int flags) +{ + int fd = sbr_tcp_accept (sk, new_sk, addr, addrlen); + + if (0 > fd) + { + return fd; + } + + if (flags & O_NONBLOCK) + { + int opts = new_sk->fdopt->fcntl (new_sk, F_GETFL, 0); + if (opts < 0) + { + NSSBR_LOGERR ("sbr_tcp_fcntl(sock,GETFL)"); + sbr_tcp_accept_failed (new_sk); + return -1; + } + + opts = opts | O_NONBLOCK; + + if (new_sk->fdopt->fcntl (new_sk, F_SETFL, opts) < 0) + + { + NSSBR_LOGERR ("sbr_tcp_fcntl(sock,F_SETFL,opts)"); + sbr_tcp_accept_failed (new_sk); + return -1; + } + } + + return new_sk->fd; +} + +NSTACK_STATIC int +sbr_tcp_connect (sbr_socket_t * sk, const struct sockaddr *name, + socklen_t namelen) +{ + const struct sockaddr_in *addr_in = (const struct sockaddr_in *) name; + + NSSBR_LOGINF ("fd=%d,addr=%s,port=%d,conn=%p,private_data=%p", sk->fd, + spl_inet_ntoa (addr_in->sin_addr), ntohs (addr_in->sin_port), + sbr_get_conn (sk), ss_get_private_data (sbr_get_conn (sk))); + spl_ip_addr_t remote_addr; + + inet_addr_to_ipaddr (&remote_addr, &addr_in->sin_addr); + u16 remote_port = addr_in->sin_port; + + spl_ip_addr_t local_addr; + if (IPADDR_ANY == ss_get_local_ip (sbr_get_conn (sk))->addr) + { + if (sbr_get_src_ip (remote_addr.addr, &local_addr.addr) != 0) + { + sbr_set_sk_errno (sk, EHOSTUNREACH); + NSSBR_LOGERR ("get src ip failed]fd=%d", sk->fd); + return -1; + } + } + + if (sbr_handle_connect (sk, &remote_addr, ntohs (remote_port), &local_addr) + != 0) + { + NSSBR_LOGERR ("fail]fd=%d", sk->fd); + return -1; + } + + if (ss_is_shut_rd (sbr_get_conn (sk))) + { + NSSBR_LOGERR ("shut_rd]fd=%d", sk->fd); + sbr_set_sk_errno (sk, ECONNRESET); + return -1; + } + + NSSBR_LOGINF ("succeeded]fd=%d", sk->fd); + sbr_set_sk_errno (sk, ERR_OK); + + return 0; +} + +static u8 netconn_shutdown_opt[] = { + SPL_NETCONN_SHUT_RD, + SPL_NETCONN_SHUT_WR, + SPL_NETCONN_SHUT_RDWR +}; + +NSTACK_STATIC int +sbr_tcp_shutdown (sbr_socket_t * sk, int how) +{ + err_t err; + + if (ss_is_listen_state (sbr_get_conn (sk))) + { + return 0; + } + + ss_set_shut_status (sbr_get_conn (sk), how); + + err = sbr_handle_shutdown (sk, netconn_shutdown_opt[how]); + + return (err == ERR_OK ? 0 : -1); +} + +NSTACK_STATIC int +sbr_tcp_getsockname (sbr_socket_t * sk, struct sockaddr *name, + socklen_t * namelen) +{ + + NSSBR_LOGINF ("sockname]fd=%d,tcp_state=%d", sk->fd, + ss_get_tcp_state (sbr_get_conn (sk))); + + return sbr_handle_get_name (sk, name, namelen, SBR_GET_SOCK_NAME); +} + +NSTACK_STATIC int +sbr_tcp_getpeername (sbr_socket_t * sk, struct sockaddr *name, + socklen_t * namelen) +{ + + if (SPL_CLOSED == ss_get_tcp_state (sbr_get_conn (sk))) + { + NSSBR_LOGERR ("connection not exist]fd=%d", sk->fd); + sbr_set_sk_errno (sk, ENOTCONN); + return -1; + } + + NSSBR_LOGINF ("peername]fd=%d,tcp_state=%d", sk->fd, + ss_get_tcp_state (sbr_get_conn (sk))); + + return sbr_handle_get_name (sk, name, namelen, SBR_GET_PEER_NAME); +} + +static int +sbr_getsockopt_ipproto_tcp (int optname, void *optval, socklen_t optlen) +{ + int err = ERR_OK; + + switch (optname) + { + case SPL_TCP_NODELAY: + break; + case SPL_TCP_KEEPIDLE: + case SPL_TCP_KEEPINTVL: + case SPL_TCP_KEEPCNT: + break; + default: + err = ENOPROTOOPT; + break; + } + + return err; +} + +NSTACK_STATIC int inline +sbr_tcp_set_sockopt_err (sbr_socket_t * sk, int err) +{ + if (ENOPROTOOPT == err) + { + return 0; + } + else + { + sbr_set_sk_errno (sk, err); + return -1; + } +} + +NSTACK_STATIC int inline +sbr_tcp_get_sockopt_err (sbr_socket_t * sk, int err) +{ + sbr_set_sk_errno (sk, err); + return -1; +} + +NSTACK_STATIC int +sbr_tcp_getsockopt (sbr_socket_t * sk, int level, int optname, void *optval, + socklen_t * optlen) +{ + int err = 0; + + switch (level) + { + case SOL_SOCKET: + err = sbr_getsockopt_sol_socket (sk, optname, optval, *optlen); + break; + + case IPPROTO_IP: + err = sbr_getsockopt_ipproto_ip (optname, optval, *optlen); + break; + + case IPPROTO_TCP: + err = sbr_getsockopt_ipproto_tcp (optname, optval, *optlen); + break; + + case NSTACK_SOCKOPT: + if ((optname == NSTACK_SEM_SLEEP) || (*optlen < sizeof (u32_t))) + { + *(u32_t *) optval = + sbr_get_fd_share (sk)->block_polling_time / 1000; + NSSOC_LOGINF + ("tcp get recv sleep time success, usleep time = %d,fd = %d", + sbr_get_fd_share (sk)->block_polling_time, sk->fd); + return ERR_OK; + } + else + { + NSSOC_LOGINF ("get recv sleep time failed, fd = %d", sk->fd); + sbr_set_sk_io_errno (sk, EINVAL); + return -1; + } + default: + err = ENOPROTOOPT; + break; + } + + if (0 != err) + { + NSSBR_LOGERR ("fail]fd=%d,level=%d,optname=%d,err=%d", sk->fd, level, + optname, err); + /* for option not support ,getsockopt() should return fail */ + return sbr_tcp_get_sockopt_err (sk, err); + } + + return sbr_handle_getsockopt (sk, level, optname, optval, optlen); +} + +int +sbr_setsockopt_ipproto_tcp (int optname, socklen_t optlen) +{ + int err = 0; + + if (optlen < sizeof (int)) + { + return EINVAL; + } + + switch (optname) + { + case SPL_TCP_KEEPIDLE: + case SPL_TCP_KEEPINTVL: + case SPL_TCP_KEEPCNT: + break; + default: + err = ENOPROTOOPT; + break; + } + + return err; +} + +NSTACK_STATIC int +sbr_tcp_setsockopt (sbr_socket_t * sk, int level, int optname, + const void *optval, socklen_t optlen) +{ + int err = 0; + + switch (level) + { + case SOL_SOCKET: + err = + sbr_setsockopt_sol_socket (sk, optname, optval, optlen, + SPL_NETCONN_TCP); + break; + case IPPROTO_IP: + err = + sbr_setsockopt_ipproto_ip (optname, optval, optlen, SPL_NETCONN_TCP); + break; + case IPPROTO_TCP: + err = sbr_setsockopt_ipproto_tcp (optname, optlen); + break; + case NSTACK_SOCKOPT: + { + u32_t sleep_time = *(u32_t *) optval; + /*sleep time should less than 1s */ + if ((optname == NSTACK_SEM_SLEEP) && (optlen >= sizeof (u32_t)) + && (sleep_time < 1000000)) + { + sbr_get_fd_share (sk)->block_polling_time = sleep_time * 1000; + NSSOC_LOGINF + ("tcp set recv sleep time success, usleep time = %d,fd = %d", + sbr_get_fd_share (sk)->block_polling_time, sk->fd); + return ERR_OK; + } + else + { + NSSOC_LOGINF ("set recv sleep time failed, fd = %d", sk->fd); + sbr_set_sk_io_errno (sk, EINVAL); + return -1; + } + } + + default: + err = ENOPROTOOPT; + break; + } + + if (0 != err) + { + NSSBR_LOGERR ("fail]fd=%d,level=%d,optname=%d,err=%d", sk->fd, level, + optname, err); + + return sbr_tcp_set_sockopt_err (sk, err); + } + + return sbr_handle_setsockopt (sk, level, optname, optval, optlen); +} + +static inline u16 +sbr_tcp_mbuf_count (struct spl_pbuf *p) +{ + u16 count = 0; + struct spl_pbuf *buf = p; + struct common_mem_mbuf *mbuf; + + while (buf) + { + mbuf = + (struct common_mem_mbuf *) ((char *) buf - + sizeof (struct common_mem_mbuf)); + while (mbuf) + { + count++; +#ifdef HAL_LIB +#else + mbuf = mbuf->next; +#endif + } + + buf = (struct spl_pbuf *) ADDR_SHTOL (buf->next_a); + } + + return count; +} + +static inline void +sbr_tcp_free_recvbuf (sbr_socket_t * sk, struct spl_pbuf *p) +{ + int len; + + if (ss_is_noautorecved_flag (sbr_get_conn (sk))) + { + len = sbr_tcp_mbuf_count (p); + sbr_handle_tcp_recv (sk, len, p); + } +} + +static inline void +sbr_tcp_recv_no_peak (sbr_socket_t * sk, struct spl_pbuf *buf, u32 buflen, + u32 copylen) +{ + if ((buflen - copylen) > 0) + { + sbr_get_fd_share (sk)->lastdata = (void *) ADDR_LTOSH (buf); + sbr_get_fd_share (sk)->lastoffset += copylen; + } + else + { + sbr_get_fd_share (sk)->lastdata = 0; + sbr_get_fd_share (sk)->lastoffset = 0; + sbr_tcp_free_recvbuf (sk, buf); + } +} + +static inline int +sbr_tcp_recv_from_ring (sbr_socket_t * sk, struct spl_pbuf **buf, i32 timeout) +{ + int err; + spl_netconn_t *conn = sbr_get_conn (sk); + + err = ss_get_last_errno (conn); + if (SPL_ERR_IS_FATAL (err)) + { + /* don't recv on fatal errors: this might block the application task + waiting on recvmbox forever! */ + + /* @todo: this does not allow us to fetch data that has been put into recvmbox + before the fatal error occurred - is that a problem? */ + NSSBR_LOGDBG ("last err when recv:]=%d", err); + if (ERR_CLSD != err) + { + sbr_set_sk_io_errno (sk, sbr_spl_err_to_errno (err)); + return -1; + } + } + + *buf = NULL; + if (0 != sbr_dequeue_buf (sk, (void **) buf, timeout)) + { + return -1; + } + + ss_sub_recv_avail (sbr_get_conn (sk), (*buf)->tot_len); + + ss_sub_recv_event (sbr_get_conn (sk)); + + return 0; +} + +static inline int +sbr_tcp_recv_state_check (sbr_socket_t * sk) +{ + + spl_tcp_state_t state = ss_get_tcp_state (sbr_get_conn (sk)); + + NSSBR_LOGDBG ("tcp state when recv:]=%d", state); + + //close_wait state also can recive data + //no connect cannot recive data + if (SPL_ESTABLISHED > state) + { + if (SPL_SHUT_WR != ss_get_shut_status (sbr_get_conn (sk))) + { + /* after all data retrnasmission, connection is active */ + /* patch solution as last_err is not maintained properly */ + if ((SPL_CLOSED == state) + && (ERR_TIMEOUT == ss_get_last_errno (sbr_get_conn (sk)))) + { + sbr_set_sk_io_errno (sk, ETIMEDOUT); + } + else if ((SPL_CLOSED == state) + && (ERR_RST == ss_get_last_errno (sbr_get_conn (sk)))) + { + sbr_set_sk_io_errno (sk, ECONNRESET); + } + else + { + sbr_set_sk_io_errno (sk, ENOTCONN); + } + + return -1; + } + } + + return 0; +} + +NSTACK_STATIC int +sbr_tcp_recvfrom (sbr_socket_t * sk, void *mem, size_t len, int flags, + struct sockaddr *from, socklen_t * fromlen) +{ + struct spl_pbuf *p; + u32 buflen; + u32 copylen; + u32 off = 0; + u8 done = 0; + int para_len = len; + int retval = 0; + + sbr_com_lock_recv (sk); + NSSOC_LOGINF ("recv start, fd = %d last data %p flags to be set %d", sk->fd, + ADDR_SHTOL (sbr_get_fd_share (sk)->lastdata), MSG_DONTWAIT); + + if (0 != sbr_tcp_recv_state_check (sk)) + { + retval = -1; + goto sbr_tcp_recvfrom_exit; + } + + do + { + if (sbr_get_fd_share (sk)->lastdata) + { + p = ADDR_SHTOL (sbr_get_fd_share (sk)->lastdata); + } + else + { + if ((flags & MSG_DONTWAIT) + || ss_is_nonblock_flag (sbr_get_conn (sk))) + { + NSSOC_LOGINF ("call ss_get_recv_event"); + if (0 >= ss_get_recv_event (sbr_get_conn (sk))) + { + NSSOC_LOGINF ("no recv event]fd=%d", sk->fd); + sbr_set_sk_io_errno (sk, EWOULDBLOCK); + retval = -1; + goto sbr_tcp_recvfrom_exit; + } + } + + if (0 != + sbr_tcp_recv_from_ring (sk, &p, + sbr_get_fd_share (sk)->recv_timeout)) + { + /* already received data, return that */ + if (off > 0) + { + sbr_set_sk_io_errno (sk, ERR_OK); + retval = off; + goto sbr_tcp_recvfrom_exit; + } + + /* we tell the user the connection is closed by returning zero */ + if (sbr_get_sk_errno (sk) == ENOTCONN) + { + retval = 0; + goto sbr_tcp_recvfrom_exit; + } + + retval = -1; + goto sbr_tcp_recvfrom_exit; + } + + sbr_get_fd_share (sk)->lastdata = (void *) ADDR_LTOSH (p); + } + + buflen = p->tot_len - sbr_get_fd_share (sk)->lastoffset; + copylen = len > buflen ? buflen : len; + + if ((copylen > 0) + && 0 == spl_pbuf_copy_partial (p, (u8 *) mem + off, copylen, + sbr_get_fd_share (sk)->lastoffset)) + { + NSSBR_LOGERR ("copy failed]fd=%d", sk->fd); + sbr_set_sk_io_errno (sk, EFAULT); + retval = -1; + goto sbr_tcp_recvfrom_exit; + } + + off += copylen; + + len -= copylen; + + if ((len == 0) || (ss_get_recv_event (sbr_get_conn (sk)) <= 0) + || ((flags & MSG_PEEK) != 0)) + { + if ((off >= sbr_get_fd_share (sk)->rcvlowat) + || (para_len <= sbr_get_fd_share (sk)->rcvlowat)) + { + done = 1; + } + } + + if (done) + { + if (sbr_tcp_get_sockaddr (sk, from, fromlen) != 0) + { + retval = -1; + goto sbr_tcp_recvfrom_exit; + } + } + + /* If this is a TCP socket, check if there is data left in the buffer, + If so, it should be saved in the sock structure for next time around. */ + if (!(flags & MSG_PEEK)) + { + sbr_tcp_recv_no_peak (sk, p, buflen, copylen); + } + } + while (!done); + + retval = off; + + NSSOC_LOGINF ("recv done, fd = %d last data %p", sk->fd); +sbr_tcp_recvfrom_exit: + + NSSOC_LOGINF ("recv exit, fd = %d last data %p", sk->fd); + sbr_com_unlock_recv (sk); + return retval; +} + +/***************************************************************************** +* Prototype : sbr_tcp_recvdata +* Description : recvdata +* Input : sbr_socket_t* sk +* const struct iovec* iov +* int iovcnt +* int flags +* Output : None +* Return Value : static inline int +* Calls : +* Called By : +* +*****************************************************************************/ +static inline int +sbr_tcp_recvdata (sbr_socket_t * sk, const struct iovec *iov, int iovcnt) +{ + int max = SBR_MAX_INTEGER; + int len = 0; + int ret = 0; + int i = 0; + + do + { + len += ret; + + if (!iov[i].iov_base || (0 == iov[i].iov_len)) + { + ret = 0; + continue; + } + + ret = sbr_tcp_recvfrom (sk, (char *) iov[i].iov_base, iov[i].iov_len, 0, + NULL, NULL); + } + while ((ret == (int) iov[i].iov_len) && (iovcnt > (++i)) + && (max - len - ret > (int) iov[i].iov_len)); + + if (len == 0) + { + return ret; + } + else + { + return (ret == -1 ? len : len + ret); + } +} + +/***************************************************************************** +* Prototype : sbr_tcp_readv +* Description : readv +* Input : sbr_socket_t* sk +* const struct iovec* iov +* int iovcnt +* Output : None +* Return Value : static int +* Calls : +* Called By : +* +*****************************************************************************/ +static int +sbr_tcp_readv (sbr_socket_t * sk, const struct iovec *iov, int iovcnt) +{ + return sbr_tcp_recvdata (sk, iov, iovcnt); +} + +/***************************************************************************** +* Prototype : sbr_tcp_recvmsg +* Description : recvmsg,unsupport flags +* Input : sbr_socket_t* sk +* struct msghdr* msg +* int flags +* Output : None +* Return Value : static int +* Calls : +* Called By : +* +*****************************************************************************/ +static int +sbr_tcp_recvmsg (sbr_socket_t * sk, struct msghdr *msg, int flags) +{ + if (sbr_tcp_get_sockaddr + (sk, (struct sockaddr *) msg->msg_name, &msg->msg_namelen) != 0) + { + return -1; + } + + return sbr_tcp_recvdata (sk, msg->msg_iov, msg->msg_iovlen); +} + +static int +sbr_tcp_send_is_timeout (sbr_socket_t * sk, struct timespec *starttm) +{ + struct timespec currtm; + i64 timediff_ms, timediff_sec; + i64 timeout_thr_ms, timeout_thr_sec; + + timeout_thr_ms = sbr_get_fd_share (sk)->send_timeout; + if (0 == timeout_thr_ms) + { + return 0; + } + + /* it is possible that starttm don't be inited, + if send_timeout is change when this write function is running */ + timeout_thr_sec = (timeout_thr_ms + 240) >> 10; + + /* Handle system time change side-effects */ + if (unlikely (0 != clock_gettime (CLOCK_MONOTONIC, &currtm))) + { + NSSBR_LOGERR ("Failed to get time, errno = %d", errno); + } + + timediff_sec = currtm.tv_sec - starttm->tv_sec; + if (timediff_sec >= timeout_thr_sec) + { + timediff_ms = currtm.tv_nsec > starttm->tv_nsec ? + (timediff_sec * 1000) + (currtm.tv_nsec - + starttm->tv_nsec) / + USEC_TO_SEC : (timediff_sec * 1000) - + ((starttm->tv_nsec - currtm.tv_nsec) / USEC_TO_SEC); + + /*NOTE: if user configured the timeout as say 0.5 ms, then timediff value + will be negetive if still 0.5 ms is not elapsed. this is intended and we should + not typecast to any unsigned type during this below if check */ + if (timediff_ms > timeout_thr_ms) + { + return 1; + } + } + + return 0; +} + +static inline int +sbr_tcp_write_is_wait (sbr_socket_t * sk, struct timespec *starttm, + int noneblockFlg) +{ + if (noneblockFlg || sbr_tcp_send_is_timeout (sk, starttm)) + { + return 0; + } + else + { + return 1; + } +} + +static struct spl_pbuf * +sbr_tcp_write_alloc_buf (sbr_socket_t * sk, size_t seglen, u8 api_flag, + struct timespec *starttm, u8 * errno_flag) +{ + spl_netconn_t *conn = sbr_get_conn (sk); + + struct spl_pbuf *curr_buf = NULL; + size_t head_len = SPL_TCP_HLEN + SPL_PBUF_IP_HLEN + SPL_PBUF_LINK_HLEN; + int noneblockFlg = (api_flag & SPL_NETCONN_DONTBLOCK) + || ss_is_nonblock_flag (sbr_get_conn (sk)); + + do + { + /* When packages are lost more than TCP_MAXRTX times, + * conn will be closed and pcb will be removed. */ + if (ss_get_tcp_state (conn) == SPL_CLOSED) + { + NSSBR_LOGERR ("pcb SPL_CLOSED]conn=%p", conn); + sbr_set_sk_io_errno (sk, ECONNABORTED); + /* Must set errno_flag when set errno, to avoid errnno overwritten by sbr_tcp_write */ + *errno_flag = 1; + return NULL; + } + + curr_buf = sbr_malloc_tx_pbuf (seglen + head_len, head_len); + if (NULL == curr_buf) + { + if (!sbr_tcp_write_is_wait (sk, starttm, noneblockFlg)) + { + return NULL; + } + + int err = ss_get_last_errno (sbr_get_conn (sk)); + if (SPL_ERR_IS_FATAL (err)) + { + NSSBR_LOGERR ("connection fatal error!err=%d", err); + sbr_set_sk_io_errno (sk, sbr_spl_err_to_errno (err)); + *errno_flag = 1; + return NULL; + } + + sched_yield (); + } + } + while (curr_buf == NULL); + + return curr_buf; +} + +static inline void +sbr_tcp_write_rel_buf (sbr_socket_t * sk, struct spl_pbuf *buf, + u32 thread_index) +{ + if (buf != NULL) + { + sbr_handle_free_send_buf (sk, buf); + } +} + +static inline int +sbr_tcp_write_fill_buf (const void *data, size_t * pos, + struct spl_pbuf *seg_buf, size_t seglen, + size_t optlen) +{ + size_t start = *pos; + size_t copy = seglen; + struct spl_pbuf *first = seg_buf; + + while ((0 < copy) && (NULL != first)) + { + char *dst_ptr = PTR_SHTOL (char *, first->payload_a) + optlen; + + if (NULL == + common_memcpy (dst_ptr, (u8_t *) data + start, first->len - optlen)) + { + NSSBR_LOGERR ("common_memcpy error]dst=%p,src=%p,len=%u", + dst_ptr, (u8_t *) data + start, first->len); + return -1; + } + + start += (first->len - optlen); + copy -= (first->len - optlen); + first = ADDR_SHTOL (first->next_a); + } + + (*pos) = start; + + return 0; +} + +static inline int +sbr_tcp_writev_fill_buf (const struct iovec *iov, size_t * iov_pos, + int *iov_var, size_t * pos, struct spl_pbuf *seg_buf, + size_t seglen, size_t optlen) +{ + size_t valid_copy_len; + size_t iov_data_left; + + size_t copy = seglen; + size_t start = *pos; + size_t current_iov_pos = *iov_pos; + int current_iov_var = *iov_var; + + u32 pbuf_offset = optlen; + u32 pbuf_data_len; + struct spl_pbuf *first = seg_buf; + + while ((0 < copy) && (NULL != first)) + { + iov_data_left = iov[current_iov_var].iov_len - current_iov_pos; + if (seglen == copy) + { + pbuf_offset = optlen; + } + + pbuf_data_len = first->len - pbuf_offset; + valid_copy_len = + (iov_data_left > pbuf_data_len ? pbuf_data_len : iov_data_left); + if (NULL == + common_memcpy ((char *) ADDR_SHTOL (first->payload_a) + pbuf_offset, + (u8_t *) iov[current_iov_var].iov_base + + current_iov_pos, valid_copy_len)) + { + NSSBR_LOGERR + ("common_memcpy error]current_iov_var=%d, dst=%p,src=%p,len=%zu", + current_iov_var, + (char *) ADDR_SHTOL (first->payload_a) + pbuf_offset, + (u8_t *) iov[current_iov_var].iov_base + current_iov_pos, + valid_copy_len); + return -1; + } + + start += valid_copy_len; + copy -= valid_copy_len; + + if (iov_data_left == pbuf_data_len) + { + first = PTR_SHTOL (struct spl_pbuf *, first->next_a); + pbuf_offset = optlen; //+= valid_copy_len; + current_iov_var++; + current_iov_pos = 0; + } + else if (iov_data_left > pbuf_data_len) + { + first = PTR_SHTOL (struct spl_pbuf *, first->next_a); + pbuf_offset = optlen; //+= valid_copy_len; + current_iov_pos += valid_copy_len; + } + else + { + pbuf_offset += valid_copy_len; + + current_iov_var++; + current_iov_pos = 0; + } + } + + *iov_pos = current_iov_pos; + *iov_var = current_iov_var; + *pos = start; + + return 0; +} + +static inline void +sbr_tcp_write_add_buf_to_list (struct spl_pbuf **p_head, + struct spl_pbuf **p_tail, + struct spl_pbuf *seg_buf, size_t seglen, + size_t optlen) +{ + seg_buf->len = seglen + optlen; + seg_buf->tot_len = seglen + optlen; + seg_buf->next_a = 0; + + /*put seg_buf after p_head */ + if (NULL == (*p_head)) + { + (*p_head) = seg_buf; + (*p_tail) = seg_buf; + } + else + { + (*p_tail)->next_a = ADDR_LTOSH (seg_buf); + (*p_tail) = seg_buf; + } +} + +NSTACK_STATIC int +sbr_tcp_write (sbr_socket_t * sk, const void *data, size_t size, u8 api_flag, + size_t * written) +{ + err_t err = -1; + size_t pos = 0, left, seglen; + u32 pbuf_seg_cnt = 0; + u32 thread_index = 0; + struct spl_pbuf *seg_buf = NULL; + struct spl_pbuf *p_head = NULL; + struct spl_pbuf *p_tail = p_head; + struct spl_netconn *conn = sbr_get_conn (sk); + u32 mss = ss_get_mss (sbr_get_conn (sk)); + + if (0 == size) + { + NSSBR_LOGERR ("fd=%d,size=%u", sk->fd, (u32) size); + return 0; + } + + struct timespec ts; + if (unlikely (0 != clock_gettime (CLOCK_MONOTONIC, &ts))) + { + NSSBR_LOGERR ("Failed to get time, errno = %d", errno); + } + + while (pos < size) + { + left = size - pos; + seglen = left > mss ? mss : left; + u8 errno_set = 0; + seg_buf = + sbr_tcp_write_alloc_buf (sk, seglen, api_flag, &ts, &errno_set); + if (NULL == seg_buf) + { + NSSBR_LOGINF ("sbr_tcp_write_alloc_buf failed......"); + if (NULL != p_head) + { + err = sbr_handle_tcp_send (sk, size, p_head, api_flag); + if (ERR_OK != err) + { + NSSBR_LOGERR ("sbr_handle_tcp_send error]err(%d)", err); + goto err_ref_buf; + } + } + + if (0 == pos) + { + /* If errno is already set in sbr_tcp_write_alloc_buf, do not overwrite here */ + if (!errno_set) + { + sbr_set_sk_io_errno (sk, EWOULDBLOCK); + } + return -1; + } + + NSSBR_LOGDBG ("sent size %zu", pos); + *written = pos; + + return ERR_OK; + } + + if (0 != sbr_tcp_write_fill_buf (data, &pos, seg_buf, seglen, 0)) + { + sbr_set_sk_io_errno (sk, EFAULT); + NSSBR_LOGERR ("sbr_tcp_write_fill_buf error]"); + goto err_ref_buf; + } + + sbr_tcp_write_add_buf_to_list (&p_head, &p_tail, seg_buf, seglen, 0); + + ++pbuf_seg_cnt; + if (p_head + && ((SPL_TCP_SEND_MAX_SEG_PER_MSG <= pbuf_seg_cnt) + || (pos >= size))) + { + pbuf_seg_cnt = 0; + err = sbr_handle_tcp_send (sk, size, p_head, api_flag); + if (ERR_OK != err) + { + NSSBR_LOGERR ("sbr_handle_tcp_send error]err(%d)", err); + goto err_ref_buf; + } + + p_head = NULL; + } + } + + *written = size; + + (void) conn; + return ERR_OK; + +err_ref_buf: + sbr_tcp_write_rel_buf (sk, p_head, thread_index); + (void) conn; + return -1; +} + +NSTACK_STATIC int +sbr_tcp_writev (sbr_socket_t * sk, const struct iovec *iov, int iovcnt) +{ + err_t err = -1; + int idx = 0; + size_t pos = 0, left, seglen, optlen = 0; + u32 pbuf_seg_cnt = 0; + u32 thread_index = 0; + size_t size = 0; + size_t iov_pos = 0; + int iov_var = 0; + struct spl_pbuf *seg_buf = NULL; + struct spl_pbuf *p_head = NULL; + struct spl_pbuf *p_tail = p_head; + struct spl_netconn *conn = sbr_get_conn (sk); + u32 mss = ss_get_mss (sbr_get_conn (sk)); + + if (mss <= optlen) + { + NSSBR_LOGERR ("mss invalid]mss=%u,optlen=%zu,fd=%d", mss, optlen, + sk->fd); + sbr_set_sk_io_errno (sk, EINVAL); + return -1; + } + + /* mss dose't include the tcp options length */ + mss -= optlen; + + while (idx < iovcnt) + { + if (SBR_MAX_INTEGER - iov[idx].iov_len <= size) + { + size = SBR_MAX_INTEGER; + break; + } + + size += iov[idx].iov_len; + idx++; + } + + struct timespec starttm; + if (unlikely (0 != clock_gettime (CLOCK_MONOTONIC, &starttm))) + { + NSSBR_LOGERR ("Failed to get time, errno = %d", errno); + } + + while (pos < size) + { + left = size - pos; + + seglen = left > mss ? mss : left; + u8 errno_set = 0; + seg_buf = + sbr_tcp_write_alloc_buf (sk, seglen + optlen, SPL_NETCONN_COPY, + &starttm, &errno_set); + if (NULL == seg_buf) + { + if (NULL != p_head) + { + err = sbr_handle_tcp_send (sk, size, p_head, SPL_NETCONN_COPY); + /*If errno is already set in sbr_tcp_write_alloc_buf, do not overwrite here */ + if (err != ERR_OK) + { + NSSBR_LOGERR ("sbr_handle_tcp_send error]err(%d)", err); + goto err_ref_buf; + } + } + + /* [Start] + 1)Set SO_SNDTIMEO to 10 + 2)Send a msg of larger buff size.and let the timeout happen for send (dont receive at peer side.) + 3)iRet will be 0 and errno received will be 11 (EAGAIN). + + Above issue is fixed. + */ + if (0 == pos) + { + if (!errno_set) + { + sbr_set_sk_io_errno (sk, EWOULDBLOCK); + } + return -1; + } + /* [End] */ + + NSSBR_LOGDBG ("sent size %zu", pos); + + return pos; + } + + if (0 != + sbr_tcp_writev_fill_buf (iov, &iov_pos, &iov_var, &pos, seg_buf, + seglen, optlen)) + { + sbr_set_sk_io_errno (sk, EFAULT); + NSSBR_LOGERR ("sbr_tcp_writev_fill_buf error]"); + goto err_ref_buf; + } + + sbr_tcp_write_add_buf_to_list (&p_head, &p_tail, seg_buf, seglen, + optlen); + + /* @todo: for non-blocking write, check if 'size' would ever fit into + snd_queue or snd_buf */ + ++pbuf_seg_cnt; + if (p_head + && ((SPL_TCP_SEND_MAX_SEG_PER_MSG <= pbuf_seg_cnt) + || (pos >= size))) + { + pbuf_seg_cnt = 0; + err = sbr_handle_tcp_send (sk, size, p_head, SPL_NETCONN_COPY); + if (ERR_OK != err) + { + NSSBR_LOGERR ("sbr_handle_tcp_send error]err(%d)", err); + goto err_ref_buf; + } + + p_head = NULL; + } + } + (void) conn; + return size; + +err_ref_buf: + sbr_tcp_write_rel_buf (sk, p_head, thread_index); + (void) conn; + return -1; +} + +NSTACK_STATIC int +sbr_tcp_sendto (sbr_socket_t * sk, const void *data, size_t size, int flags, + const struct sockaddr *to, socklen_t tolen) +{ + return sk->fdopt->send (sk, data, size, flags); +} + +static inline int +sbr_tcp_send_state_check (sbr_socket_t * sk) +{ + if ((SPL_SHUT_WR == ss_get_shut_status (sbr_get_conn (sk))) + || (SPL_SHUT_RDWR == ss_get_shut_status (sbr_get_conn (sk)))) + { + sbr_set_sk_io_errno (sk, EPIPE); + return -1; + } + + spl_tcp_state_t state = ss_get_tcp_state (sbr_get_conn (sk)); + if ((SPL_ESTABLISHED != state) && (SPL_CLOSE_WAIT != state)) + { + /* after all data retrnasmission, connection is active */ + /* patch solution as last_err is not maintained properly */ + if ((SPL_CLOSED == state) + && (ERR_TIMEOUT == ss_get_last_errno (sbr_get_conn (sk)))) + { + sbr_set_sk_io_errno (sk, ETIMEDOUT); + } + else if ((SPL_CLOSED == state) + && (ERR_RST == ss_get_last_errno (sbr_get_conn (sk)))) + { + sbr_set_sk_io_errno (sk, ECONNRESET); + } + else + { + sbr_set_sk_io_errno (sk, EPIPE); + } + + return -1; + } + + return 0; +} + +NSTACK_STATIC int +sbr_tcp_send (sbr_socket_t * sk, const void *data, size_t size, int flags) +{ + int err; + size_t written = 0; + u8 write_flags; + + if (0 != sbr_tcp_send_state_check (sk)) + { + NSSBR_LOGDBG ("tcp state not correct]fd=%d, err=%d", sk->fd, + sbr_get_sk_errno (sk)); + return -1; + } + + write_flags = SPL_NETCONN_COPY | + ((flags & MSG_MORE) ? SPL_NETCONN_MORE : 0) | + ((flags & MSG_DONTWAIT) ? SPL_NETCONN_DONTBLOCK : 0); + + NSSBR_LOGINF ("Sbr tcp write start"); + err = sbr_tcp_write (sk, data, size, write_flags, &written); + NSSBR_LOGINF ("Sbr tcp write end written %d", written); + + return (err == ERR_OK ? written : -1); +} + +NSTACK_STATIC int +sbr_tcp_sendmsg (sbr_socket_t * sk, const struct msghdr *pmsg, int flags) +{ + if (0 != sbr_tcp_send_state_check (sk)) + { + NSSBR_LOGDBG ("tcp state not correct]fd=%d, err=%d", sk->fd, + sbr_get_sk_errno (sk)); + return -1; + } + + return sbr_tcp_writev (sk, pmsg->msg_iov, pmsg->msg_iovlen); +} + +NSTACK_STATIC int +sbr_tcp_fcntl (sbr_socket_t * sk, int cmd, long arg) +{ + int ret = 0; + + switch (cmd) + { + case F_GETFL: + ret = ss_get_nonblock_flag (sbr_get_conn (sk)); + NSSBR_LOGDBG ("F_GETFL]fd=%d,ret=%d", sk->fd, ret); + break; + + case F_SETFL: + if (arg & O_NONBLOCK) + { + NSSBR_LOGDBG ("F_SETFL set O_NONBLOCK val]fd=%d,arg=%ld", sk->fd, + arg); + ss_set_nonblock_flag (sbr_get_conn (sk), (arg & O_NONBLOCK)); + } + else + { + NSSBR_LOGDBG ("F_SETFL clean O_NONBLOCK val]fd=%d,arg=%ld", sk->fd, + arg); + ss_set_nonblock_flag (sbr_get_conn (sk), 0); + } + + break; + + default: + NSSBR_LOGERR ("cmd is not support]fd=%d,cmd=%d", sk->fd, cmd); + ret = -1; + sbr_set_sk_errno (sk, EINVAL); + break; + } + + return ret; +} + +NSTACK_STATIC int +sbr_tcp_ioctl (sbr_socket_t * sk, unsigned long cmd, void *arg) +{ + int ret = 0; + int recv_avail; + + switch (cmd) + { + case FIONREAD: + { + if (ss_is_listen_state (sbr_get_conn (sk))) + { + ret = -1; + sbr_set_sk_errno (sk, EINVAL); + break; + } + + recv_avail = ss_get_recv_avail (sbr_get_conn (sk)); + *((u32 *) arg) = recv_avail >= 0 ? recv_avail : 0; + if (sbr_get_fd_share (sk)->lastdata) + { + struct spl_pbuf *buf = + ADDR_SHTOL (sbr_get_fd_share (sk)->lastdata); + *((u32 *) arg) += + (buf->tot_len - sbr_get_fd_share (sk)->lastoffset); + } + } + + break; + + case FIONBIO: + { + u8 val = 0; + + if (arg && *(u32 *) arg) + { + val = 1; + } + + ss_set_nonblock_flag (sbr_get_conn (sk), val); + NSSBR_LOGDBG ("FIONBIO]fd=%d,val=%u", sk->fd, val); + } + + break; + + default: + { + NSSBR_LOGERR ("cmd is not support]fd=%d,cmd=%lu", sk->fd, cmd); + ret = -1; + sbr_set_sk_errno (sk, ENOTTY); + } + break; + } + + return ret; +} + +NSTACK_STATIC int +sbr_tcp_close (sbr_socket_t * sk) +{ + if (sbr_get_fd_share (sk)->lastdata) + { + struct spl_netbuf *buf = ADDR_SHTOL (sbr_get_fd_share (sk)->lastdata); + struct spl_pbuf *p = (struct spl_pbuf *) ADDR_SHTOL (buf->p); + sbr_tcp_free_recvbuf (sk, p); + } + + return sbr_handle_close (sk, 0); +} + +sbr_fdopt tcp_fdopt = { + .socket = sbr_tcp_socket, + .bind = sbr_tcp_bind, + .listen = sbr_tcp_listen, + .accept = sbr_tcp_accept, + .accept4 = sbr_tcp_accept4, + .connect = sbr_tcp_connect, + .shutdown = sbr_tcp_shutdown, + .getsockname = sbr_tcp_getsockname, + .getpeername = sbr_tcp_getpeername, + .getsockopt = sbr_tcp_getsockopt, + .setsockopt = sbr_tcp_setsockopt, + .recvfrom = sbr_tcp_recvfrom, + .readv = sbr_tcp_readv, + .recvmsg = sbr_tcp_recvmsg, + .send = sbr_tcp_send, + .sendto = sbr_tcp_sendto, + .sendmsg = sbr_tcp_sendmsg, + .writev = sbr_tcp_writev, + .fcntl = sbr_tcp_fcntl, + .ioctl = sbr_tcp_ioctl, + .close = sbr_tcp_close, + .peak = sbr_com_peak, + .lock_common = sbr_com_lock_common, + .unlock_common = sbr_com_unlock_common, + .ep_getevt = stackx_eventpoll_getEvt, + .ep_ctl = stackx_eventpoll_triggle, + .set_close_stat = NULL, +}; diff --git a/stacks/lwip_stack/lwip_src/socket/stackx_udp.c b/stacks/lwip_stack/lwip_src/socket/stackx_udp.c new file mode 100644 index 0000000..cf08731 --- /dev/null +++ b/stacks/lwip_stack/lwip_src/socket/stackx_udp.c @@ -0,0 +1,1169 @@ +/* +* +* Copyright (c) 2018 Huawei Technologies Co.,Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at: +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "stackx_prot_com.h" +#include "stackx_msg_handler.h" +#include "stackx_pbuf.h" +#include "stackx_epoll_api.h" +#include "stackx_err.h" +#include "nstack_securec.h" +#include "common_pal_bitwide_adjust.h" +#include "stackx_cfg.h" +#include <netinet/in.h> +#ifdef HAL_LIB +#else +#include "rte_memcpy.h" +#endif + +#define SPL_PBUF_UDP_LEN (SPL_FRAME_MTU + SPL_PBUF_LINK_HLEN) +#define L2_L3_ROOM_LEN (SPL_PBUF_LINK_HLEN + SPL_PBUF_IP_HLEN) +#define L4_ROOM_LEN SPL_PBUF_UDP_HLEN + +/***************************************************************************** +* Prototype : sbr_udp_socket +* Description : create socket +* Input : sbr_socket_t * sk +* int domain +* int type +* int protocol +* Output : None +* Return Value : static int +* Calls : +* Called By : +* +*****************************************************************************/ +static int +sbr_udp_socket (sbr_socket_t * sk, int domain, int type, int protocol) +{ + if (sbr_malloc_conn_for_sk (sk, SPL_NETCONN_UDP) != 0) + { + return -1; + } + + int ret = sbr_handle_socket (sk, SPL_NETCONN_UDP, 0); + if (ret != 0) + { + sbr_free_conn_from_sk (sk); + return ret; + } + + ss_set_nonblock_flag (sbr_get_conn (sk), (type & O_NONBLOCK)); + ss_set_send_event (sbr_get_conn (sk), 1); + return ret; +} + +/***************************************************************************** +* Prototype : sbr_udp_bind +* Description : udp bind +* Input : sbr_socket_t * sk +* const struct sockaddr * name +* socklen_t namelen +* Output : None +* Return Value : int +* Calls : +* Called By : +* +*****************************************************************************/ +int +sbr_udp_bind (sbr_socket_t * sk, const struct sockaddr *name, + socklen_t namelen) +{ + const struct sockaddr_in *addr_in = (const struct sockaddr_in *) name; + + NSSBR_LOGINF ("fd=%d,addr=%s,port=%d,conn=%p,private_data=%p", sk->fd, + spl_inet_ntoa (addr_in->sin_addr), ntohs (addr_in->sin_port), + sbr_get_conn (sk), ss_get_private_data (sbr_get_conn (sk))); + spl_ip_addr_t local_addr; + inet_addr_to_ipaddr (&local_addr, &addr_in->sin_addr); + u16 local_port = addr_in->sin_port; + return sbr_handle_bind (sk, &local_addr, ntohs (local_port)); +} + +/***************************************************************************** +* Prototype : sbr_udp_listen +* Description : unsupport +* Input : sbr_socket_t * sk +* int backlog +* Output : None +* Return Value : int +* Calls : +* Called By : +* +*****************************************************************************/ +int +sbr_udp_listen (sbr_socket_t * sk, int backlog) +{ + NSSBR_LOGERR ("type is not TCP]fd=%d", sk->fd); + sbr_set_sk_errno (sk, EOPNOTSUPP); + return -1; +} + +/***************************************************************************** +* Prototype : sbr_udp_accept +* Description : unsupport +* Input : sbr_socket_t * sk +* sbr_socket_t * new_sk +* struct sockaddr * addr +* socklen_t * addrlen +* Output : None +* Return Value : int +* Calls : +* Called By : +* +*****************************************************************************/ +int +sbr_udp_accept (sbr_socket_t * sk, sbr_socket_t * new_sk, + struct sockaddr *addr, socklen_t * addrlen) +{ + NSSBR_LOGERR ("type is not TCP]fd=%d", sk->fd); + sbr_set_sk_errno (sk, EOPNOTSUPP); + return -1; +} + +/***************************************************************************** +* Prototype : sbr_udp_accept4 +* Description : unsupport +* Input : sbr_socket_t * sk +* sbr_socket_t * new_sk +* struct sockaddr * addr +* socklen_t * addrlen +* int flags +* Output : None +* Return Value : int +* Calls : +* Called By : +* +*****************************************************************************/ +int +sbr_udp_accept4 (sbr_socket_t * sk, sbr_socket_t * new_sk, + struct sockaddr *addr, socklen_t * addrlen, int flags) +{ + NSSBR_LOGERR ("type is not TCP]fd=%d", sk->fd); + sbr_set_sk_errno (sk, EOPNOTSUPP); + return -1; +} + +/***************************************************************************** +* Prototype : sbr_udp_connect +* Description : udp connect +* Input : sbr_socket_t * sk +* const struct sockaddr * name +* socklen_t namelen +* Output : None +* Return Value : int +* Calls : +* Called By : +* +*****************************************************************************/ +int +sbr_udp_connect (sbr_socket_t * sk, const struct sockaddr *name, + socklen_t namelen) +{ + const struct sockaddr_in *addr_in = (const struct sockaddr_in *) name; + + NSSBR_LOGINF ("fd=%d,addr=%s,port=%d,conn=%p,private_data=%p", sk->fd, + spl_inet_ntoa (addr_in->sin_addr), ntohs (addr_in->sin_port), + sbr_get_conn (sk), ss_get_private_data (sbr_get_conn (sk))); + spl_ip_addr_t remote_addr; + + inet_addr_to_ipaddr (&remote_addr, &addr_in->sin_addr); + u16 remote_port = addr_in->sin_port; + + spl_ip_addr_t local_addr; + if (IPADDR_ANY == ss_get_local_ip (sbr_get_conn (sk))->addr) + { + if (sbr_get_src_ip (remote_addr.addr, &local_addr.addr) != 0) + { + sbr_set_sk_errno (sk, EHOSTUNREACH); + NSSBR_LOGERR ("get src ip failed]fd=%d", sk->fd); + return -1; + } + } + + return sbr_handle_connect (sk, &remote_addr, ntohs (remote_port), + &local_addr); +} + +/***************************************************************************** +* Prototype : sbr_udp_shutdown +* Description : udp shutdown +* Input : sbr_socket_t * sk +* int how +* Output : None +* Return Value : static int +* Calls : +* Called By : +* +*****************************************************************************/ +static int +sbr_udp_shutdown (sbr_socket_t * sk, int how) +{ + ss_set_shut_status (sbr_get_conn (sk), how); + NSSBR_LOGERR ("type is not TCP]fd=%d", sk->fd); + sbr_set_sk_errno (sk, EOPNOTSUPP); + return -1; +} + +/***************************************************************************** +* Prototype : sbr_udp_getsockname +* Description : get sock name +* Input : sbr_socket_t * sk +* struct sockaddr * name +* socklen_t * namelen +* Output : None +* Return Value : int +* Calls : +* Called By : +* +*****************************************************************************/ +int +sbr_udp_getsockname (sbr_socket_t * sk, struct sockaddr *name, + socklen_t * namelen) +{ + return sbr_handle_get_name (sk, name, namelen, SBR_GET_SOCK_NAME); +} + +/***************************************************************************** +* Prototype : sbr_udp_getpeername +* Description : get peer name +* Input : sbr_socket_t * sk +* struct sockaddr * name +* socklen_t * namelen +* Output : None +* Return Value : int +* Calls : +* Called By : +* +*****************************************************************************/ +int +sbr_udp_getpeername (sbr_socket_t * sk, struct sockaddr *name, + socklen_t * namelen) +{ + return sbr_handle_get_name (sk, name, namelen, SBR_GET_PEER_NAME); +} + +/***************************************************************************** +* Prototype : sbr_udp_getsockopt +* Description : get sockopt +* Input : sbr_socket_t * sk +* int level +* int optname +* void * optval +* socklen_t * optlen +* Output : None +* Return Value : int +* Calls : +* Called By : +* +*****************************************************************************/ +int +sbr_udp_getsockopt (sbr_socket_t * sk, int level, int optname, void *optval, + socklen_t * optlen) +{ + int err = 0; + + switch (level) + { + case SOL_SOCKET: + err = sbr_getsockopt_sol_socket (sk, optname, optval, *optlen); + break; + case IPPROTO_IP: + err = sbr_getsockopt_ipproto_ip (optname, optval, *optlen); + break; + + case NSTACK_SOCKOPT: + if ((optname == NSTACK_SEM_SLEEP) || (*optlen < sizeof (u32_t))) + { + *(u32_t *) optval = + sbr_get_fd_share (sk)->block_polling_time / 1000; + NSSOC_LOGINF + ("udp get recv sleep time success]usleep time=%d,fd=%d", + sbr_get_fd_share (sk)->block_polling_time, sk->fd); + return ERR_OK; + } + else + { + NSSOC_LOGINF ("get recv sleep time failed]fd=%d", sk->fd); + sbr_set_sk_io_errno (sk, EINVAL); + return -1; + } + + default: + err = ENOPROTOOPT; + break; + } + + if (err != 0) + { + NSSBR_LOGERR ("fail]fd=%d,level=%d,optname=%d,err=%d", sk->fd, level, + optname, err); + /* for option not support ,getsockopt() should return fail */ + sbr_set_sk_errno (sk, err); + return -1; + } + + return sbr_handle_getsockopt (sk, level, optname, optval, optlen); +} + +/***************************************************************************** +* Prototype : sbr_udp_setsockopt +* Description : set sockopt +* Input : sbr_socket_t * sk +* int level +* int optname +* const void * optval +* socklen_t optlen +* Output : None +* Return Value : static int +* Calls : +* Called By : +* +*****************************************************************************/ +static int +sbr_udp_setsockopt (sbr_socket_t * sk, int level, int optname, + const void *optval, socklen_t optlen) +{ + NSSBR_LOGDBG ("udp setsockopt]fd=%d,level=%d,optname=%d", sk->fd, level, + optname); + int err = 0; + switch (level) + { + case SOL_SOCKET: + err = + sbr_setsockopt_sol_socket (sk, optname, optval, optlen, + SPL_NETCONN_UDP); + break; + case IPPROTO_IP: + err = + sbr_setsockopt_ipproto_ip (optname, optval, optlen, SPL_NETCONN_UDP); + break; + case NSTACK_SOCKOPT: + { + u32_t sleep_time = *(u32_t *) optval; + /*sleep time should less than 1s */ + if ((optname == NSTACK_SEM_SLEEP) && (optlen >= sizeof (u32_t)) + && (sleep_time < 1000000)) + { + sbr_get_fd_share (sk)->block_polling_time = sleep_time * 1000; + NSSOC_LOGINF + ("udp set recv sleep time success]usleep time=%d,fd=%d", + sbr_get_fd_share (sk)->block_polling_time, sk->fd); + return ERR_OK; + } + else + { + NSSOC_LOGINF ("set recv sleep time failed]fd=%d", sk->fd); + sbr_set_sk_io_errno (sk, EINVAL); + return -1; + } + } + + default: + err = ENOPROTOOPT; + break; + } + + if (err != 0) + { + NSSBR_LOGERR ("fail]fd=%d,level=%d,optname=%d,err=%d", sk->fd, level, + optname, err); + + if (ENOPROTOOPT == err) + { + return 0; + } + else + { + sbr_set_sk_errno (sk, err); + return -1; + } + } + + return sbr_handle_setsockopt (sk, level, optname, optval, optlen); +} + +static inline int +sbr_udp_get_from_addr (sbr_socket_t * sk, struct sockaddr *from, + socklen_t * fromlen, struct spl_netbuf *buf) +{ + int ret; + u16 port = netbuf_fromport (buf); + spl_ip_addr_t *addr = netbuf_fromaddr (buf); + + ret = (from + && fromlen) ? sbr_get_sockaddr_and_len (port, addr, from, + fromlen) : 0; + if (0 != ret) + { + sbr_set_sk_io_errno (sk, EINVAL); + NSSBR_LOGERR ("sbr_udp_get_from_addr]fd=%d", sk->fd); + return -1; + } + + return 0; +} + +/***************************************************************************** +* Prototype : sbr_udp_recv_from_ring +* Description : recv buf from ring +* Input : sbr_socket_t * sk +* struct spl_netbuf ** buf +* i32 timeout +* Output : None +* Return Value : static inline int +* Calls : +* Called By : +* +*****************************************************************************/ +static inline int +sbr_udp_recv_from_ring (sbr_socket_t * sk, struct spl_netbuf **buf, + i32 timeout) +{ + void *p = NULL; + spl_netconn_t *conn = sbr_get_conn (sk); + + if (sbr_dequeue_buf (sk, &p, timeout) != 0) + { + return -1; + } + + *buf = (struct spl_netbuf *) ((char *) p + sizeof (struct spl_pbuf)); + ss_sub_recv_event (conn); + return 0; +} + +/***************************************************************************** +* Prototype : _sbr_udp_recvfrom +* Description : base recvfrom,without lock +* Input : sbr_socket_t * sk +* void * mem +* size_t len +* int flags +* struct sockaddr * from +* socklen_t * fromlen +* Output : None +* Return Value : static inline int +* Calls : +* Called By : +* +*****************************************************************************/ +static inline int +_sbr_udp_recvfrom (sbr_socket_t * sk, void *mem, size_t len, int flags, + struct sockaddr *from, socklen_t * fromlen) +{ + struct spl_netbuf *buf = NULL; + struct spl_pbuf *p; + u32 buflen; + u32 copylen; + u32 off = 0; + + if (sbr_get_fd_share (sk)->lastdata) + { + buf = ADDR_SHTOL (sbr_get_fd_share (sk)->lastdata); + } + else + { + if ((flags & MSG_DONTWAIT) || ss_is_nonblock_flag (sbr_get_conn (sk))) + { + /* + * return with last err when + * some fatal err occurs, for example, spl just recovered from a fault. + */ + int err = ss_get_last_errno (sbr_get_conn (sk)); + if (SPL_ERR_IS_FATAL (err)) + { + NSSBR_LOGDBG ("connection fatal error]sk->fd=%d,errno=%d", + sk->fd, err); + sbr_set_sk_io_errno (sk, sbr_spl_err_to_errno (err)); + return -1; + } + + if (ss_get_recv_event (sbr_get_conn (sk)) <= 0) + { + NSSBR_LOGDBG ("no recv event]fd=%d", sk->fd); + sbr_set_sk_io_errno (sk, EWOULDBLOCK); + return -1; + } + } + + if (sbr_udp_recv_from_ring + (sk, &buf, sbr_get_fd_share (sk)->recv_timeout) != 0) + { + return -1; + } + + sbr_get_fd_share (sk)->lastdata = (void *) ADDR_LTOSH (buf); + } + + p = (struct spl_pbuf *) ADDR_SHTOL (buf->p); + buflen = p->tot_len; + + if (mem) + { + copylen = len > buflen ? buflen : len; + + if ((copylen > 0) && 0 == spl_pbuf_copy_partial (p, mem, copylen, 0)) + { + NSSBR_LOGERR ("copy failed]fd=%d", sk->fd); + sbr_set_sk_io_errno (sk, EFAULT); + return -1; + } + + off += copylen; + } + + if (sbr_udp_get_from_addr (sk, from, fromlen, buf) != 0) + { + return -1; + } + + if (!(flags & MSG_PEEK)) + { + sbr_get_fd_share (sk)->lastdata = NULL; + sbr_com_free_recv_buf (sk, (struct spl_pbuf *) ADDR_SHTOL (buf->p)); + } + + return off; +} + +/***************************************************************************** +* Prototype : sbr_udp_recvfrom +* Description : recv from +* Input : sbr_socket_t * sk +* void * mem +* size_t len +* int flags +* struct sockaddr * from +* socklen_t * fromlen +* Output : None +* Return Value : static int +* Calls : +* Called By : +* +*****************************************************************************/ +static int +sbr_udp_recvfrom (sbr_socket_t * sk, void *mem, size_t len, int flags, + struct sockaddr *from, socklen_t * fromlen) +{ + sbr_com_lock_recv (sk); + int ret = _sbr_udp_recvfrom (sk, mem, len, flags, from, fromlen); + sbr_com_unlock_recv (sk); + return ret; +} + +/***************************************************************************** +* Prototype : sbr_udp_recvdata +* Description : recv data +* Input : sbr_socket_t * sk +* const struct iovec* iov +* int iovcnt +* struct spl_netbuf *buf +* Output : None +* Return Value : static inline +* Calls : +* Called By : +* +*****************************************************************************/ +static inline int +sbr_udp_recvdata (sbr_socket_t * sk, const struct iovec *iov, int iovcnt, + int flags, struct sockaddr *from, socklen_t * fromlen) +{ + sbr_com_lock_recv (sk); + if (-1 == _sbr_udp_recvfrom (sk, NULL, 0, MSG_PEEK, from, fromlen)) + { + sbr_com_unlock_recv (sk); + return -1; + } + + struct spl_netbuf *buf = ADDR_SHTOL (sbr_get_fd_share (sk)->lastdata); + struct spl_pbuf *p = (struct spl_pbuf *) ADDR_SHTOL (buf->p); + u32 buflen = p->tot_len; + u32 copylen = 0; + u32 offset = 0; + + int i; + + for (i = 0; i < iovcnt; ++i) + { + if (!iov[i].iov_base || (0 == iov[i].iov_len)) + { + continue; + } + + copylen = buflen > iov[i].iov_len ? iov[i].iov_len : buflen; + if ((copylen > 0) + && 0 == spl_pbuf_copy_partial (p, iov[i].iov_base, copylen, offset)) + { + NSSBR_LOGERR ("copy failed]fd=%d", sk->fd); + goto done; + } + + offset += copylen; + buflen -= copylen; + + if (0 == buflen) + { + goto done; + } + } + +done: + if (!(flags & MSG_PEEK)) + { + sbr_get_fd_share (sk)->lastdata = NULL; + sbr_com_free_recv_buf (sk, (struct spl_pbuf *) ADDR_SHTOL (buf->p)); + } + + sbr_com_unlock_recv (sk); + return offset; +} + +/***************************************************************************** +* Prototype : sbr_udp_readv +* Description : readv +* Input : sbr_socket_t* sk +* const struct iovec* iov +* int iovcnt +* Output : None +* Return Value : static int +* Calls : +* Called By : +* +*****************************************************************************/ +static int +sbr_udp_readv (sbr_socket_t * sk, const struct iovec *iov, int iovcnt) +{ + return sbr_udp_recvdata (sk, iov, iovcnt, 0, NULL, NULL); +} + +/***************************************************************************** +* Prototype : sbr_udp_recvmsg +* Description : recv msg +* Input : sbr_socket_t* sk +* struct msghdr* msg +* int flags +* Output : None +* Return Value : static int +* Calls : +* Called By : +* +*****************************************************************************/ +static int +sbr_udp_recvmsg (sbr_socket_t * sk, struct msghdr *msg, int flags) +{ + return sbr_udp_recvdata (sk, msg->msg_iov, msg->msg_iovlen, flags, + (struct sockaddr *) msg->msg_name, + &msg->msg_namelen); +} + +/***************************************************************************** +* Prototype : sbr_copy_iov +* Description : copy iov +* Input : sbr_socket_t * sk +* const struct iovec * iov +* int iovcnt +* struct spl_pbuf* buf +* Output : None +* Return Value : static inline int +* Calls : +* Called By : +* +*****************************************************************************/ +static inline int +sbr_copy_iov (sbr_socket_t * sk, const struct iovec *iov, int iovcnt, + struct spl_pbuf *buf) +{ + u32 buf_left = buf->len; + i8 *buf_data = (i8 *) ADDR_SHTOL (buf->payload); + u32 iov_left; + i8 *iov_data; + u32 copy_len; + + int i; + + for (i = 0; i < iovcnt; ++i) + { + if (!iov[i].iov_base || (0 == iov[i].iov_len)) + { + continue; + } + + iov_left = (u32) iov[i].iov_len; /* to u32 is ok,len is checked in sbr_udp_senddata */ + iov_data = (i8 *) iov[i].iov_base; + while (iov_left) + { + copy_len = buf_left > iov_left ? iov_left : buf_left; + + if (NULL == common_memcpy (buf_data, iov_data, copy_len)) + { + NSSBR_LOGERR ("common_memcpy error]fd=%d", sk->fd); + sbr_set_sk_errno (sk, EFAULT); + return -1; + } + + buf_data += copy_len; + buf_left -= copy_len; + iov_data += copy_len; + iov_left -= copy_len; + if (0 == buf_left) + { + buf = (struct spl_pbuf *) ADDR_SHTOL (buf->next); + if (buf) + { + buf_left = buf->len; + buf_data = (i8 *) ADDR_SHTOL (buf->payload); + } + else + { + return 0; + } + } + } + } + + return 0; +} + +/***************************************************************************** +* Prototype : sbr_udp_senddata +* Description : send data +* Input : sbr_socket_t * sk +* const struct iovec * iov +* int iovcnt +* int flags +* const struct sockaddr * to +* socklen_t tolen +* Output : None +* Return Value : static inline int +* Calls : +* Called By : +* +*****************************************************************************/ +static inline int +sbr_udp_senddata (sbr_socket_t * sk, const struct iovec *iov, int iovcnt, + int flags, const struct sockaddr *to, socklen_t tolen) +{ + size_t size = 0; + int iov_idx; + + for (iov_idx = 0; iov_idx < iovcnt; ++iov_idx) + { + if ((SPL_MAX_UDP_MSG_LEN - size) < iov[iov_idx].iov_len) + { + NSSBR_LOGERR + ("size > SPL_MAX_UDP_MSG_LEN]fd=%d,SPL_MAX_UDP_MSG_LEN=%u", + sk->fd, SPL_MAX_UDP_MSG_LEN); + sbr_set_sk_io_errno (sk, EMSGSIZE); + return -1; + } + + size += iov[iov_idx].iov_len; + } + + if (to == NULL) + { + /* if not bind , then dest address should not be NULL */ + if (IPADDR_ANY == ss_get_remote_ip (sbr_get_conn (sk))->addr) + { + NSSBR_LOGERR ("dest address is null]fd=%d", sk->fd); + sbr_set_sk_io_errno (sk, EDESTADDRREQ); + return -1; + } + } + else if (to->sa_family != AF_INET) + { + NSSBR_LOGERR ("invalid address family]fd=%d,family=%d", sk->fd, + to->sa_family); + sbr_set_sk_io_errno (sk, EAFNOSUPPORT); + return -1; + } + else if (tolen != sizeof (struct sockaddr_in)) + { + NSSBR_LOGERR ("invalid address len]fd=%d,tolen=%u", sk->fd, tolen); + sbr_set_sk_io_errno (sk, EINVAL); + return -1; + } + + struct spl_netbuf buf; + const struct sockaddr_in *to_in = (const struct sockaddr_in *) to; + buf.p = NULL; + if (to_in) + { + NSSBR_LOGDBG ("fd=%d,addr=%s,port=%d,conn=%p,private_data=%p", sk->fd, + spl_inet_ntoa (to_in->sin_addr), ntohs (to_in->sin_port), + sbr_get_conn (sk), + ss_get_private_data (sbr_get_conn (sk))); + inet_addr_to_ipaddr (&buf.addr, &to_in->sin_addr); + netbuf_fromport (&buf) = ntohs (to_in->sin_port); + } + else + { + spl_ip_addr_set_any (&buf.addr); + netbuf_fromport (&buf) = 0; + } + + spl_ip_addr_t local_ip; + if (IPADDR_ANY == ss_get_local_ip (sbr_get_conn (sk))->addr) + { + if (sbr_get_src_ip (buf.addr.addr, &local_ip.addr) != 0) + { + sbr_set_sk_io_errno (sk, EHOSTUNREACH); + NSSBR_LOGERR ("get src ip failed]fd=%d", sk->fd); + return -1; + } + } + + int err = ss_get_last_errno (sbr_get_conn (sk)); + if (SPL_ERR_IS_FATAL (err)) + { + NS_LOG_CTRL (LOG_CTRL_SEND, LOGSBR, "NSSBR", NSLOG_ERR, + "connection fatal error!err=%d", err); + sbr_set_sk_errno (sk, sbr_spl_err_to_errno (err)); + return -1; + } + + u16 remain_len = size; //+ head_room_len; + struct spl_pbuf *p = NULL; + PRIMARY_ADDR struct spl_pbuf *header = NULL; + struct spl_pbuf **tail = &header; + u16 head_len = L2_L3_ROOM_LEN + L4_ROOM_LEN; + u16 copy_len; + u16 alloc_len; + + do + { + copy_len = + remain_len > + (SPL_PBUF_UDP_LEN - head_len) ? (SPL_PBUF_UDP_LEN - + head_len) : remain_len; + alloc_len = head_len + copy_len; + p = sbr_malloc_tx_pbuf (alloc_len, head_len); + if (unlikely (!p)) + { + NSSBR_LOGDBG ("malloc pbuf failed]fd=%d", sk->fd); + sbr_set_sk_io_errno (sk, ENOMEM); + sbr_handle_free_send_buf (sk, + (struct spl_pbuf *) ADDR_SHTOL (header)); + // ss_set_send_event(sbr_get_conn(sk), 0); + return -1; + } + + struct spl_pbuf *tmp = (struct spl_pbuf *) ADDR_SHTOL (header); + while (tmp) + { + tmp->tot_len += p->len; + tmp = (struct spl_pbuf *) ADDR_SHTOL (tmp->next); + } + + *tail = (struct spl_pbuf *) ADDR_LTOSH (p); /* header will changed to share */ + tail = &p->next; + + remain_len -= copy_len; + head_len = L2_L3_ROOM_LEN; + } + while (remain_len); + + /*udp support len=0 */ + if (size != 0) + { + if (sbr_copy_iov + (sk, iov, iovcnt, (struct spl_pbuf *) ADDR_SHTOL (header)) != 0) + { + sbr_handle_free_send_buf (sk, + (struct spl_pbuf *) ADDR_SHTOL (header)); + return -1; + } + } + + buf.p = header; + err = sbr_handle_udp_send (sk, &buf, &local_ip); + if (0 == err) + { + epoll_triggle_event_from_api (sk, EPOLL_API_OP_SEND); + //ss_set_send_event(sbr_get_conn(sk), 1); + return size; + } + else + { + sbr_handle_free_send_buf (sk, (struct spl_pbuf *) ADDR_SHTOL (buf.p)); + return -1; + } + +} + +/***************************************************************************** +* Prototype : sbr_udp_sendto +* Description : sendto +* Input : sbr_socket_t * sk +* const void * data +* size_t size +* int flags +* const struct sockaddr * to +* socklen_t tolen +* Output : None +* Return Value : static int +* Calls : +* Called By : +* +*****************************************************************************/ +static int +sbr_udp_sendto (sbr_socket_t * sk, const void *data, size_t size, int flags, + const struct sockaddr *to, socklen_t tolen) +{ + struct iovec iov; + + iov.iov_base = (void *) data; + iov.iov_len = size; + return sbr_udp_senddata (sk, &iov, 1, flags, to, tolen); +} + +/***************************************************************************** +* Prototype : sbr_udp_send +* Description : send +* Input : sbr_socket_t * sk +* const void * data +* size_t size +* int flags +* Output : None +* Return Value : static int +* Calls : +* Called By : +* +*****************************************************************************/ +static int +sbr_udp_send (sbr_socket_t * sk, const void *data, size_t size, int flags) +{ + return sk->fdopt->sendto (sk, data, size, flags, NULL, 0); +} + +/***************************************************************************** +* Prototype : sbr_udp_sendmsg +* Description : send msg +* Input : sbr_socket_t * sk +* const struct msghdr * pmsg +* int flags +* Output : None +* Return Value : static int +* Calls : +* Called By : +* +*****************************************************************************/ +static int +sbr_udp_sendmsg (sbr_socket_t * sk, const struct msghdr *pmsg, int flags) +{ + return sbr_udp_senddata (sk, pmsg->msg_iov, pmsg->msg_iovlen, flags, + (struct sockaddr *) pmsg->msg_name, + pmsg->msg_namelen); +} + +/***************************************************************************** +* Prototype : sbr_udp_writev +* Description : writev +* Input : sbr_socket_t * sk +* const struct iovec * iov +* int iovcnt +* Output : None +* Return Value : static int +* Calls : +* Called By : +* +*****************************************************************************/ +static int +sbr_udp_writev (sbr_socket_t * sk, const struct iovec *iov, int iovcnt) +{ + return sbr_udp_senddata (sk, iov, iovcnt, 0, NULL, 0); +} + +/***************************************************************************** +* Prototype : sbr_udp_fcntl +* Description : fcntl +* Input : sbr_socket_t * sk +* int cmd +* long arg +* Output : None +* Return Value : static int +* Calls : +* Called By : +* +*****************************************************************************/ +static int +sbr_udp_fcntl (sbr_socket_t * sk, int cmd, long arg) +{ + int ret = 0; + + switch (cmd) + { + case F_GETFL: + ret = ss_get_nonblock_flag (sbr_get_conn (sk)); + NSSBR_LOGDBG ("F_GETFL]fd=%d,ret=%d", sk->fd, ret); + break; + case F_SETFL: + if (arg & O_NONBLOCK) + { + NSSBR_LOGDBG ("F_SETFL set O_NONBLOCK val]fd=%d,arg=%ld", sk->fd, + arg); + ss_set_nonblock_flag (sbr_get_conn (sk), (arg & O_NONBLOCK)); + } + else + { + NSSBR_LOGDBG ("F_SETFL clean O_NONBLOCK val]fd=%d,arg=%ld", sk->fd, + arg); + ss_set_nonblock_flag (sbr_get_conn (sk), 0); + } + + break; + default: + NSSBR_LOGERR ("cmd is not support]fd=%d,cmd=%d", sk->fd, cmd); + ret = -1; + sbr_set_sk_errno (sk, EINVAL); + + break; + } + + return ret; +} + +/***************************************************************************** +* Prototype : sbr_udp_ioctl +* Description : ioctl +* Input : sbr_socket_t * sk +* unsigned long cmd +* void * arg +* Output : None +* Return Value : static int +* Calls : +* Called By : +* +*****************************************************************************/ +static int +sbr_udp_ioctl (sbr_socket_t * sk, unsigned long cmd, void *arg) +{ + int ret = 0; + + switch (cmd) + { + case FIONREAD: + { + if (!sbr_com_try_lock_recv (sk)) + { + return 0; + } + + struct spl_pbuf *p = NULL; + struct spl_netbuf *buf = NULL; + if (!sbr_get_fd_share (sk)->lastdata) + { + ret = sbr_udp_recv_from_ring (sk, &buf, -1); + if (ret != 0) + { + sbr_com_unlock_recv (sk); + return EWOULDBLOCK == errno ? 0 : -1; + } + + sbr_get_fd_share (sk)->lastdata = (void *) ADDR_LTOSH (buf); + p = (struct spl_pbuf *) ADDR_SHTOL (buf->p); + } + else + { + buf = + (struct spl_netbuf *) + ADDR_SHTOL (sbr_get_fd_share (sk)->lastdata); + p = (struct spl_pbuf *) ADDR_SHTOL (buf->p); + } + + *((u32 *) arg) = p->tot_len; + sbr_com_unlock_recv (sk); + } + break; + case FIONBIO: + { + u8 val = 0; + + if (arg && *(u32 *) arg) + { + val = 1; + } + + ss_set_nonblock_flag (sbr_get_conn (sk), val); + NSSBR_LOGDBG ("FIONBIO]fd=%d,val=%u", sk->fd, val); + } + break; + default: + { + NSSBR_LOGERR ("cmd is not support]fd=%d,cmd=%lu", sk->fd, cmd); + ret = -1; + sbr_set_sk_errno (sk, ENOTTY); + } + + break; + } + + return ret; +} + +/***************************************************************************** +* Prototype : sbr_udp_close +* Description : close +* Input : sbr_socket_t * sk +* Output : None +* Return Value : static int +* Calls : +* Called By : +* +*****************************************************************************/ +static int +sbr_udp_close (sbr_socket_t * sk) +{ + if (sbr_get_fd_share (sk)->lastdata) + { + struct spl_netbuf *buf = ADDR_SHTOL (sbr_get_fd_share (sk)->lastdata); + struct spl_pbuf *p = (struct spl_pbuf *) ADDR_SHTOL (buf->p); + sbr_com_free_recv_buf (sk, p); + } + + /* if failed,free it in recycle */ + return sbr_handle_close (sk, 0); +} + +sbr_fdopt udp_fdopt = { + .socket = sbr_udp_socket, + .bind = sbr_udp_bind, + .listen = sbr_udp_listen, + .accept = sbr_udp_accept, + .accept4 = sbr_udp_accept4, + .connect = sbr_udp_connect, + .shutdown = sbr_udp_shutdown, + .getsockname = sbr_udp_getsockname, + .getpeername = sbr_udp_getpeername, + .getsockopt = sbr_udp_getsockopt, + .setsockopt = sbr_udp_setsockopt, + .recvfrom = sbr_udp_recvfrom, + .readv = sbr_udp_readv, + .recvmsg = sbr_udp_recvmsg, + .send = sbr_udp_send, + .sendto = sbr_udp_sendto, + .sendmsg = sbr_udp_sendmsg, + .writev = sbr_udp_writev, + .fcntl = sbr_udp_fcntl, + .ioctl = sbr_udp_ioctl, + .close = sbr_udp_close, + .peak = sbr_com_peak, + .lock_common = sbr_com_lock_common, + .unlock_common = sbr_com_unlock_common, + .ep_getevt = stackx_eventpoll_getEvt, + .ep_ctl = stackx_eventpoll_triggle, + .set_close_stat = NULL, +}; |