/* * * 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 #include #ifndef __USE_GNU #define __USE_GNU #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE /* define RTLD_NEXT */ #endif #include #include #include #include "nstack.h" #include "nstack_socket.h" #include "nstack_fd_mng.h" #include "nstack_dmm_api.h" #include "nstack_sockops.h" #include "nstack_module.h" #include "common_mem_spinlock.h" #include "nstack_securec.h" #include "nsfw_init.h" #include "nsfw_recycle_api.h" #include "nsfw_base_linux_api.h" #include "nstack_rd_data.h" #include "nstack_rd.h" #include "select_adapt.h" #include "nstack_select.h" #include "nstack_share_res.h" #ifndef F_SETFL #define F_SETFL 4 #endif #define NSTACK_LOOP_IP 0x100007f #define NSTACK_ANY_IP 0x0 #ifndef REPLAYS_POSIX_API #define REPLAYS_POSIX_API 1 #endif #if REPLAYS_POSIX_API #define strong_alias(name, aliasname) \ extern __typeof (name) aliasname __attribute__ ((alias (#name))); #undef NSTACK_MK_DECL #define NSTACK_MK_DECL(ret, fn, args) strong_alias(nstack_##fn, fn) #include #endif #define NSTACK_FUN_CHECK_RET(fdops, mod, fun) \ if (!(fdops) || !(fdops)->pf##fun) \ { \ nstack_set_errno(ENOSYS); \ NSSOC_LOGERR("nstack module:%d ops:%p, ops->pf%s:%p error [return]", mod, fdops, #fun, (fdops)->pf##fun); \ return -1; \ } #define NSTACK_DOMAIN_CHECK_RET(domainVal, fn, para) { \ if ((domainVal != AF_INET) \ && (domainVal != PF_INET)) \ { \ int _ret_ = 0; \ if (nstack_fix_fd_check() && nstack_fix_fd_check()(-1, STACK_FD_FUNCALL_CHECK)) \ { \ NSTACK_CAL_FUN(nstack_fix_mid_ops(), fn, para, _ret_); \ } \ return _ret_; \ } \ } #define NSTACK_FD_LINUX_CHECK(fdVal, fn, fdInf, para) { \ if (!(fdInf = nstack_getValidInf(fdVal))) \ { \ if (NSTACK_THREAD_LOADING()) \ { \ return nsfw_base_##fn para;\ } \ if (0 == nstack_stack_module_load()) \ { \ if (nstack_fix_fd_check() && nstack_fix_fd_check()(fdVal, STACK_FD_FUNCALL_CHECK)) \ { \ int _ret_ = 0; \ NSTACK_CAL_FUN(nstack_fix_mid_ops(), fn, para, _ret_); \ return _ret_; \ } \ } \ nstack_set_errno(ENOSYS); \ return -1; \ } \ } #define NSTACK_SELECT_LINUX_CHECK() (get_select_module()->inited) /* Supports multi-threaded and multi-process */ NSTACK_STATIC inline void set_fd_status (int fd, FD_STATUS status) { nstack_fd_local_lock_info_t *local_lock = get_fd_local_lock_info (fd); if (local_lock) { if (FD_OPEN == status) { atomic_inc (&local_lock->fd_ref); } local_lock->fd_status = status; } } void set_fd_status_lock_fork (int fd, FD_STATUS status) { common_mem_rwlock_read_lock (get_fork_lock ()); set_fd_status (fd, status); common_mem_rwlock_read_unlock (get_fork_lock ()); } /***************************************************************** Parameters : domain type protocol Return : Description : create a nstack fd for application *****************************************************************/ int nstack_socket (int domain, int itype, int protocol) { int ret = -1; //tmp ret of a Single proctol mode. int rdret = -1; //the final Return judge vale. int modInx; nstack_socket_ops *ops; int ret_fd = -1; int protoFD[NSTACK_MAX_MODULE_NUM]; nstack_rd_key rdkey = { 0 }; int selectmod = -1; /*check whether module init finish or not */ NSTACK_INIT_CHECK_RET (socket, domain, itype, protocol); NSSOC_LOGINF ("(domain=%d, type=%d, protocol=%d) [Caller]", domain, itype, protocol); /*if domain don't equal AF_INET , just call linux */ NSTACK_DOMAIN_CHECK_RET (domain, socket, (domain, itype, protocol)); nstack_each_modInx (modInx) { protoFD[modInx] = -1; } /*create the fix socket first, and check it wether ok */ NSTACK_CAL_FUN (nstack_fix_mid_ops (), socket, (domain, itype, protocol), ret_fd); if (!nstack_is_nstack_sk (ret_fd)) { if (ret_fd >= 0) { NSTACK_CAL_FUN (nstack_fix_mid_ops (), close, (ret_fd), ret); nstack_set_errno (EMFILE); } NSSOC_LOGERR ("[nstack_linux]domain=%d,type=%d protocol=%d linux fd=%d is too big and return fail [return]", domain, itype, protocol, ret_fd); return ns_fail; } protoFD[nstack_get_fix_mid ()] = ret_fd; nstack_fd_local_lock_info_t *lock_info = get_fd_local_lock_info (ret_fd); LOCK_FOR_EP (lock_info); /*check wether select stack create success, if no return fail */ rdkey.type = RD_DATA_TYPE_PROTO; rdkey.proto_type = itype; rdret = nstack_rd_get_stackid (&rdkey, &selectmod); if ((0 != rdret) || (selectmod < 0) || (selectmod >= nstack_get_modNum ())) { NSSOC_LOGERR ("protocol:%d select stack fail", protocol); selectmod = -1; } else { NSSOC_LOGINF ("Create socket of]select modName=%s", nstack_get_module_name_by_idx (selectmod)); } /*create socket by calling select module or all module */ nstack_each_modOps (modInx, ops) { if (modInx == nstack_get_fix_mid ()) { continue; } /*if no module selected then create all or just create selected stack */ if ((selectmod == -1) || (modInx == selectmod)) { NSTACK_CAL_FUN (ops, socket, (domain, itype, protocol), ret); protoFD[modInx] = ret; NSSOC_LOGINF ("Create socket of]modName=%s:%d", nstack_get_module_name_by_idx (modInx), protoFD[modInx]); if ((modInx == selectmod) && (-1 == ret)) { goto SOCKET_ERR; } } } /* alloc nstack fd info */ nstack_fd_Inf *fdInf = nstack_lk_fd_alloc_with_kernel (ret_fd); if (NULL == fdInf) { /*if alloc failed */ nstack_set_errno (EMFILE); NSSOC_LOGERR ("have no available nstack_fd_Inf [return]"); goto SOCKET_ERR; } /*save the fd into fdinfo */ fdInf->type = itype; nstack_each_modInx (modInx) { if (-1 != protoFD[modInx]) { nstack_set_ret (fdInf, modInx, 0); nstack_set_protoFd (fdInf, modInx, protoFD[modInx]); nstack_set_app_info (fdInf, modInx); } } set_fd_status_lock_fork (ret_fd, FD_OPEN); /*if some stack was choose, just set the chose stack */ if (-1 != selectmod) { fdInf->ops = nstack_module_ops (selectmod); nstack_set_router_protocol (fdInf, selectmod); nstack_set_routed_fd (fdInf, protoFD[selectmod]); } NSSOC_LOGINF ("create fix stack[%s] fd=%d,fdInf->fd=%d,ret=%d [return]", nstack_fix_stack_name (), ret_fd, fdInf->fd, ret_fd); UNLOCK_FOR_EP (lock_info); return ret_fd; SOCKET_ERR: nstack_each_modOps (modInx, ops) { if (-1 != protoFD[modInx]) { NSTACK_CAL_FUN (ops, close, (protoFD[modInx]), ret); } } UNLOCK_FOR_EP (lock_info); return -1; } /***************************************************************** Parameters : fd addr len Return : Description : the code of bind&listen are same, if there are another same api we should extract *****************************************************************/ int nstack_bind (int fd, const struct sockaddr *addr, socklen_t addrlen) { nstack_fd_Inf *fdInf; int retval = ns_fail; int tem = -1; int modIdx = 0; int tfd; int selectmod = -1; struct sockaddr_in *iaddr = NULL; nstack_rd_key rdkey = { 0 }; NSTACK_INIT_CHECK_RET (bind, fd, addr, addrlen); NSSOC_LOGINF ("(sockfd=%d, addr=%p, addrlen=%u) [Caller]", fd, addr, addrlen); if (fd < 0) { nstack_set_errno (EBADF); NSSOC_LOGERR ("invalid input]fd=%d,addr=%p,len=0x%x [return]", fd, addr, addrlen); return -1; } if ((NULL == addr) || (addrlen < 2)) { nstack_set_errno (EINVAL); NSSOC_LOGERR ("invalid input]fd=%d,addr=%p,len=0x%x [return]", fd, addr, addrlen); return -1; } iaddr = (struct sockaddr_in *) addr; if ((addrlen >= sizeof (struct sockaddr_in)) && ((addr->sa_family) == AF_INET)) { NSSOC_LOGINF ("fd=%d,addr=%s,port=%d", fd, inet_ntoa (iaddr->sin_addr), ntohs (iaddr->sin_port)); } else { NSSOC_LOGINF ("addrlen = %d ,fd=%d", (int) addrlen, fd); } NSTACK_FD_LINUX_CHECK (fd, bind, fdInf, (fd, addr, addrlen)); nstack_fd_local_lock_info_t *local_lock = &fdInf->local_lock; LOCK_COMMON (fd, fdInf, local_lock); NSTACK_EPOLL_FD_CHECK_RET_UNLOCK_COMMON (fd, bind, fdInf, ENOTSOCK, local_lock); /*bind repeat, first time success, other return fail */ if (fdInf->isBound) { nstack_set_errno (EINVAL); NSPOL_LOGERR ("error, already bind]fd=%d", fd); UNLOCK_COMMON (fd, local_lock); return -1; } /*just support af_inet and pf_inet */ if (iaddr->sin_family != AF_INET && iaddr->sin_family != PF_INET) { nstack_set_errno (EAFNOSUPPORT); NSSOC_LOGERR ("not surport]fd=%d,domain=%d,[return]", fd, iaddr->sin_family); UNLOCK_COMMON (fd, local_lock); return -1; } /* need check addrlen's validity, will visite iaddr->sin_addr.s_addr following code for visite iaddr->sin_addr.s_addr is 8 byte */ if (addrlen < 8) { nstack_set_errno (EINVAL); NSPOL_LOGERR ("addrlenops) { NSTACK_CAL_FUN (fdInf->ops, bind, (fdInf->rlfd, addr, addrlen), tem); if (ns_success == tem) { retval = ns_success; nstack_set_bind_ret (fdInf, fdInf->rmidx, NSTACK_BIND_SUCCESS); } else { nstack_set_bind_ret (fdInf, fdInf->rmidx, NSTACK_BIND_FAIL); } goto bind_over; } /*loop ip call linux */ rdkey.type = RD_DATA_TYPE_IP; rdkey.ip_addr = iaddr->sin_addr.s_addr; retval = nstack_rd_get_stackid (&rdkey, &selectmod); if ((ns_success != retval) && (-1 != selectmod)) { NSSOC_LOGWAR ("fd Can't select any module for]fd=%d,IP==%s", fd, inet_ntoa ((iaddr->sin_addr))); selectmod = -1; } else { NSSOC_LOGINF ("fd addr Select module]fd=%d,addr=%s,module=%s", fd, inet_ntoa (iaddr->sin_addr), nstack_get_module_name_by_idx (selectmod)); } retval = -1; nstack_each_modInx (modIdx) { tfd = nstack_get_protoFd (fdInf, modIdx); if ((-1 == tfd) || (selectmod != modIdx)) // for INADDR_ANY, need try to bind on both stack-x and linux { /*tfd is -1, but is the select module */ if (selectmod == modIdx) { retval = -1; nstack_set_errno (ENOSYS); NSSOC_LOGDBG ("fd tfd=-1, but is the select module]fd=%d,tfd=-1,modIdx=%d", fd, modIdx); } nstack_set_bind_ret (fdInf, modIdx, NSTACK_BIND_FAIL); continue; } NSTACK_CAL_FUN (nstack_module_ops (modIdx), bind, (tfd, addr, addrlen), tem); if (ns_success == tem) { fdInf->ops = nstack_module_ops (modIdx); nstack_set_router_protocol (fdInf, modIdx); nstack_set_routed_fd (fdInf, tfd); retval = ns_success; nstack_set_bind_ret (fdInf, modIdx, NSTACK_BIND_SUCCESS); } else { NSSOC_LOGWAR ("bind fail]module=%s,fd=%d", nstack_get_module_name_by_idx (modIdx), tfd); nstack_set_bind_ret (fdInf, modIdx, NSTACK_BIND_FAIL); } } if (-1 == selectmod) { nstack_set_errno (EINVAL); NSSOC_LOGERR ("failed for no module selected]fd=%d", fd); } bind_over: if (ns_success == retval) { fdInf->isBound = 1; } NSSOC_LOGINF ("appfd=%d,prot_fd=%d,rmidx=%d, retVal=%d [return]", fd, fdInf->rlfd, fdInf->rmidx, retval); UNLOCK_COMMON (fd, local_lock); return retval; } int nstack_listen (int fd, int backlog) { nstack_fd_Inf *fdInf; int retval = -1; int tem = -1; int modIdx = 0; int tfd; int func_called = 0; NSTACK_INIT_CHECK_RET (listen, fd, backlog); NSSOC_LOGINF ("(sockfd=%d, backlog=%d) [Caller]", fd, backlog); if (fd < 0) { nstack_set_errno (EBADF); NSSOC_LOGERR ("invalid input]fd=%d,backlog=%d [return]", fd, backlog); return -1; } NSTACK_FD_LINUX_CHECK (fd, listen, fdInf, (fd, backlog)); nstack_fd_local_lock_info_t *local_lock = &fdInf->local_lock; LOCK_COMMON (fd, fdInf, local_lock); NSTACK_EPOLL_FD_CHECK_RET_UNLOCK_COMMON (fd, listen, fdInf, ENOTSOCK, local_lock); /*listen:use all mode we support */ nstack_each_modInx (modIdx) { tfd = nstack_get_protoFd (fdInf, modIdx); if ((-1 == tfd) || (NSTACK_BIND_FAIL == nstack_get_bind_ret (fdInf, modIdx))) { continue; } func_called = 1; NSTACK_CAL_FUN (nstack_module_ops (modIdx), listen, (tfd, backlog), tem); if (ns_success == tem) { nstack_set_listen_state (fdInf, modIdx, NSTACK_LISTENING); NSTACK_SET_FD_LISTEN_SOCKET (fdInf); retval = ns_success; nstack_set_listen_ret (fdInf, modIdx, NSTACK_LISTEN_SUCCESS); } else { NSSOC_LOGWAR ("listen fail]fd=%d,module=%s,tfd=%d", fd, nstack_get_module_name_by_idx (modIdx), tfd); nstack_set_listen_ret (fdInf, modIdx, NSTACK_LISTEN_FAIL); nstack_set_listen_state (fdInf, modIdx, NSTACK_NO_LISTENING); } } if (0 == func_called) { retval = -1; nstack_set_errno (ENOSYS); NSSOC_LOGERR ("listen fail for no module called]fd=%d", fd); } NSSOC_LOGINF ("fd=%d,ret=%d [return]", fd, retval); UNLOCK_COMMON (fd, local_lock); return retval; } int nstack_accept (int fd, struct sockaddr *addr, socklen_t * addr_len) { nstack_fd_Inf *apstfdInf = NULL; int tfd = -1; int accfd = -1; int fix_fd; int ret_fd = -1; nstack_fd_Inf *accInf; int ret = -1; NSTACK_INIT_CHECK_RET (accept, fd, addr, addr_len); NSSOC_LOGINF ("(sockfd=%d, addr=%p, addrlen=%p) [Caller]", fd, addr, addr_len); if (fd < 0) { nstack_set_errno (EBADF); NSSOC_LOGERR ("fd is invalid]fd=%d [return]", fd); return -1; } NSTACK_FD_LINUX_CHECK (fd, accept, apstfdInf, (fd, addr, addr_len)); nstack_fd_local_lock_info_t *local_lock = &apstfdInf->local_lock; LOCK_ACCEPT (fd, apstfdInf, local_lock); NSTACK_EPOLL_FD_CHECK_RET_UNLOCK_ACCEPT (fd, accept, apstfdInf, ENOTSOCK, local_lock); if (addr) { if ((!addr_len) || (*addr_len == NSTACK_MAX_U32_NUM)) { nstack_set_errno (EINVAL); NSSOC_LOGERR ("addr_len input error [return]"); UNLOCK_ACCEPT (fd, local_lock); return -1; } } /*if no module select or listen / bind fail, just return fail */ if ((!apstfdInf->ops) || (NSTACK_LISTEN_FAIL == nstack_get_listen_ret (apstfdInf, apstfdInf->rmidx)) || (NSTACK_BIND_FAIL == nstack_get_bind_ret (apstfdInf, apstfdInf->rmidx))) { nstack_set_errno (EINVAL); NSSOC_LOGERR ("nstack accept fd=%d no module select, or bind/listen fail [return]", fd); UNLOCK_ACCEPT (fd, local_lock); return -1; } tfd = nstack_get_protoFd (apstfdInf, apstfdInf->rmidx); NSTACK_CAL_FUN (nstack_module_ops (apstfdInf->rmidx), accept, (tfd, addr, addr_len), accfd); NSSOC_LOGINF ("nstack fd=%d:%d accept fd=%d from module=%s", fd, tfd, accfd, nstack_get_module_name_by_idx (apstfdInf->rmidx)); if (-1 == accfd) { if (errno != EAGAIN) { NSSOC_LOGERR ("appfd=%d,module=%s,ret=%d,errno=%d [return]", fd, nstack_get_module_name_by_idx (apstfdInf->rmidx), accfd, errno); } UNLOCK_ACCEPT (fd, local_lock); return -1; } // If it is not from kernel, need to create one kernel socket if (apstfdInf->rmidx != nstack_get_fix_mid ()) { /*err num is same with linux */ fix_fd = nstack_extern_deal (nstack_get_fix_mid ()).stack_alloc_fd (); if (fix_fd < 0) { NSSOC_LOGERR ("nstack accept fd=%d return fd=%d kernelFD fd create fail [return]", fd, accfd); NSTACK_CAL_FUN (nstack_module_ops (apstfdInf->rmidx), close, (accfd), ret); UNLOCK_ACCEPT (fd, local_lock); return -1; } } else { fix_fd = accfd; } if (fix_fd >= (int) NSTACK_KERNEL_FD_MAX) { /* nstack not support kernel fd >= NSTACK_MAX_SOCK_NUM. * close it and nstack_accept() return failed */ NSSOC_LOGERR ("kernelFD fd too big, close it. kernelFD=%d [return]", accfd); NSTACK_CAL_FUN (nstack_module_ops (apstfdInf->rmidx), close, (accfd), ret); if (apstfdInf->rmidx != nstack_get_fix_mid ()) { NSTACK_CAL_FUN (nstack_fix_mid_ops (), close, (fix_fd), ret); } nstack_set_errno (EMFILE); UNLOCK_ACCEPT (fd, local_lock); return -1; } nstack_fd_local_lock_info_t *lock_info = get_fd_local_lock_info (fix_fd); LOCK_FOR_EP (lock_info); accInf = nstack_lk_fd_alloc_with_kernel (fix_fd); ret_fd = fix_fd; if (NULL == accInf) { NSSOC_LOGERR ("Can't alloc nstack fdInf [return]"); NSTACK_CAL_FUN (nstack_module_ops (apstfdInf->rmidx), close, (accfd), ret); if (apstfdInf->rmidx != nstack_get_fix_mid ()) { NSTACK_CAL_FUN (nstack_fix_mid_ops (), close, (fix_fd), ret); } UNLOCK_FOR_EP (lock_info); nstack_set_errno (EMFILE); UNLOCK_ACCEPT (fd, local_lock); return -1; } nstack_set_routed_fd (accInf, accfd); accInf->ops = nstack_module_ops (apstfdInf->rmidx); /*do not include SOCK_CLOEXEC SOCK_NONBLOCK */ accInf->type = apstfdInf->type & (~((ns_int32) SOCK_CLOEXEC | (ns_int32) SOCK_NONBLOCK)); nstack_set_router_protocol (accInf, apstfdInf->rmidx); nstack_set_protoFd (accInf, apstfdInf->rmidx, accfd); nstack_set_app_info (accInf, apstfdInf->rmidx); /* Set the linux kernel fd also in accInf for kernel module (0) */ if (apstfdInf->rmidx != nstack_get_fix_mid ()) { nstack_set_protoFd (accInf, nstack_get_fix_mid (), fix_fd); } NSSOC_LOGINF ("listenfd=%d,acceptfd=%d,module=%s(rlfd=%d),ret=%d [return]", fd, ret_fd, nstack_get_module_name_by_idx (apstfdInf->rmidx), accfd, ret_fd); set_fd_status_lock_fork (ret_fd, FD_OPEN); UNLOCK_FOR_EP (lock_info); UNLOCK_ACCEPT (fd, local_lock); return ret_fd; } int nstack_accept4 (int fd, struct sockaddr *addr, socklen_t * addr_len, int flags) { nstack_fd_Inf *pstfdInf = NULL; int tfd = -1; int accfd = -1; int fix_fd = -1; int ret_fd = -1; int ret = -1; nstack_fd_Inf *accInf; NSTACK_INIT_CHECK_RET (accept4, fd, addr, addr_len, flags); NSSOC_LOGINF ("(sockfd=%d, addr=%p, addrlen=%p, flags=%d) [Caller]", fd, addr, addr_len, flags); if (fd < 0) { nstack_set_errno (EBADF); NSSOC_LOGERR ("nstack accept4,fd=%d invalid [return]", fd); return -1; } NSTACK_FD_LINUX_CHECK (fd, accept4, pstfdInf, (fd, addr, addr_len, flags)); nstack_fd_local_lock_info_t *local_lock = &pstfdInf->local_lock; LOCK_ACCEPT (fd, pstfdInf, local_lock); NSTACK_EPOLL_FD_CHECK_RET_UNLOCK_ACCEPT (fd, accept4, pstfdInf, ENOTSOCK, local_lock); if (addr) { if ((!addr_len) || (*addr_len == NSTACK_MAX_U32_NUM)) { nstack_set_errno (EINVAL); NSSOC_LOGERR ("nstack accept4 addr_len input error [return]"); UNLOCK_ACCEPT (fd, local_lock); return -1; } } /*if no module select or listen / bind fail, just return fail */ if ((!pstfdInf->ops) || (NSTACK_LISTEN_FAIL == nstack_get_listen_ret (pstfdInf, pstfdInf->rmidx)) || (NSTACK_BIND_FAIL == nstack_get_bind_ret (pstfdInf, pstfdInf->rmidx))) { nstack_set_errno (EINVAL); NSSOC_LOGERR ("nstack accept4 fd:%d no module select, or bind/listen fail [return]", fd); UNLOCK_ACCEPT (fd, local_lock); return -1; } tfd = nstack_get_protoFd (pstfdInf, pstfdInf->rmidx); NSTACK_CAL_FUN (nstack_module_ops (pstfdInf->rmidx), accept4, (tfd, addr, addr_len, flags), accfd); if (-1 == accfd) { if (errno != EAGAIN) { NSSOC_LOGERR ("appfd=%d,module=%s,ret=%d,errno=%d [return]", fd, nstack_get_module_name_by_idx (pstfdInf->rmidx), accfd, errno); } UNLOCK_ACCEPT (fd, local_lock); return -1; } // If it is not from kernel, need to create one kernel socket if (pstfdInf->rmidx != nstack_get_fix_mid ()) { fix_fd = nstack_extern_deal (nstack_get_fix_mid ()).stack_alloc_fd (); } else { fix_fd = accfd; } if (!nstack_is_nstack_sk (fix_fd)) { /* nstack not support kernel fd >= NSTACK_MAX_SOCK_NUM. * close it and nstack_accept() return failed */ NSSOC_LOGERR ("nstack accept4 fd=%d kernelFD fd too big, close it. kernelFD=%d [return]", fd, fix_fd); if (fix_fd >= 0) { NSTACK_CAL_FUN (nstack_module_ops (pstfdInf->rmidx), close, (accfd), ret); } if (pstfdInf->rmidx != nstack_get_fix_mid ()) { NSTACK_CAL_FUN (nstack_module_ops (nstack_get_fix_mid ()), close, (fix_fd), ret); } nstack_set_errno (EMFILE); UNLOCK_ACCEPT (fd, local_lock); return -1; } nstack_fd_local_lock_info_t *lock_info = get_fd_local_lock_info (fix_fd); LOCK_FOR_EP (lock_info); accInf = nstack_lk_fd_alloc_with_kernel (fix_fd); ret_fd = fix_fd; if (NULL == accInf) { NSTACK_CAL_FUN (nstack_module_ops (pstfdInf->rmidx), close, (accfd), ret); if (pstfdInf->rmidx != nstack_get_fix_mid ()) { NSTACK_CAL_FUN (nstack_module_ops (nstack_get_fix_mid ()), close, (fix_fd), ret); } UNLOCK_FOR_EP (lock_info); NSSOC_LOGERR ("nstack accept fd alloc is NULL [return]"); UNLOCK_ACCEPT (fd, local_lock); return -1; } nstack_set_routed_fd (accInf, accfd); accInf->ops = nstack_module_ops (pstfdInf->rmidx); accInf->type = (pstfdInf->type & (~((ns_int32) SOCK_CLOEXEC | (ns_int32) SOCK_NONBLOCK))) | (ns_int32) flags; nstack_set_router_protocol (accInf, pstfdInf->rmidx); nstack_set_protoFd (accInf, pstfdInf->rmidx, accfd); nstack_set_app_info (accInf, pstfdInf->rmidx); /* Set the linux kernel fd also in accInf for kernel module (0) */ if (pstfdInf->rmidx != nstack_get_fix_mid ()) { nstack_set_protoFd (accInf, nstack_get_fix_mid (), fix_fd); } NSSOC_LOGINF ("listenfd=%d,acceptfd=%d,accInf->fd=%d,module=%s(rlfd:%d),ret=%d [return]", fd, ret_fd, accInf->fd, nstack_get_module_name_by_idx (pstfdInf->rmidx), accfd, ret_fd); set_fd_status_lock_fork (ret_fd, FD_OPEN); UNLOCK_FOR_EP (lock_info); UNLOCK_ACCEPT (fd, local_lock); return ret_fd; } /***************************************************************** Parameters : fd addr len Return : Description : use the rd select rlfd or default rlfd to Establish connection. the unused fd should closed *****************************************************************/ int nstack_connect (int fd, const struct sockaddr *addr, socklen_t addrlen) { int retval = -1; nstack_fd_Inf *fdInf; struct sockaddr_in *iaddr = NULL; iaddr = (struct sockaddr_in *) addr; int selectmod = -1; nstack_rd_key rdkey = { 0 }; NSTACK_INIT_CHECK_RET (connect, fd, addr, addrlen); NSSOC_LOGINF ("(sockfd=%d, addr=%p, addrlen=%u) [Caller]", fd, addr, addrlen); if (fd < 0) { nstack_set_errno (EBADF); NSSOC_LOGERR ("nstack connect, fd=%d invalid input: addr=%p,len=0x%x [return]", fd, addr, addrlen); return -1; } if ((NULL == addr) || (addrlen < 2)) { nstack_set_errno (EINVAL); NSSOC_LOGERR ("nstack connect, fd=%d invalid input: addr=%p,len=0x%x [return]", fd, addr, addrlen); return -1; } if ((addrlen >= sizeof (struct sockaddr_in)) && ((addr->sa_family) == AF_INET)) { NSSOC_LOGINF ("fd=%d,addr=%s,port=%d", fd, inet_ntoa (iaddr->sin_addr), ntohs (iaddr->sin_port)); } else { NSSOC_LOGINF ("addrlen = %d ,fd=%d", (int) addrlen, fd); } /* need check addrlen's validity, will visite iaddr->sin_addr.s_addr following code,for visite iaddr->sin_addr.s_addr is 8 byte */ if (addrlen < 8) { nstack_set_errno (EINVAL); NSSOC_LOGERR ("nstack connect, fd=%d invalid addrlen input: addr=%p,len=0x%x [return]", fd, addr, addrlen); return -1; } if (NSTACK_ANY_IP == iaddr->sin_addr.s_addr) { nstack_set_errno (ECONNREFUSED); NSSOC_LOGERR ("nstack connect, fd=%d invalid input: 0==addr_in->sin_addr.s_addr [return]", fd); return -1; } else if (NSTACK_MAX_U32_NUM == iaddr->sin_addr.s_addr) { nstack_set_errno (ENETUNREACH); NSSOC_LOGERR ("nstack connect, fd=%d invalid input: 0xffffffff==addr_in->sin_addr.s_addr [return]", fd); return -1; } NSTACK_FD_LINUX_CHECK (fd, connect, fdInf, (fd, addr, addrlen)); nstack_fd_local_lock_info_t *local_lock = &fdInf->local_lock; LOCK_CONNECT (fd, fdInf, local_lock); NSTACK_EPOLL_FD_CHECK_RET_UNLOCK_CONNECT (fd, connect, fdInf, ENOTSOCK, local_lock); /*if no module select, according to dest ip */ if (!fdInf->ops) { rdkey.type = RD_DATA_TYPE_IP; rdkey.ip_addr = iaddr->sin_addr.s_addr; retval = nstack_rd_get_stackid (&rdkey, &selectmod); if (ns_success == retval && selectmod >= 0) { NSSOC_LOGINF ("fd=%d addr=%s Select module=%s", fd, inet_ntoa (iaddr->sin_addr), nstack_get_module_name_by_idx (selectmod)); /*in case of that multi-thread connect. if route was chosen by one thread, the other just use the first one */ fdInf->rmidx = selectmod; fdInf->ops = nstack_module_ops (selectmod); nstack_set_routed_fd (fdInf, nstack_get_protoFd (fdInf, selectmod)); nstack_set_router_protocol (fdInf, selectmod); } else { NSSOC_LOGERR ("fd=%d Callback select module=%d ret=0x%x", fd, selectmod, retval); nstack_set_errno (ENETUNREACH); UNLOCK_CONNECT (fd, local_lock); return -1; } NSSOC_LOGINF ("fd=%d addr=%s Select module=%s", fd, inet_ntoa (iaddr->sin_addr), nstack_get_module_name_by_idx (selectmod)); } NSTACK_CAL_FUN (fdInf->ops, connect, (fdInf->rlfd, addr, addrlen), retval); if (-1 == retval && errno != EINPROGRESS) { NSSOC_LOGERR ("appfd=%d,module=%s,proto_fd=%d,ret=%d,errno=%d [return]", fd, nstack_get_module_name_by_idx (fdInf->rmidx), fdInf->rlfd, retval, errno); } else { NSSOC_LOGINF ("appfd=%d,module=%s,proto_fd=%d,ret=%d,errno=%d [return]", fd, nstack_get_module_name_by_idx (fdInf->rmidx), fdInf->rlfd, retval, errno); } UNLOCK_CONNECT (fd, local_lock); return retval; } int nstack_shutdown (int fd, int how) { nstack_fd_Inf *fdInf = NULL; int retval = -1; int tfd; if (fd < 0) { nstack_set_errno (EBADF); NSSOC_LOGERR ("fd=%d invalid input [return]", fd); return -1; } NSTACK_INIT_CHECK_RET (shutdown, fd, how); NSSOC_LOGINF ("(fd=%d, how=%d) [Caller]", fd, how); NSTACK_FD_LINUX_CHECK (fd, shutdown, fdInf, (fd, how)); nstack_fd_local_lock_info_t *local_lock = &fdInf->local_lock; LOCK_COMMON (fd, fdInf, local_lock); NSTACK_EPOLL_FD_CHECK_RET_UNLOCK_COMMON (fd, shutdown, fdInf, ENOTSOCK, local_lock); if (!fdInf->ops || -1 == fdInf->rlfd) { NSSOC_LOGWAR ("fd=%d,how=%d, shutdown fail [return]", fd, how); nstack_set_errno (ENOTCONN); UNLOCK_COMMON (fd, local_lock); return -1; } tfd = fdInf->rlfd; NSTACK_CAL_FUN (fdInf->ops, shutdown, (tfd, how), retval); NSSOC_LOGINF ("fd=%d,ret=%d [return]", fd, retval); UNLOCK_COMMON (fd, local_lock); return retval; } int release_fd (int fd, nstack_fd_local_lock_info_t * local_lock) { nstack_fd_Inf *fdInf = NULL; nstack_module *pMod = NULL; int retval = 0; int curRet = -1; int modInx, tfd; if (!local_lock) { return -1; } LOCK_CLOSE (local_lock); /* if fd is used by others, just pass, delay close it */ if (local_lock->fd_status != FD_CLOSING || local_lock->fd_ref.counter > 0) { UNLOCK_CLOSE (local_lock); return 0; } local_lock->fd_status = FD_CLOSE; fdInf = nstack_fd2inf (fd); if (NULL == fdInf) { nstack_set_errno (EINVAL); NSSOC_LOGERR ("pstfdInf is NULL"); UNLOCK_CLOSE (local_lock); return -1; } (void) nsep_epoll_close (fd); nstack_each_module (modInx, pMod) { tfd = nstack_get_protoFd (fdInf, modInx); if (nstack_get_minfd_id (modInx) > tfd || tfd > nstack_get_maxfd_id (modInx)) { continue; } NSSOC_LOGINF ("fd=%d,module=%s,tfd=%d", fd, nstack_get_module_name_by_idx (modInx), tfd); if (0 == strcmp (nstack_fix_stack_name (), nstack_get_module_name_by_idx (modInx))) { continue; } nssct_close (fd, modInx); NSTACK_CAL_FUN ((&pMod->mops.socket_ops), close, (tfd), curRet); if (-1 == curRet) { NSSOC_LOGERR ("failed]module=%s,tfd=%d,errno=%d", nstack_get_module_name_by_idx (modInx), tfd, errno); } retval &= curRet; } retval &= nstack_fd_free_with_kernel (fdInf); if (-1 == retval) { NSSOC_LOGWAR ("fd=%d,ret=%d [return]", fd, retval); } else { NSSOC_LOGINF ("fd=%d,ret=%d [return]", fd, retval); } UNLOCK_CLOSE (local_lock); return retval; } /*not support fork now, to support fork the module must provide gfdt & refer cnt while fork the frame use callback fun to add refer*/ int nstack_close (int fd) { nstack_fd_Inf *fdInf; int ret = -1; NSTACK_INIT_CHECK_RET (close, fd); /*linux fd check */ if (!(fdInf = nstack_getValidInf (fd))) { if (NSTACK_THREAD_LOADING ()) { return nsfw_base_close (fd); } if (0 != nstack_stack_module_load ()) { return -1; } if (nstack_fix_fd_check () && nstack_fix_fd_check ()(fd, STACK_FD_FUNCALL_CHECK)) { /*free epoll resoure */ nsep_epoll_close (fd); nssct_close (fd, nstack_get_fix_mid ()); NSTACK_CAL_FUN (nstack_fix_mid_ops (), close, (fd), ret); return ret; } nstack_set_errno (ENOSYS); return -1; } NSSOC_LOGINF ("Caller]fd=%d", fd); nstack_fd_local_lock_info_t *local_lock = &fdInf->local_lock; LOCK_CLOSE (local_lock); if (local_lock->fd_status != FD_OPEN) { NSSOC_LOGERR ("return]fd_status=%d,fd=%d", local_lock->fd_status, fd); nstack_set_errno (EBADF); UNLOCK_CLOSE (local_lock); return -1; } set_fd_status_lock_fork (fd, FD_CLOSING); UNLOCK_CLOSE (local_lock); ret = (atomic_dec (&local_lock->fd_ref) > 0 ? 0 : release_fd (fd, local_lock)); if (-1 == ret) { NSSOC_LOGWAR ("return]fd=%d,retVal=%d", fd, ret); } else { NSSOC_LOGINF ("return]fd=%d,retVal=%d", fd, ret); } return ret; } ssize_t nstack_send (int fd, const void *buf, size_t len, int flags) { nstack_fd_Inf *fdInf = NULL; int size = -1; NSTACK_INIT_CHECK_RET (send, fd, buf, len, flags); NS_LOG_CTRL (LOG_CTRL_SEND, NSOCKET, "NSSOC", NSLOG_DBG, "(sockfd=%d, buf=%p, len=%zu, flags=%d) [Caller]", fd, buf, len, flags); NSTACK_FD_LINUX_CHECK (fd, send, fdInf, (fd, buf, len, flags)); nstack_fd_local_lock_info_t *local_lock = &fdInf->local_lock; LOCK_SEND (fd, fdInf, local_lock); NSTACK_EPOLL_FD_CHECK_RET_UNLOCK_SEND (fd, send, fdInf, ENOTSOCK, local_lock); if ((!fdInf->ops) || (-1 == fdInf->rlfd)) { NSSOC_LOGINF ("fd Fail: Not select any module yet!]fd=%d [return]", fd); nstack_set_errno (ENOTCONN); UNLOCK_SEND (fd, local_lock); return -1; } NSTACK_CAL_FUN (fdInf->ops, send, (fdInf->rlfd, buf, len, flags), size); NSSOC_LOGDBG ("fd=%d,ret=%d [Return]", fd, size); UNLOCK_SEND (fd, local_lock); return size; } ssize_t nstack_recv (int fd, void *buf, size_t len, int flags) { nstack_fd_Inf *fdInf = NULL; int size = -1; NSTACK_INIT_CHECK_RET (recv, fd, buf, len, flags); NS_LOG_CTRL (LOG_CTRL_RECV, NSOCKET, "NSSOC", NSLOG_DBG, "(sockfd=%d, buf=%p, len=%zu, flags=%d) [Caller]", fd, buf, len, flags); NSTACK_FD_LINUX_CHECK (fd, recv, fdInf, (fd, buf, len, flags)); nstack_fd_local_lock_info_t *local_lock = &fdInf->local_lock; LOCK_RECV (fd, fdInf, local_lock); NSTACK_EPOLL_FD_CHECK_RET_UNLOCK_RECV (fd, recv, fdInf, ENOTSOCK, local_lock); if ((!fdInf->ops) || (-1 == fdInf->rlfd)) { NSSOC_LOGINF ("Not select any module yet!]fd=%d [Return]", fd); nstack_set_errno (ENOTCONN); UNLOCK_RECV (fd, local_lock); return -1; } NSTACK_CAL_FUN (fdInf->ops, recv, (fdInf->rlfd, buf, len, flags), size); NSSOC_LOGDBG ("fd=%d,ret=%d [Return]", fd, size); UNLOCK_RECV (fd, local_lock); return size; } ssize_t nstack_write (int fd, const void *buf, size_t count) { nstack_fd_Inf *fdInf = NULL; int size = -1; NSTACK_INIT_CHECK_RET (write, fd, buf, count); NSTACK_FD_LINUX_CHECK (fd, write, fdInf, (fd, buf, count)); NS_LOG_CTRL (LOG_CTRL_WRITE, NSOCKET, "NSSOC", NSLOG_DBG, "(fd=%d, buf=%p, count=%zu) [Caller]", fd, buf, count); nstack_fd_local_lock_info_t *local_lock = &fdInf->local_lock; LOCK_SEND (fd, fdInf, local_lock); NSTACK_EPOLL_FD_CHECK_RET_UNLOCK_SEND (fd, write, fdInf, EINVAL, local_lock); if ((!fdInf->ops) || (-1 == fdInf->rlfd)) { NSSOC_LOGINF ("Not select any module yet!]fd=%d [Return]", fd); nstack_set_errno (ENOTCONN); UNLOCK_SEND (fd, local_lock); return -1; } NSTACK_CAL_FUN (fdInf->ops, write, (fdInf->rlfd, buf, count), size); NSSOC_LOGDBG ("fd=%d,ret=%d [Return]", fd, size); UNLOCK_SEND (fd, local_lock); return size; } ssize_t nstack_read (int fd, void *buf, size_t count) { nstack_fd_Inf *fdInf = NULL; int size = -1; NSTACK_INIT_CHECK_RET (read, fd, buf, count); NS_LOG_CTRL (LOG_CTRL_READ, NSOCKET, "NSSOC", NSLOG_DBG, "(fd=%d, buf=%p, count=%zu) [Caller]", fd, buf, count); NSTACK_FD_LINUX_CHECK (fd, read, fdInf, (fd, buf, count)); nstack_fd_local_lock_info_t *local_lock = &fdInf->local_lock; LOCK_RECV (fd, fdInf, local_lock); NSTACK_EPOLL_FD_CHECK_RET_UNLOCK_RECV (fd, read, fdInf, EINVAL, local_lock); if ((!fdInf->ops) || (-1 == fdInf->rlfd)) { NSSOC_LOGINF ("Not select any module yet!]fd=%d [Return]", fd); nstack_set_errno (ENOTCONN); UNLOCK_RECV (fd, local_lock); return -1; } NSTACK_CAL_FUN (fdInf->ops, read, (fdInf->rlfd, buf, count), size); NSSOC_LOGDBG ("fd=%d,ret=%d [Return]", fd, size); UNLOCK_RECV (fd, local_lock); return size; } ssize_t nstack_writev (int fd, const struct iovec * iov, int iovcnt) { nstack_fd_Inf *fdInf = NULL; int size = -1; NSTACK_INIT_CHECK_RET (writev, fd, iov, iovcnt); NS_LOG_CTRL (LOG_CTRL_WRITEV, NSOCKET, "NSSOC", NSLOG_DBG, "(fd=%d, iov=%p, count=%d) [Caller]", fd, iov, iovcnt); NSTACK_FD_LINUX_CHECK (fd, writev, fdInf, (fd, iov, iovcnt)); nstack_fd_local_lock_info_t *local_lock = &fdInf->local_lock; LOCK_SEND (fd, fdInf, local_lock); NSTACK_EPOLL_FD_CHECK_RET_UNLOCK_SEND (fd, writev, fdInf, EINVAL, local_lock); if ((!fdInf->ops) || (-1 == fdInf->rlfd)) { NSSOC_LOGERR ("Not select any module yet!]fd=%d [Return]", fd); nstack_set_errno (ENOTCONN); UNLOCK_SEND (fd, local_lock); return -1; } NSTACK_CAL_FUN (fdInf->ops, writev, (fdInf->rlfd, iov, iovcnt), size); NSSOC_LOGDBG ("fd=%d,ret=%d [Return]", fd, size); UNLOCK_SEND (fd, local_lock); return size; } ssize_t nstack_readv (int fd, const struct iovec * iov, int iovcnt) { nstack_fd_Inf *fdInf = NULL; int size = -1; NSTACK_INIT_CHECK_RET (readv, fd, iov, iovcnt); NS_LOG_CTRL (LOG_CTRL_READV, NSOCKET, "NSSOC", NSLOG_DBG, "(fd=%d, iov=%p, count=%d) [Caller]", fd, iov, iovcnt); NSTACK_FD_LINUX_CHECK (fd, readv, fdInf, (fd, iov, iovcnt)); nstack_fd_local_lock_info_t *local_lock = &fdInf->local_lock; LOCK_RECV (fd, fdInf, local_lock); NSTACK_EPOLL_FD_CHECK_RET_UNLOCK_RECV (fd, readv, fdInf, EINVAL, local_lock); if ((!fdInf->ops) || (-1 == fdInf->rlfd)) { NSSOC_LOGERR ("Not select any module yet!]fd=%d [Return]", fd); nstack_set_errno (ENOTCONN); UNLOCK_RECV (fd, local_lock); return -1; } NSTACK_CAL_FUN (fdInf->ops, readv, (fdInf->rlfd, iov, iovcnt), size); NSSOC_LOGDBG ("fd=%d,ret=%d [Return]", fd, size); UNLOCK_RECV (fd, local_lock); return size; } /*we assumed that the connect allready called, if not call, we must try many sok*/ ssize_t nstack_sendto (int fd, const void *buf, size_t len, int flags, const struct sockaddr * dest_addr, socklen_t addrlen) { nstack_fd_Inf *fdInf = NULL; int size = -1; struct sockaddr_in *iaddr = NULL; int selectmod = -1; int retval = 0; nstack_rd_key rdkey = { 0 }; NSTACK_INIT_CHECK_RET (sendto, fd, buf, len, flags, dest_addr, addrlen); NSSOC_LOGDBG ("(sockfd=%d, buf=%p, len=%zu, flags=%d, dest_addr=%p, addrlen=%u) [Caller]", fd, buf, len, flags, dest_addr, addrlen); NSTACK_FD_LINUX_CHECK (fd, sendto, fdInf, (fd, buf, len, flags, dest_addr, addrlen)); nstack_fd_local_lock_info_t *local_lock = &fdInf->local_lock; LOCK_SEND (fd, fdInf, local_lock); NSTACK_EPOLL_FD_CHECK_RET_UNLOCK_SEND (fd, sendto, fdInf, ENOTSOCK, local_lock); if (fdInf->ops) { NSTACK_CAL_FUN (fdInf->ops, sendto, (fdInf->rlfd, buf, len, flags, dest_addr, addrlen), size); NSSOC_LOGDBG ("fdInf->ops:fd=%d buf=%p,len=%zu,size=%d,addr=%p [Return]", fd, buf, len, size, dest_addr); UNLOCK_SEND (fd, local_lock); return size; } /*invalid ip, just return */ /*validity check for addrlen: for visite iaddr->sin_addr.s_addr is 8 byte */ if ((NULL == dest_addr) || (addrlen < 8)) { nstack_set_errno (EINVAL); NSSOC_LOGERR ("invalid input]fd=%d,buf=%p,len=%zu,addr=%p [Return]", fd, buf, len, dest_addr); UNLOCK_SEND (fd, local_lock); return -1; } iaddr = (struct sockaddr_in *) dest_addr; rdkey.type = RD_DATA_TYPE_IP; rdkey.ip_addr = iaddr->sin_addr.s_addr; retval = nstack_rd_get_stackid (&rdkey, &selectmod); if ((ns_success == retval) && (selectmod >= 0)) { NSSOC_LOGINF ("fd=%d,addr=%s,select_module=%s", fd, inet_ntoa (iaddr->sin_addr), nstack_get_module_name_by_idx (selectmod)); fdInf->rmidx = selectmod; nstack_set_routed_fd (fdInf, nstack_get_protoFd (fdInf, selectmod)); nstack_set_router_protocol (fdInf, selectmod); fdInf->ops = nstack_module_ops (selectmod); } else { NSSOC_LOGERR ("fd=%d Callback select module=%d,ret=0x%x", fd, selectmod, retval); nstack_set_errno (ENETUNREACH); UNLOCK_SEND (fd, local_lock); return -1; } NSSOC_LOGDBG ("fd=%d,addr=%s,select_module=%s", fd, inet_ntoa (iaddr->sin_addr), nstack_get_module_name_by_idx (selectmod)); NSTACK_CAL_FUN (fdInf->ops, sendto, (fdInf->rlfd, buf, len, flags, dest_addr, addrlen), size); NSSOC_LOGDBG ("fd=%d,module=%s,ret=%d [Return]", fd, nstack_get_module_name_by_idx (fdInf->rmidx), size); UNLOCK_SEND (fd, local_lock); return size; } ssize_t nstack_sendmsg (int fd, const struct msghdr * msg, int flags) { nstack_fd_Inf *fdInf = NULL; int size = -1; struct sockaddr_in *iaddr = NULL; int selectmod = -1; int retval = 0; nstack_rd_key rdkey = { 0 }; NSTACK_INIT_CHECK_RET (sendmsg, fd, msg, flags); NS_LOG_CTRL (LOG_CTRL_SENDMSG, NSOCKET, "NSSOC", NSLOG_DBG, "(sockfd=%d, msg=%p, flags=%d) [Caller]", fd, msg, flags); if (NULL == msg) { nstack_set_errno (EINVAL); NSSOC_LOGERR ("invalid input]fd=%d,msg=%p [Return]", fd, msg); return -1; } NSTACK_FD_LINUX_CHECK (fd, sendmsg, fdInf, (fd, msg, flags)); nstack_fd_local_lock_info_t *local_lock = &fdInf->local_lock; LOCK_SEND (fd, fdInf, local_lock); NSTACK_EPOLL_FD_CHECK_RET_UNLOCK_SEND (fd, sendmsg, fdInf, ENOTSOCK, local_lock); /*if some module select, just connect */ if (fdInf->ops) { NSTACK_CAL_FUN (fdInf->ops, sendmsg, (fdInf->rlfd, msg, flags), size); NSSOC_LOGDBG ("]fd=%d,size=%d msg=%p [Return]", fd, size, msg); UNLOCK_SEND (fd, local_lock); return size; } iaddr = (struct sockaddr_in *) msg->msg_name; /* validity check for msg->msg_namelen,for visite iaddr->sin_addr.s_addr is 8 byte */ if ((NULL == iaddr) || (msg->msg_namelen < 8)) { NSSOC_LOGINF ("fd addr is null and select linux module]fd=%d", fd); fdInf->ops = nstack_module_ops (nstack_get_fix_mid ()); nstack_set_routed_fd (fdInf, nstack_get_protoFd (fdInf, nstack_get_fix_mid ())); nstack_set_router_protocol (fdInf, nstack_get_fix_mid ()); } else { rdkey.type = RD_DATA_TYPE_IP; rdkey.ip_addr = iaddr->sin_addr.s_addr; retval = nstack_rd_get_stackid (&rdkey, &selectmod); if (ns_success == retval) { NSSOC_LOGINF ("fd=%d,addr=%s,select_module=%s", fd, inet_ntoa (iaddr->sin_addr), nstack_get_module_name_by_idx (selectmod)); fdInf->rmidx = selectmod; nstack_set_routed_fd (fdInf, nstack_get_protoFd (fdInf, selectmod)); nstack_set_router_protocol (fdInf, selectmod); fdInf->ops = nstack_module_ops (selectmod); } else { NSSOC_LOGERR ("fd=%d Callback select_module=%d,ret=0x%x", fd, selectmod, retval); nstack_set_errno (ENETUNREACH); UNLOCK_SEND (fd, local_lock); return -1; } NSSOC_LOGDBG ("fd=%d,addr=%s,select_module=%s", fd, inet_ntoa (iaddr->sin_addr), nstack_get_module_name_by_idx (selectmod)); } NSTACK_CAL_FUN (fdInf->ops, sendmsg, (fdInf->rlfd, msg, flags), size); NSSOC_LOGDBG ("fd=%d,module=%s,ret=%d [Return]", fd, nstack_get_module_name_by_idx (fdInf->rmidx), size); UNLOCK_SEND (fd, local_lock); return size; } /*we assumed that the connect allready called, if not call, we must try many sok*/ ssize_t nstack_recvfrom (int fd, void *buf, size_t len, int flags, struct sockaddr * src_addr, socklen_t * addrlen) { nstack_fd_Inf *fdInf = NULL; int size = -1; NSTACK_INIT_CHECK_RET (recvfrom, fd, buf, len, flags, src_addr, addrlen); NSSOC_LOGDBG ("(sockfd=%d, buf=%p, len=%zu, flags=%d, src_addr=%p, addrlen=%p) [Caller]", fd, buf, len, flags, src_addr, addrlen); if (NULL == buf) { nstack_set_errno (EFAULT); NSSOC_LOGERR ("invalid input]fd=%d,buf=%p [Return]", fd, buf); return -1; } NSTACK_FD_LINUX_CHECK (fd, recvfrom, fdInf, (fd, buf, len, flags, src_addr, addrlen)); nstack_fd_local_lock_info_t *local_lock = &fdInf->local_lock; LOCK_RECV (fd, fdInf, local_lock); NSTACK_EPOLL_FD_CHECK_RET_UNLOCK_RECV (fd, recvfrom, fdInf, ENOTSOCK, local_lock); if ((!fdInf->ops) || (-1 == fdInf->rlfd)) { NSSOC_LOGINF ("Not select any module yet!]fd=%d [Return]", fd); nstack_set_errno (ENOTCONN); UNLOCK_RECV (fd, local_lock); return -1; } NSTACK_CAL_FUN (fdInf->ops, recvfrom, (fdInf->rlfd, buf, len, flags, src_addr, addrlen), size); NSSOC_LOGDBG ("fd=%d,retVal=%d [Return]", fd, size); UNLOCK_RECV (fd, local_lock); return size; } ssize_t nstack_recvmsg (int fd, struct msghdr * msg, int flags) { nstack_fd_Inf *fdInf = NULL; int size = -1; NSTACK_INIT_CHECK_RET (recvmsg, fd, msg, flags); NS_LOG_CTRL (LOG_CTRL_RECVMSG, NSOCKET, "NSSOC", NSLOG_DBG, "(sockfd=%d, msg=%p, flags=%d) [Caller]", fd, msg, flags); NSTACK_FD_LINUX_CHECK (fd, recvmsg, fdInf, (fd, msg, flags)); nstack_fd_local_lock_info_t *local_lock = &fdInf->local_lock; LOCK_RECV (fd, fdInf, local_lock); NSTACK_EPOLL_FD_CHECK_RET_UNLOCK_RECV (fd, recvmsg, fdInf, ENOTSOCK, local_lock); if ((-1 == fdInf->rlfd) || (NULL == fdInf->ops)) { NSSOC_LOGERR ("Not select any module yet!]fd=%d [Return]", fd); nstack_set_errno (ENOTCONN); UNLOCK_RECV (fd, local_lock); return -1; } NSTACK_CAL_FUN (fdInf->ops, recvmsg, (fdInf->rlfd, msg, flags), size); NSSOC_LOGDBG ("fd=%d,ret=%d [Return]", fd, size); UNLOCK_RECV (fd, local_lock); return size; } /***************************************************************** Parameters : fd addr len Return : Description : all module fd bind to same addr, so just use first rlfd to get bind addr. *****************************************************************/ int nstack_getsockname (int fd, struct sockaddr *addr, socklen_t * addrlen) { nstack_fd_Inf *fdInf = NULL; int tfd = -1; int ret = -1; NSTACK_INIT_CHECK_RET (getsockname, fd, addr, addrlen); NS_LOG_CTRL (LOG_CTRL_GETSOCKNAME, NSOCKET, "NSSOC", NSLOG_INF, "(fd=%d, addr=%p, addrlen=%p) [Caller]", fd, addr, addrlen); if (fd < 0) { nstack_set_errno (EBADF); NSSOC_LOGERR ("invalid input]fd=%d. [return]", fd); return -1; } NSTACK_FD_LINUX_CHECK (fd, getsockname, fdInf, (fd, addr, addrlen)); nstack_fd_local_lock_info_t *local_lock = &fdInf->local_lock; LOCK_COMMON (fd, fdInf, local_lock); if ((NULL != fdInf->ops) && (fdInf->rlfd != -1)) { tfd = fdInf->rlfd; NSTACK_CAL_FUN (fdInf->ops, getsockname, (tfd, addr, addrlen), ret); NSSOC_LOGINF ("fd=%d,module=%s,tfd=%d [return]", fd, nstack_get_module_name_by_idx (fdInf->rmidx), tfd); if (-1 == ret) { NSSOC_LOGERR ("rmidx=%d,fd=%d return fail [return]", fdInf->rmidx, tfd); } UNLOCK_COMMON (fd, local_lock); return ret; } if (NULL != g_nstack_modules.defMod) { tfd = nstack_get_protoFd (fdInf, nstack_defMod_inx ()); if (tfd >= 0) { nstack_socket_ops *ops = nstack_def_ops (); NSTACK_CAL_FUN (ops, getsockname, (tfd, addr, addrlen), ret); NSSOC_LOGINF ("fd=%d,module=%s,tfd=%d [return]", fd, nstack_defmod_name (), tfd); if (-1 == ret) { NSSOC_LOGERR ("return fail]module=%d,fd=%d [return]", nstack_defMod_inx (), tfd); } UNLOCK_COMMON (fd, local_lock); return ret; } } nstack_set_errno (ENOTSOCK); NSSOC_LOGINF ("fd=%d,ret=%d [Return]", fd, ret); UNLOCK_COMMON (fd, local_lock); return ret; } /***************************************************************** Parameters : fd addr len Return : Description : getpeername only used by the fd who already Establish connection, so use first rlfd. *****************************************************************/ int nstack_getpeername (int fd, struct sockaddr *addr, socklen_t * addrlen) { nstack_fd_Inf *fdInf; int tfd; int ret = -1; NSTACK_INIT_CHECK_RET (getpeername, fd, addr, addrlen); NS_LOG_CTRL (LOG_CTRL_GETPEERNAME, NSOCKET, "NSSOC", NSLOG_INF, "(fd=%d, addr=%p, addrlen=%p) [Caller]", fd, addr, addrlen); if (fd < 0) { nstack_set_errno (EBADF); NSSOC_LOGERR ("invalid input, fd=%d. [return]", fd); return -1; } NSTACK_FD_LINUX_CHECK (fd, getpeername, fdInf, (fd, addr, addrlen)); nstack_fd_local_lock_info_t *local_lock = &fdInf->local_lock; LOCK_COMMON (fd, fdInf, local_lock); /*?????????,????????????? */ if (fdInf->ops) { tfd = fdInf->rlfd; NSTACK_CAL_FUN (fdInf->ops, getpeername, (tfd, addr, addrlen), ret); NSSOC_LOGINF ("fd=%d,module=%s,rlfd=%d,ret=%d [return]", fd, nstack_get_module_name_by_idx (fdInf->rmidx), fdInf->rlfd, ret); if (-1 == ret) { NSSOC_LOGERR ("return fail]module=%d,fd=%d [return]", fdInf->rmidx, tfd); } UNLOCK_COMMON (fd, local_lock); return ret; } if (NULL != g_nstack_modules.defMod) { tfd = nstack_get_protoFd (fdInf, nstack_defMod_inx ()); if (tfd >= 0) { nstack_socket_ops *ops = nstack_def_ops (); NSTACK_CAL_FUN (ops, getpeername, (tfd, addr, addrlen), ret); NSSOC_LOGINF ("fd=%d,module=%s,tfd=%d [return]", fd, nstack_defmod_name (), tfd); if (-1 == ret) { NSSOC_LOGERR ("return fail] module=%d,fd=%d [return]", nstack_defMod_inx (), tfd); } UNLOCK_COMMON (fd, local_lock); return ret; } } nstack_set_errno (ENOTSOCK); NSSOC_LOGINF ("fd=%d,ret=%d [Return]", fd, ret); UNLOCK_COMMON (fd, local_lock); return ret; } int nstack_option_set (nstack_fd_Inf * fdInf, int optname, const void *optval, socklen_t optlen) { #define SLEEP_MAX 10000000 if ((!optval) || (optlen < sizeof (u32_t))) { NSSOC_LOGINF ("rong parmeter optname]=%d", optname); nstack_set_errno (EINVAL); return -1; } switch (optname) { case NSTACK_SEM_SLEEP: if ((*(u32_t *) optval) > SLEEP_MAX) { NSSOC_LOGWAR ("time overflow]epfd=%d", fdInf->fd); nstack_set_errno (EINVAL); return -1; } nsep_set_infoSleepTime (fdInf->fd, *(u32_t *) optval); NSSOC_LOGINF ("set sem wait option] g_sem_sleep_time=%ld", *(u32_t *) optval); break; default: NSSOC_LOGINF ("rong parmeter optname]=%d", optname); nstack_set_errno (ENOPROTOOPT); return -1; } return 0; } int nstack_option_get (nstack_fd_Inf * fdInf, int optname, const void *optval, socklen_t * optlen) { if ((!optval) || (!optlen) || (optlen && (*optlen < sizeof (u32_t)))) { NSSOC_LOGINF ("rong parmeter optname]=%d", optname); nstack_set_errno (EINVAL); return -1; } switch (optname) { case NSTACK_SEM_SLEEP: *(long *) optval = nsep_get_infoSleepTime (fdInf->fd); NSSOC_LOGINF ("get sem wait option] g_sem_sleep_time=%ld", *(long *) optval); break; default: NSSOC_LOGINF ("rong parmeter optname]=%d", optname); nstack_set_errno (ENOPROTOOPT); return -1; } return 0; } /* just use first rlfd to getsockopt, this may not what app really want.*/ /* Currently, if getsockopt is successfull either in kernel or stack-x, the below API returns SUCCESS */ int nstack_getsockopt (int fd, int level, int optname, void *optval, socklen_t * optlen) { nstack_fd_Inf *fdInf; int tfd; int ret = -1; nstack_socket_ops *ops; NSTACK_INIT_CHECK_RET (getsockopt, fd, level, optname, optval, optlen); NS_LOG_CTRL (LOG_CTRL_GETSOCKOPT, NSOCKET, "NSSOC", NSLOG_INF, "(fd=%d, level=%d, optname=%d, optval=%p, optlen=%p) [Caller]", fd, level, optname, optval, optlen); if (fd < 0) { nstack_set_errno (EBADF); NSSOC_LOGERR ("invalid input]fd=%d [return]", fd); return -1; } NSTACK_FD_LINUX_CHECK (fd, getsockopt, fdInf, (fd, level, optname, optval, optlen)); nstack_fd_local_lock_info_t *local_lock = &fdInf->local_lock; LOCK_COMMON (fd, fdInf, local_lock); if ((NSTACK_SOCKOPT == level) && NSTACK_IS_FD_EPOLL_SOCKET (fdInf)) { ret = nstack_option_get (fdInf, optname, optval, optlen); UNLOCK_COMMON (fd, local_lock); return ret; } if (fdInf->ops) { tfd = fdInf->rlfd; NSTACK_CAL_FUN (fdInf->ops, getsockopt, (tfd, level, optname, optval, optlen), ret); NSSOC_LOGINF ("fd=%d,module=%s,tfd=%d,level=%d,optname=%d,ret=%d [return]", fd, nstack_get_module_name_by_idx (fdInf->rmidx), tfd, level, optname, ret); if (-1 == ret) { NSSOC_LOGERR ("return fail]module=%d,fd=%d [return]", fdInf->rmidx, tfd); } UNLOCK_COMMON (fd, local_lock); return ret; } if (NULL != g_nstack_modules.defMod) { tfd = nstack_get_protoFd (fdInf, nstack_defMod_inx ()); if (tfd >= 0) { ops = nstack_def_ops (); NSTACK_CAL_FUN (ops, getsockopt, (tfd, level, optname, optval, optlen), ret); NSSOC_LOGINF ("fd=%d,module=%s:%d,level=%d,optname=%d,ret=%d [return]", fd, nstack_defmod_name (), tfd, level, optname, ret); if (-1 == ret) { NSSOC_LOGERR ("return fail]module=%d,fd=%d [return]", nstack_defMod_inx (), tfd); } UNLOCK_COMMON (fd, local_lock); return ret; } } nstack_set_errno (ENOTSOCK); NSSOC_LOGINF ("fd=%d,ret=%d [Return]", fd, ret); UNLOCK_COMMON (fd, local_lock); return ret; } /* all rlfd need setsockopt, set opt failed still can Establish connection. so we not care suc/fail */ /* Currently, if setsockopt is successfull either in kernel or stack-x, the below API returns SUCCESS */ int nstack_setsockopt (int fd, int level, int optname, const void *optval, socklen_t optlen) { nstack_fd_Inf *fdInf; int ret = -1; nstack_socket_ops *ops; int itfd; int modInx = 0; int curRet = -1; int lerror = 0; int flag = 0; NSTACK_INIT_CHECK_RET (setsockopt, fd, level, optname, optval, optlen); NSSOC_LOGINF ("(fd=%d, level=%d, optname=%d, optval=%p, optlen=%u) [Caller]", fd, level, optname, optval, optlen); if (fd < 0) { nstack_set_errno (EBADF); NSSOC_LOGERR ("invalid input]fd=%d [return]", fd); return -1; } NSTACK_FD_LINUX_CHECK (fd, setsockopt, fdInf, (fd, level, optname, optval, optlen)); nstack_fd_local_lock_info_t *local_lock = &fdInf->local_lock; LOCK_COMMON (fd, fdInf, local_lock); if ((NSTACK_SOCKOPT == level) && NSTACK_IS_FD_EPOLL_SOCKET (fdInf)) { ret = nstack_option_set (fdInf, optname, optval, optlen); UNLOCK_COMMON (fd, local_lock); return ret; } if (fdInf->ops) { itfd = fdInf->rlfd; NSTACK_CAL_FUN (fdInf->ops, setsockopt, (itfd, level, optname, optval, optlen), ret); NSSOC_LOGINF ("fd=%d,module=%s,tfd=%d,level=%d,optname=%d,ret=%d [return]", fd, nstack_get_module_name_by_idx (fdInf->rmidx), itfd, level, optname, ret); if (-1 == ret) { NSSOC_LOGERR ("return fail]module=%d,fd=%d [return]", fdInf->rmidx, itfd); } UNLOCK_COMMON (fd, local_lock); return ret; } nstack_each_modOps (modInx, ops) { itfd = nstack_get_protoFd (fdInf, modInx); if (-1 == itfd) { continue; } flag = 1; NSTACK_CAL_FUN (ops, setsockopt, (itfd, level, optname, optval, optlen), curRet); NSSOC_LOGDBG ("fd=%d,module=%s,tfd=%d,level=%d,optname=%d,ret=%d", fd, nstack_get_module_name_by_idx (modInx), itfd, level, optname, curRet); if (modInx == nstack_get_fix_mid ()) { ret = curRet; /* errno is thread safe, but stack-x is not, so save it first */ lerror = errno; } } /* errno is thread safe, but stack-x is not, so save it first begin */ /*if all fd of stack is -1, the input fd maybe invalid */ if (0 == flag) { nstack_set_errno (EBADF); } /*if linux return fail, and error is none zero, just reset it again */ if ((lerror != 0) && (ns_success != ret)) { nstack_set_errno (lerror); } /* errno is thread safe, but stack-x is not, so save it first end */ NSSOC_LOGINF ("fd=%d,ret=%d [Return]", fd, ret); UNLOCK_COMMON (fd, local_lock); return ret; } int nstack_ioctl (int fd, unsigned long request, unsigned long argp) { nstack_fd_Inf *fdInf; int ret = -1; nstack_socket_ops *ops; int tfd; int modInx = 0; int curRet = -1; int lerror = 0; int flag = 0; NSTACK_INIT_CHECK_RET (ioctl, fd, request, argp); NSSOC_LOGINF ("(fd=%d, request=%lu) [Caller]", fd, request); if (fd < 0) { nstack_set_errno (EBADF); NSSOC_LOGERR ("invalid input]fd=%d [return]", fd); return -1; } NSTACK_FD_LINUX_CHECK (fd, ioctl, fdInf, (fd, request, argp)); nstack_fd_local_lock_info_t *local_lock = &fdInf->local_lock; LOCK_COMMON (fd, fdInf, local_lock); if (fdInf->ops) { tfd = fdInf->rlfd; NSTACK_CAL_FUN (fdInf->ops, ioctl, (tfd, request, argp), ret); NSSOC_LOGINF ("fd=%d,module=%s,rlfd=%d,argp=0x%x,ret=%d [return]", fd, nstack_get_module_name_by_idx (fdInf->rmidx), fdInf->rlfd, argp, ret); if (-1 == ret) { NSSOC_LOGERR ("return fail]module=%d,fd=%d [return]", fdInf->rmidx, tfd); } UNLOCK_COMMON (fd, local_lock); return ret; } nstack_each_modOps (modInx, ops) { tfd = nstack_get_protoFd (fdInf, modInx); if (-1 == tfd) { continue; } flag = 1; NSTACK_CAL_FUN (ops, ioctl, (tfd, request, argp), curRet); NSSOC_LOGINF ("fd=%d,module=%s,tfd=%d,argp=0x%x,ret=%d ", fd, nstack_get_module_name_by_idx (modInx), tfd, argp, curRet); if (modInx == nstack_get_fix_mid ()) { ret = curRet; /* errno is thread safe, but stack-x is not, so save it first */ lerror = errno; } } /* errno is thread safe, but stack-x is not, so save it first */ if (0 == flag) { nstack_set_errno (EBADF); } if ((0 != lerror) && (ns_success != ret)) { nstack_set_errno (lerror); } NSSOC_LOGINF ("fd=%d,ret=%d [return]", fd, ret); UNLOCK_COMMON (fd, local_lock); return ret; } int nstack_fcntl (int fd, int cmd, unsigned long argp) { nstack_fd_Inf *fdInf; nstack_socket_ops *ops = NULL; int ret = -1; int noProOpt = 0; int tfd; int modInx = 0; int curRet = -1; int lerror = 0; int flag = 0; NSTACK_INIT_CHECK_RET (fcntl, fd, cmd, argp); NSSOC_LOGINF ("(fd=%d, cmd=%d) [Caller]", fd, cmd); if (fd < 0) { nstack_set_errno (EBADF); NSSOC_LOGERR ("invalid input]fd=%d [return]", fd); return -1; } NSTACK_FD_LINUX_CHECK (fd, fcntl, fdInf, (fd, cmd, argp)); nstack_fd_local_lock_info_t *local_lock = &fdInf->local_lock; LOCK_COMMON (fd, fdInf, local_lock); /*have already bind */ if (fdInf->ops) { tfd = fdInf->rlfd; NSTACK_CAL_FUN (fdInf->ops, fcntl, (tfd, cmd, argp), ret); NSSOC_LOGINF ("fd=%d,cmd=%d,mod=%s,tfd=%d,argp=0x%x,ret=%d", fd, cmd, nstack_get_module_name_by_idx (fdInf->rmidx), tfd, argp, ret); if (-1 == ret) { NSSOC_LOGERR ("return fail]module=%d,fd=%d", fdInf->rmidx, tfd); } } else { /*set cmd call all module, and return just linux */ if (F_SETFL == cmd) { nstack_each_modOps (modInx, ops) { tfd = nstack_get_protoFd (fdInf, modInx); if (-1 == tfd) { continue; } flag = 1; noProOpt = 0; NSTACK_CAL_FUN (ops, fcntl, (tfd, cmd, argp), curRet); NSSOC_LOGINF ("fd=%d,module=%s,tfd=%d,argp=0x%x,ret=%d ", fd, nstack_get_module_name_by_idx (modInx), tfd, argp, curRet); if (modInx == nstack_get_fix_mid ()) { ret = curRet; lerror = errno; } } /* errno is thread safe, but stack-x is not, so save it first */ if (0 == flag) { nstack_set_errno (EBADF); } if ((0 != lerror) && (ns_success != ret)) { nstack_set_errno (lerror); } } /*other cmd call default */ else if (g_nstack_modules.defMod) { tfd = nstack_get_protoFd (fdInf, g_nstack_modules.defMod->modInx); if (tfd >= 0) { ops = nstack_def_ops (); NSTACK_CAL_FUN (ops, fcntl, (tfd, cmd, argp), ret); NSSOC_LOGINF ("fd=%d,cmd=%d,mod=%s,tfd=%d,argp=0x%x,ret=%d", fd, cmd, g_nstack_modules.defMod->modulename, tfd, argp, ret); if (-1 == ret) { NSSOC_LOGERR ("return fail]module=%d,fd=%d", g_nstack_modules.defMod->modInx, tfd); } } else { noProOpt = 1; } } else { noProOpt = 1; } } if (noProOpt) { nstack_set_errno (EBADF); NSSOC_LOGINF ("fd=%d,ret=%d", fd, ret); } NSSOC_LOGINF ("fd=%d,cmd=%d,ret=%d [return]", fd, cmd, ret); UNLOCK_COMMON (fd, local_lock); return ret; } /***************************************************************************** * Prototype : nstack_select * Description : nstack_select * Input : int nfds * fd_set *readfds * fd_set *writefds * fd_set *exceptfds * struct timeval *timeout * Output : None * Return Value : int * Calls : * Called By : *****************************************************************************/ int nstack_select (int nfds, fd_set * readfds, fd_set * writefds, fd_set * exceptfds, struct timeval *timeout) { int ret = -1; struct select_entry *entry = NULL; struct select_module_info *select_module = get_select_module (); u64_t msec; int i; NSTACK_INIT_CHECK_RET (select, nfds, readfds, writefds, exceptfds, timeout); if ((nfds > __FD_SETSIZE) || (nfds < 0) || ((timeout) && ((timeout->tv_sec < 0) || (timeout->tv_usec < 0)))) { NSSOC_LOGERR ("paremeter of nfds or timeout are no correct.]nfds = %d \ sec = %ld usec = %ld", nfds, timeout->tv_sec, timeout->tv_usec); errno = EINVAL; return -1; } for (i = 0; i < nfds; i++) { if ((readfds) && (FD_ISSET (i, readfds))) { NSSOC_LOGDBG ("input readfd set %d", i); } if ((writefds) && (FD_ISSET (i, writefds))) { NSSOC_LOGDBG ("input writefd set %d", i); } if ((exceptfds) && (FD_ISSET (i, exceptfds))) { NSSOC_LOGDBG ("input exceptfds set %d", i); } } /*check the module had regist or not */ if (TRUE != NSTACK_SELECT_LINUX_CHECK ()) { return nsfw_base_select (nfds, readfds, writefds, exceptfds, timeout); } /*nstack select not support timer function and not check nfds so calling default select */ if ((nfds <= 0) || ((NULL == readfds) && (NULL == writefds) && (NULL == exceptfds))) { if ((select_module) && (select_module->default_fun)) { return select_module->default_fun (nfds, readfds, writefds, exceptfds, timeout); } else { return nsfw_base_select (nfds, readfds, writefds, exceptfds, timeout); } } entry = (struct select_entry *) select_alloc (sizeof (struct select_entry)); if (NULL == entry) { errno = ENOMEM; NSSOC_LOGERR ("select entry alloc failed"); goto err_return; } /* fix dead-code type Codex issue */ /*split select fd to each modules fd and save to entry */ (void) select_cb_split_by_mod (nfds, readfds, writefds, exceptfds, entry); /*if all fd in default module we just calling it */ if (entry->info.set_num <= 1) { /*adapte linux */ if ((select_module) && (entry->info.index == select_module->default_mod)) { if (select_module->default_fun) { ret = select_module->default_fun (nfds, readfds, writefds, exceptfds, timeout); } else { ret = nsfw_base_select (nfds, readfds, writefds, exceptfds, timeout); } goto err_return; } } /*checking if event ready or not */ if (FALSE == select_scan (entry)) { NSSOC_LOGERR ("select scan failed"); goto err_return; } if (entry->ready.readyset != 0) { goto scan_return; } if ((timeout) && (timeout->tv_sec == 0) && (timeout->tv_usec == 0)) { goto scan_return; } if (FALSE == select_add_cb (entry)) { errno = ENOMEM; NSSOC_LOGERR ("select entry add failed"); goto err_return; } if (NULL == timeout) { select_sem_wait (&entry->sem); } else { u64_t time_cost; if (nstack_timeval2msec (timeout, &msec)) { nstack_set_errno (EINVAL); goto err_return; } time_cost = nstack_sem_timedwait (&entry->sem, msec); if (time_cost >= msec) { timeout->tv_sec = 0; timeout->tv_usec = 0; } else if (time_cost > 0) { msec = msec - time_cost; timeout->tv_sec = msec / 1000; timeout->tv_usec = (msec % 1000) * 1000; } } select_rm_cb (entry); scan_return: if (readfds) { *readfds = entry->ready.readset; } if (writefds) { *writefds = entry->ready.writeset; } if (exceptfds) { *exceptfds = entry->ready.exceptset; } ret = entry->ready.readyset; if (ret < 0) { errno = entry->ready.select_errno; } err_return: if (entry) { select_free ((char *) entry); } NSSOC_LOGDBG ("(nfds=%d,readfds=%p,writefds=%p,exceptfds=%p,timeout=%p),ret=%d errno = %d", nfds, readfds, writefds, exceptfds, timeout, ret, errno); return ret; } /* epfd?fd maybe is from kernel or stack-x,should take care */ int nstack_epoll_ctl (int epfd, int op, int fd, struct epoll_event *event) { int ret = ns_fail; struct eventpoll *ep = NULL; nstack_fd_Inf *epInf; struct epoll_event ep_event = { 0 }; struct epitem *epi = NULL; NSTACK_INIT_CHECK_RET (epoll_ctl, epfd, op, fd, event); NSSOC_LOGINF ("(epfd=%d, op=%d, fd=%d, event=%p) [Caller]", epfd, op, fd, event); if (event) NSSOC_LOGINF ("event->data.fd=%d,event->events=%u", event->data.fd, event->events); NSTACK_FD_LINUX_CHECK (epfd, epoll_ctl, epInf, (epfd, op, fd, event)); nstack_fd_local_lock_info_t *epoll_local_lock = &epInf->local_lock; LOCK_EPOLL (epfd, epInf, epoll_local_lock); nstack_fd_local_lock_info_t *local_lock = get_fd_local_lock_info (fd); LOCK_EPOLL_CTRL (fd, local_lock, epfd, epoll_local_lock); if (!NSTACK_IS_FD_EPOLL_SOCKET (epInf) || fd == epfd) /* `man epoll_ctl` tells me to do this check :) */ { NSSOC_LOGWAR ("epfd=%d is not a epoll fd [return]", epfd); errno = EINVAL; goto err_return; } if (!nstack_is_nstack_sk (fd)) { NSSOC_LOGWAR ("epfd=%d ,fd %d is not a supported [return]", epfd, fd); errno = EBADF; goto err_return; } nsep_epollInfo_t *epInfo = nsep_get_infoBySock (epfd); if (NULL == epInfo) { NSSOC_LOGWAR ("epInfo of epfd=%d is NULL [return]", epfd); errno = EINVAL; goto err_return; } ep = ADDR_SHTOL (epInfo->ep); if (NULL == ep) { NSSOC_LOGWAR ("ep of epfd=%d is NULL [return]", epfd); errno = EINVAL; goto err_return; } if (NULL != event) { ep_event.data = event->data; ep_event.events = event->events; } else { if (op != EPOLL_CTL_DEL) { NSSOC_LOGWAR ("events epfd=%d is NULL [return]", epfd); errno = EFAULT; goto err_return; } } sys_arch_lock_with_pid (&ep->sem); epi = nsep_find_ep (ep, fd); switch (op) { case EPOLL_CTL_ADD: if (!epi) { ep_event.events |= (EPOLLERR | EPOLLHUP); // Check `man epoll_ctl` if you don't understand , smile :) common_mem_rwlock_read_lock (get_fork_lock ()); /* to ensure that there is no fd to create and close when fork. added by tongshaojun t00391048 */ ret = nsep_epctl_add (ep, fd, &ep_event); common_mem_rwlock_read_unlock (get_fork_lock ()); } else { NSSOC_LOGWAR ("fd already in eventpoll"); errno = EEXIST; ret = -1; } break; case EPOLL_CTL_DEL: if (epi) { common_mem_rwlock_read_lock (get_fork_lock ()); ret = nsep_epctl_del (ep, epi); common_mem_rwlock_read_unlock (get_fork_lock ()); } else { NSSOC_LOGWAR ("fd not registered before"); errno = ENOENT; ret = -1; } break; case EPOLL_CTL_MOD: if (epi) { ep_event.events |= (EPOLLERR | EPOLLHUP); // Look up ? ret = nsep_epctl_mod (ep, nsep_get_infoBySock (fd), epi, &ep_event); } else { NSSOC_LOGWAR ("fd not registered before"); errno = ENOENT; ret = -1; } break; default: NSSOC_LOGERR ("epfd=%d,fd=%d,opt=%d not supported", epfd, fd, op); errno = EINVAL; ret = -1; } sys_sem_s_signal (&ep->sem); NSSOC_LOGINF ("epfd=%d,op=%d,fd=%d,ret=%d [return]", epfd, op, fd, ret); err_return: UNLOCK_EPOLL_CTRL (fd, local_lock); UNLOCK_EPOLL (epfd, epoll_local_lock); return ret; } int nstack_epoll_create (int size) { nstack_fd_Inf *fdInf = NULL; struct eventpoll *ep = NULL; int epfd = -1; int modInx = 0; int tfd = 0; nstack_socket_ops *ops; int ret = 0; NSTACK_INIT_CHECK_RET (epoll_create, size); NSSOC_LOGINF ("(size=%d) [Caller]", size); if (size <= 0) { nstack_set_errno (EINVAL); NSSOC_LOGERR ("invalid input,param]size=%d [return]", size); return -1; } /*create a epfd */ if (nstack_fix_mid_ops ()->pfepoll_create) { epfd = nstack_fix_mid_ops ()->pfepoll_create (size); } else { /*if not surport epfd create, just alloc a fd */ if (nstack_extern_deal (nstack_get_fix_mid ()).stack_alloc_fd) { epfd = nstack_extern_deal (nstack_get_fix_mid ()).stack_alloc_fd (); } else { nstack_set_errno (ENOSYS); NSSOC_LOGERR ("not surport epoll create]size=%d [return]", size); return -1; } } if (!nstack_is_nstack_sk (epfd)) { if (epfd >= 0) { NSTACK_CAL_FUN (nstack_fix_mid_ops (), close, (epfd), ret); } NSSOC_LOGERR ("kernel fd alloced is too larger]kernel_fd=%d [return]", epfd); nstack_set_errno (EMFILE); return -1; } nstack_fd_local_lock_info_t *lock_info = get_fd_local_lock_info (epfd); LOCK_FOR_EP (lock_info); fdInf = nstack_lk_fd_alloc_with_kernel (epfd); if (NULL == fdInf) { NSSOC_LOGERR ("create fdInf fail [return]"); nstack_set_errno (ENOMEM); NSTACK_CAL_FUN (nstack_fix_mid_ops (), close, (epfd), ret); UNLOCK_FOR_EP (lock_info); return -1; } if (nsep_alloc_eventpoll (&ep)) { nsep_free_infoWithSock (epfd); NSSOC_LOGERR ("Alloc eventpoll fail [return]"); nstack_fd_free_with_kernel (fdInf); nstack_set_errno (ENOMEM); UNLOCK_FOR_EP (lock_info); return -1; } ep->epfd = epfd; nsep_set_infoEp (epfd, ep); NSTACK_SET_FD_EPOLL_SOCKET (fdInf); /*if stack supply ep_create interface, just call create */ nstack_each_modOps (modInx, ops) { if (modInx == nstack_get_fix_mid ()) { nstack_set_protoFd (fdInf, modInx, epfd); continue; } if (ops->pfepoll_create) { tfd = ops->pfepoll_create (size); nstack_set_protoFd (fdInf, modInx, tfd); } } NSSOC_LOGINF ("fd=%d [return]", epfd); set_fd_status_lock_fork (epfd, FD_OPEN); UNLOCK_FOR_EP (lock_info); return epfd; } void nstack_epoll_prewait_proc (int epfd, int *eventflag, int num) { int modInx = 0; nsep_epollInfo_t *epInfo = NULL; epInfo = nsep_get_infoBySock (epfd); if (!epInfo) { return; } nstack_each_modInx (modInx) { if (nstack_extern_deal (modInx).ep_prewait_proc) { if (epInfo->protoFD[modInx] < 0) { continue; } /*if already report event, maybe next time to do this proc */ if ((eventflag) && (modInx < num) && (eventflag[modInx] != 0)) { continue; } nstack_extern_deal (modInx).ep_prewait_proc (epInfo->protoFD[modInx]); } } return; } int nstack_epoll_wait (int epfd, struct epoll_event *events, int maxevents, int timeout) { nstack_fd_Inf *fdInf = NULL; nsep_epollInfo_t *epInfo = NULL; struct eventpoll *ep = NULL; int eventflag[NSEP_SMOD_MAX]; int evt = 0; int ret = 0; NSTACK_INIT_CHECK_RET (epoll_wait, epfd, events, maxevents, timeout); NSTACK_FD_LINUX_CHECK (epfd, epoll_wait, fdInf, (epfd, events, maxevents, timeout)); nstack_fd_local_lock_info_t *local_lock = &fdInf->local_lock; LOCK_EPOLL (epfd, fdInf, local_lock); if (!NSTACK_IS_FD_EPOLL_SOCKET (fdInf)) { NSSOC_LOGWAR ("epfd=%d is not a epoll fd, return -1", epfd); errno = EINVAL; UNLOCK_EPOLL (epfd, local_lock); return -1; } /* check input paramter's validity */ if (NULL == events) { NSSOC_LOGWAR ("events is NULL, return -1 "); errno = EINVAL; UNLOCK_EPOLL (epfd, local_lock); return -1; } epInfo = nsep_get_infoBySock (epfd); if (NULL == epInfo) { NSSOC_LOGWAR ("epInfo is NULL]epinfo=%p,epfd=%d", epInfo, epfd); errno = EINVAL; UNLOCK_EPOLL (epfd, local_lock); return -1; } ep = ADDR_SHTOL (epInfo->ep); if (NULL == ep) { NSSOC_LOGWAR ("fdInf->ep is NULL, return -1,epinfo=%p,epfd=%d", epInfo, epfd); errno = EINVAL; UNLOCK_EPOLL (epfd, local_lock); return -1; } if (maxevents <= 0) { NSSOC_LOGWAR ("maxevent less than zero maxevents=%d, return -1 ", maxevents); errno = EINVAL; UNLOCK_EPOLL (epfd, local_lock); return -1; } /** * For linux epoll * Case 1: event is already there, means ks_ep_thread already reported, and epfd not in epoll. * Case 2: event is not there, so we need to add epfd to ks_ep_thread * Update : only try to add epfd to ks_ep_thread once, avoid ks_ep_thread reporting the same event again after app has got the event! */ MEMSET_S (&eventflag[0], sizeof (eventflag), 0, sizeof (eventflag)); evt = nsep_ep_poll (ep, events, maxevents, &eventflag[0], NSEP_SMOD_MAX); if (evt) { NSSOC_LOGDBG ("Got event]epfd=%d,maxevents=%d,ret=%d", epfd, maxevents, evt); nstack_epoll_prewait_proc (epfd, &eventflag[0], NSEP_SMOD_MAX); goto out; } nstack_epoll_prewait_proc (epfd, NULL, 0); do { if (0 == timeout) { goto out; } else if (timeout < 0) { ret = sem_wait (&ep->waitSem); /* when sem_wait return -1, epoll_wait should also return sem_wait's return value and errno */ if (ret < 0) { /* Change sem_wait EINTR log to WAR level */ if (errno == EINTR) { NSSOC_LOGWAR ("sem_wait return -1]errno=%d", errno); } else { NSSOC_LOGERR ("sem_wait return -1]errno=%d", errno); } evt = ret; goto out; } } else { ret = nstack_epoll_sem_timedwait (&ep->waitSem, (u64_t) timeout, epInfo->sleepTime); } if (ret) { goto out; } evt = nsep_ep_poll (ep, events, maxevents, NULL, 0); if (evt) { NSSOC_LOGDBG ("Got event]epfd=%d,maxevents=%d,ret=%d", epfd, maxevents, evt); goto out; } } while (1); out: UNLOCK_EPOLL (epfd, local_lock); return evt; } pid_t nstack_fork (void) { pid_t pid; pid_t parent_pid = sys_get_hostpid_from_file (getpid ()); NSTACK_INIT_CHECK_RET (fork); common_mem_rwlock_write_lock (get_fork_lock ()); if (NSTACK_MODULE_SUCCESS == g_nStackInfo.fwInited) { nstack_fork_init_parent (parent_pid); dmm_spinlock_lock_with_pid (nstack_get_fork_share_lock (), parent_pid); pid = nsfw_base_fork (); if (pid == 0) { /* when fork, the child process need relese the lock in glog */ nstack_log_lock_release (); nstack_fork_init_child (parent_pid); (void) nstack_for_epoll_init (); dmm_spinlock_lock_with_pid (nstack_get_fork_share_lock (), get_sys_pid ()); nsep_fork_child_proc (parent_pid); (void) select_module_init_child (); common_mem_spinlock_unlock (nstack_get_fork_share_lock ()); } else if (pid > 0) { pid_t child_pid = get_hostpid_from_file (pid); nsep_fork_parent_proc (parent_pid, child_pid); common_mem_spinlock_unlock (nstack_get_fork_share_lock ()); sys_sleep_ns (0, 10000000); /* wait child add pid for netconn */ } else { NSSOC_LOGERR ("fork failed]parent_pid=%d", parent_pid); common_mem_spinlock_unlock (nstack_get_fork_share_lock ()); } } else { pid = nsfw_base_fork (); if (pid == 0) { update_sys_pid (); } NSSOC_LOGERR ("g_nStackInfo has not initialized]parent_pid=%d, pid=%d", parent_pid, pid); } common_mem_rwlock_write_unlock (get_fork_lock ()); return pid; }