📄 sockets.c
字号:
/* Timeout */ if (readset) FD_ZERO(readset); if (writeset) FD_ZERO(writeset); if (exceptset) FD_ZERO(exceptset); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n")); set_errno(0); return 0; } if (readset) lreadset = *readset; else FD_ZERO(&lreadset); if (writeset) lwriteset = *writeset; else FD_ZERO(&lwriteset); if (exceptset) lexceptset = *exceptset; else FD_ZERO(&lexceptset); /* See what's set */ nready = lwip_selscan(maxfdp1, &lreadset, &lwriteset, &lexceptset); } else sys_sem_signal(selectsem); if (readset) *readset = lreadset; if (writeset) *writeset = lwriteset; if (exceptset) *exceptset = lexceptset; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready)); set_errno(0); return nready;}/** * Callback registered in the netconn layer for each socket-netconn. * Processes recvevent (data available) and wakes up tasks waiting for select. */static voidevent_callback(struct netconn *conn, enum netconn_evt evt, u16_t len){ int s; struct lwip_socket *sock; struct lwip_select_cb *scb; LWIP_UNUSED_ARG(len); /* Get socket */ if (conn) { s = conn->socket; if (s < 0) { /* Data comes in right away after an accept, even though * the server task might not have created a new socket yet. * Just count down (or up) if that's the case and we * will use the data later. Note that only receive events * can happen before the new socket is set up. */ sys_sem_wait(socksem); if (conn->socket < 0) { if (evt == NETCONN_EVT_RCVPLUS) { conn->socket--; } sys_sem_signal(socksem); return; } s = conn->socket; sys_sem_signal(socksem); } sock = get_socket(s); if (!sock) { return; } } else { return; } sys_sem_wait(selectsem); /* Set event as required */ switch (evt) { case NETCONN_EVT_RCVPLUS: sock->rcvevent++; break; case NETCONN_EVT_RCVMINUS: sock->rcvevent--; break; case NETCONN_EVT_SENDPLUS: sock->sendevent = 1; break; case NETCONN_EVT_SENDMINUS: sock->sendevent = 0; break; default: LWIP_ASSERT("unknown event", 0); break; } sys_sem_signal(selectsem); /* Now decide if anyone is waiting for this socket */ /* NOTE: This code is written this way to protect the select link list but to avoid a deadlock situation by releasing socksem before signalling for the select. This means we need to go through the list multiple times ONLY IF a select was actually waiting. We go through the list the number of waiting select calls + 1. This list is expected to be small. */ while (1) { sys_sem_wait(selectsem); for (scb = select_cb_list; scb; scb = scb->next) { if (scb->sem_signalled == 0) { /* Test this select call for our socket */ if (scb->readset && FD_ISSET(s, scb->readset)) if (sock->rcvevent > 0) break; if (scb->writeset && FD_ISSET(s, scb->writeset)) if (sock->sendevent) break; } } if (scb) { scb->sem_signalled = 1; sys_sem_signal(scb->sem); sys_sem_signal(selectsem); } else { sys_sem_signal(selectsem); break; } }}/** * Unimplemented: Close one end of a full-duplex connection. * Currently, the full connection is closed. */intlwip_shutdown(int s, int how){ LWIP_UNUSED_ARG(how); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how)); return lwip_close(s); /* XXX temporary hack until proper implementation */}static intlwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local){ struct lwip_socket *sock; struct sockaddr_in sin; struct ip_addr naddr; sock = get_socket(s); if (!sock) return -1; memset(&sin, 0, sizeof(sin)); sin.sin_len = sizeof(sin); sin.sin_family = AF_INET; /* get the IP address and port */ netconn_getaddr(sock->conn, &naddr, &sin.sin_port, local); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s)); ip_addr_debug_print(SOCKETS_DEBUG, &naddr); LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", sin.sin_port)); sin.sin_port = htons(sin.sin_port); sin.sin_addr.s_addr = naddr.addr; if (*namelen > sizeof(sin)) *namelen = sizeof(sin); MEMCPY(name, &sin, *namelen); sock_set_errno(sock, 0); return 0;}intlwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen){ return lwip_getaddrname(s, name, namelen, 0);}intlwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen){ return lwip_getaddrname(s, name, namelen, 1);}intlwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen){ err_t err = ERR_OK; struct lwip_socket *sock = get_socket(s); struct lwip_setgetsockopt_data data; if (!sock) return -1; if ((NULL == optval) || (NULL == optlen)) { sock_set_errno(sock, EFAULT); return -1; } /* Do length and type checks for the various options first, to keep it readable. */ switch (level) { /* Level: SOL_SOCKET */ case SOL_SOCKET: switch (optname) { case SO_ACCEPTCONN: case SO_BROADCAST: /* UNIMPL case SO_DEBUG: */ /* UNIMPL case SO_DONTROUTE: */ case SO_ERROR: case SO_KEEPALIVE: /* UNIMPL case SO_CONTIMEO: */ /* UNIMPL case SO_SNDTIMEO: */#if LWIP_SO_RCVTIMEO case SO_RCVTIMEO:#endif /* LWIP_SO_RCVTIMEO */#if LWIP_SO_RCVBUF case SO_RCVBUF:#endif /* LWIP_SO_RCVBUF */ /* UNIMPL case SO_OOBINLINE: */ /* UNIMPL case SO_SNDBUF: */ /* UNIMPL case SO_RCVLOWAT: */ /* UNIMPL case SO_SNDLOWAT: */#if SO_REUSE case SO_REUSEADDR: case SO_REUSEPORT:#endif /* SO_REUSE */ case SO_TYPE: /* UNIMPL case SO_USELOOPBACK: */ if (*optlen < sizeof(int)) { err = EINVAL; } break; case SO_NO_CHECK: if (*optlen < sizeof(int)) { err = EINVAL; }#if LWIP_UDP if ((sock->conn->type != NETCONN_UDP) || ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) { /* this flag is only available for UDP, not for UDP lite */ err = EAFNOSUPPORT; }#endif /* LWIP_UDP */ break; default: LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", s, optname)); err = ENOPROTOOPT; } /* switch (optname) */ break; /* Level: IPPROTO_IP */ case IPPROTO_IP: switch (optname) { /* UNIMPL case IP_HDRINCL: */ /* UNIMPL case IP_RCVDSTADDR: */ /* UNIMPL case IP_RCVIF: */ case IP_TTL: case IP_TOS: if (*optlen < sizeof(int)) { err = EINVAL; } break;#if LWIP_IGMP case IP_MULTICAST_TTL: if (*optlen < sizeof(u8_t)) { err = EINVAL; } break; case IP_MULTICAST_IF: if (*optlen < sizeof(struct in_addr)) { err = EINVAL; } break;#endif /* LWIP_IGMP */ default: LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", s, optname)); err = ENOPROTOOPT; } /* switch (optname) */ break; #if LWIP_TCP/* Level: IPPROTO_TCP */ case IPPROTO_TCP: if (*optlen < sizeof(int)) { err = EINVAL; break; } /* If this is no TCP socket, ignore any options. */ if (sock->conn->type != NETCONN_TCP) return 0; switch (optname) { case TCP_NODELAY: case TCP_KEEPALIVE:#if LWIP_TCP_KEEPALIVE case TCP_KEEPIDLE: case TCP_KEEPINTVL: case TCP_KEEPCNT:#endif /* LWIP_TCP_KEEPALIVE */ break; default: LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", s, optname)); err = ENOPROTOOPT; } /* switch (optname) */ break;#endif /* LWIP_TCP */#if LWIP_UDP && LWIP_UDPLITE/* Level: IPPROTO_UDPLITE */ case IPPROTO_UDPLITE: if (*optlen < sizeof(int)) { err = EINVAL; break; } /* If this is no UDP lite socket, ignore any options. */ if (sock->conn->type != NETCONN_UDPLITE) return 0; switch (optname) { case UDPLITE_SEND_CSCOV: case UDPLITE_RECV_CSCOV: break; default: LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n", s, optname)); err = ENOPROTOOPT; } /* switch (optname) */ break;#endif /* LWIP_UDP && LWIP_UDPLITE*//* UNDEFINED LEVEL */ default: LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", s, level, optname)); err = ENOPROTOOPT; } /* switch */ if (err != ERR_OK) { sock_set_errno(sock, err); return -1; } /* Now do the actual option processing */ data.sock = sock; data.level = level; data.optname = optname; data.optval = optval; data.optlen = optlen; data.err = err; tcpip_callback(lwip_getsockopt_internal, &data); sys_arch_sem_wait(sock->conn->op_completed, 0); /* maybe lwip_getsockopt_internal has changed err */ err = data.err; sock_set_errno(sock, err); return err ? -1 : 0;}static voidlwip_getsockopt_internal(void *arg){ struct lwip_socket *sock;#ifdef LWIP_DEBUG int s;#endif /* LWIP_DEBUG */ int level, optname; void *optval; struct lwip_setgetsockopt_data *data; LWIP_ASSERT("arg != NULL", arg != NULL); data = (struct lwip_setgetsockopt_data*)arg; sock = data->sock;#ifdef LWIP_DEBUG s = data->s;#endif /* LWIP_DEBUG */ level = data->level; optname = data->optname; optval = data->optval; switch (level) { /* Level: SOL_SOCKET */ case SOL_SOCKET: switch (optname) { /* The option flags */ case SO_ACCEPTCONN: case SO_BROADCAST: /* UNIMPL case SO_DEBUG: */ /* UNIMPL case SO_DONTROUTE: */ case SO_KEEPALIVE: /* UNIMPL case SO_OOBINCLUDE: */#if SO_REUSE case SO_REUSEADDR: case SO_REUSEPORT:#endif /* SO_REUSE */ /*case SO_USELOOPBACK: UNIMPL */ *(int*)optval = sock->conn->pcb.ip->so_options & optname; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n", s, optname, (*(int*)optval?"on":"off"))); break; case SO_TYPE: switch (NETCONNTYPE_GROUP(sock->conn->type)) { case NETCONN_RAW: *(int*)optval = SOCK_RAW; break; case NETCONN_TCP: *(int*)optval = SOCK_STREAM; break; case NETCONN_UDP: *(int*)optval = SOCK_DGRAM; break; default: /* unrecognized socket type */ *(int*)optval = sock->conn->type; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n", s, *(int *)optval)); } /* switch (sock->conn->type) */ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n", s, *(int *)optval)); break; case SO_ERROR: if (sock->err == 0) { sock_set_errno(sock, err_to_errno(sock->conn->err)); } *(int *)optval = sock->err; sock->err = 0; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n", s, *(int *)optval)); break;#if LWIP_SO_RCVTIMEO case SO_RCVTIMEO: *(int *)optval = sock->conn->recv_timeout; break;#endif /* LWIP_SO_RCVTIMEO */#if LWIP_SO_RCVBUF case SO_RCVBUF: *(int *)optval = sock->conn->recv_bufsize; break;#endif /* LWIP_SO_RCVBUF */#if LWIP_UDP case SO_NO_CHECK: *(int*)optval = (udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_NOCHKSUM) ? 1 : 0; break;#endif /* LWIP_UDP*/ } /* switch (optname) */ break;/* Level: IPPROTO_IP */ case IPPROTO_IP: switch (optname) { case IP_TTL: *(int*)optval = sock->conn->pcb.ip->ttl; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n", s, *(int *)optval)); break; case IP_TOS: *(int*)optval = sock->conn->pcb.ip->tos; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n", s, *(int *)optval)); break;#if LWIP_IGMP case IP_MULTICAST_TTL: *(u8_t*)optval = sock->conn->pcb.ip->ttl; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n", s, *(int *)optval));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -