int lwip_recvfrom(int s, void *mem, int len, unsigned int flags, struct sockaddr *from, socklen_t *fromlen) { struct lwip_socket *sock; struct netbuf *buf; u16_t buflen, copylen, off = 0; struct ip_addr *addr; u16_t port; u8_t done = 0; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %d, 0x%x, ..)\n", s, mem, len, flags)); sock = get_socket(s); if (!sock) return -1; do { LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: top while sock->lastdata=%p\n", (void*)sock->lastdata)); /* Check if there is data left from the last recv operation. */ if (sock->lastdata) { buf = sock->lastdata; } else { /* If this is non-blocking call, then check first */ if (((flags & MSG_DONTWAIT) || (sock->flags & O_NONBLOCK)) && !sock->rcvevent) { LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s)); sock_set_errno(sock, EWOULDBLOCK); return -1; } /* No data was left from the previous operation, so we try to get some from the network. */ sock->lastdata = buf = netconn_recv(sock->conn); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv netbuf=%p\n", (void*)buf)); if (!buf) { /* We should really do some error checking here. */ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL!\n", s)); sock_set_errno(sock, (((sock->conn->pcb.ip!=NULL) && (sock->conn->err==ERR_OK))?ETIMEDOUT:err_to_errno(sock->conn->err))); return 0; } } buflen = netbuf_len(buf); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%d len=%d off=%d sock->lastoffset=%d\n", buflen, len, off, sock->lastoffset)); buflen -= sock->lastoffset; if (len > buflen) { copylen = buflen; } else { copylen = len; } /* copy the contents of the received buffer into the supplied memory pointer mem */ netbuf_copy_partial(buf, (u8_t*)mem + off, copylen, sock->lastoffset); off += copylen; if (netconn_type(sock->conn) == NETCONN_TCP) { len -= copylen; if ( (len <= 0) || (buf->p->flags & PBUF_FLAG_PUSH) || !sock->rcvevent || ((flags & MSG_PEEK)!=0)) { done = 1; } } else { done = 1; } /* Check to see from where the data was.*/ if (done) { if (from && fromlen) { struct sockaddr_in sin; if (netconn_type(sock->conn) == NETCONN_TCP) { addr = (struct ip_addr*)&(sin.sin_addr.s_addr); netconn_getaddr(sock->conn, addr, &port, 0); } else { addr = netbuf_fromaddr(buf); port = netbuf_fromport(buf); } memset(&sin, 0, sizeof(sin)); sin.sin_len = sizeof(sin); sin.sin_family = AF_INET; sin.sin_port = htons(port); sin.sin_addr.s_addr = addr->addr; if (*fromlen > sizeof(sin)) { *fromlen = sizeof(sin); } SMEMCPY(from, &sin, *fromlen); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s)); ip_addr_debug_print(SOCKETS_DEBUG, addr); LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u len=%u\n", port, off)); } else { #if SOCKETS_DEBUG struct sockaddr_in sin; if (netconn_type(sock->conn) == NETCONN_TCP) { addr = (struct ip_addr*)&(sin.sin_addr.s_addr); netconn_getaddr(sock->conn, addr, &port, 0); } else { addr = netbuf_fromaddr(buf); port = netbuf_fromport(buf); } LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s)); ip_addr_debug_print(SOCKETS_DEBUG, addr); LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u len=%u\n", port, off)); #endif /* SOCKETS_DEBUG */ } } /* If we don't peek the incoming message... */ if ((flags & MSG_PEEK)==0) { /* 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 ((netconn_type(sock->conn) == NETCONN_TCP) && (buflen - copylen > 0)) { sock->lastdata = buf; sock->lastoffset += copylen; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", (void*)buf)); } else { sock->lastdata = NULL; sock->lastoffset = 0; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", (void*)buf)); netbuf_delete(buf); } } } while (!done); sock_set_errno(sock, 0); return off; }