socket_error_t lwipv4_socket_send_to(struct socket *socket, const void * buf, const size_t len, const struct socket_addr *addr, const uint16_t port) { ip_addr_t a; err_t err = ERR_VAL; switch(socket->family) { case SOCKET_DGRAM: { struct pbuf *pb = pbuf_alloc(PBUF_TRANSPORT,len,PBUF_RAM); socket_event_t e; socket_api_handler_t handler = socket->handler; err = pbuf_take(pb, buf, len); if (err != ERR_OK) break; a.addr = socket_addr_get_ipv4_addr(addr); err = udp_sendto(socket->impl, pb, &a, port); pbuf_free(pb); if (err != ERR_OK) break; e.event = SOCKET_EVENT_TX_DONE; e.sock = socket; e.i.t.sentbytes = len; socket->event = &e; handler(); socket->event = NULL; break; } case SOCKET_STREAM: err = ERR_USE; break; } return lwipv4_socket_error_remap(err); }
err_t irqTCPRecv(void * arg, struct tcp_pcb * tpcb, struct pbuf * p, err_t err) { (void) tpcb; struct socket_event e; struct socket *s = (struct socket *) arg; if(err != ERR_OK) { e.event = SOCKET_EVENT_ERROR; e.i.e = lwipv4_socket_error_remap(err); s->event = &e; ((socket_api_handler_t)(s->handler))(); s->event = NULL; return ERR_OK; } /* Check for a disconnect */ if (p == NULL) { e.event = SOCKET_EVENT_DISCONNECT; s->event = &e; ((socket_api_handler_t) (s->handler))(); s->event = NULL; /* Zero the impl, since a disconnect will cause a free */ s->impl = NULL; return ERR_OK; } rx_core(s, p); e.event = SOCKET_EVENT_RX_DONE; s->event = &e; ((socket_api_handler_t)(s->handler))(); s->event = NULL; return ERR_OK; }
socket_error_t lwipv4_socket_send(struct socket *socket, const void * buf, const size_t len) { err_t err = ERR_VAL; switch(socket->family) { case SOCKET_DGRAM: { struct pbuf *pb = pbuf_alloc(PBUF_TRANSPORT,len,PBUF_RAM); socket_event_t e; socket_api_handler_t handler = socket->handler; err = pbuf_take(pb, buf, len); if (err != ERR_OK) break; err = udp_send(socket->impl, pb); pbuf_free(pb); if (err != ERR_OK) break; //Notify the application that the transfer is queued at the MAC layer e.event = SOCKET_EVENT_TX_DONE; e.sock = socket; e.i.t.sentbytes = len; socket->event = &e; handler(); socket->event = NULL; break; } case SOCKET_STREAM: err = tcp_write(socket->impl,buf,len,TCP_WRITE_FLAG_COPY); tcp_output(socket->impl); // TODO use opt instead with SOCKET_OPT_NAGGLE break; } return lwipv4_socket_error_remap(err); }
static err_t irqAccept (void * arg, struct tcp_pcb * newpcb, err_t err) { struct socket * s = (struct socket *)arg; struct socket_event e; socket_api_handler_t handler = s->handler; e.sock = s; if (err != ERR_OK) { e.event = SOCKET_EVENT_ERROR; e.i.e = lwipv4_socket_error_remap(err); err = ERR_OK; s->event = &e; handler(); s->event = NULL; } else { e.event = SOCKET_EVENT_ACCEPT; e.i.a.newimpl = newpcb; e.i.a.reject = 0; s->event = &e; handler(); s->event = NULL; if (e.i.a.reject) { err = ERR_ABRT; tcp_abort(newpcb); } } return err; }
static void tcp_error_handler(void *arg, err_t err) { struct socket *sock = (struct socket *) arg; struct socket_event e; socket_api_handler_t h = sock->handler; e.event = SOCKET_EVENT_ERROR; e.i.e = lwipv4_socket_error_remap(err); sock->event = &e; h(); sock->event = NULL; }
static socket_error_t lwipv4_socket_resolve(struct socket *sock, const char *address) { struct ip_addr ia; // attempt to resolve with DNS or convert to ip addr err_t err = dns_gethostbyname(address, &ia, dnscb, sock); if (err == ERR_OK) { dnscb(address, &ia, sock); } if (err == ERR_INPROGRESS) err = ERR_OK; return lwipv4_socket_error_remap(err); }
static socket_error_t lwipv4_socket_close(struct socket *sock) { err_t err = ERR_OK; if (sock == NULL || sock->impl == NULL) return SOCKET_ERROR_NULL_PTR; switch (sock->family) { case SOCKET_DGRAM: udp_disconnect((struct udp_pcb *)sock->impl); break; case SOCKET_STREAM: err = tcp_close((struct tcp_pcb *)sock->impl); break; default: return SOCKET_ERROR_BAD_FAMILY; } return lwipv4_socket_error_remap(err); }
static socket_error_t lwipv4_socket_bind(struct socket *sock, const struct socket_addr *address, const uint16_t port) { err_t err = ERR_OK; ip_addr_t a; switch (sock->family){ case SOCKET_DGRAM: a.addr = socket_addr_get_ipv4_addr(address); err = udp_bind((struct udp_pcb *)sock->impl, &a, port); break; case SOCKET_STREAM: a.addr = socket_addr_get_ipv4_addr(address); err = tcp_bind((struct tcp_pcb *)sock->impl, &a, port); break; default: return SOCKET_ERROR_BAD_FAMILY; } return lwipv4_socket_error_remap(err); }
static socket_error_t lwipv4_socket_connect(struct socket *sock, const struct socket_addr *address, const uint16_t port) { err_t err = ERR_OK; if (!socket_addr_is_ipv4(address)) { return SOCKET_ERROR_BAD_ADDRESS; } switch (sock->family){ case SOCKET_DGRAM: err = udp_connect((struct udp_pcb *)sock->impl, (void*)socket_addr_get_ipv4_addrp(address), port); break; case SOCKET_STREAM: err = tcp_connect((struct tcp_pcb *)sock->impl, (void*)socket_addr_get_ipv4_addrp(address), port, irqConnect); break; default: return SOCKET_ERROR_BAD_FAMILY; } return lwipv4_socket_error_remap(err); }
socket_error_t lwipv4_socket_send(struct socket *socket, const void * buf, const size_t len) { err_t err = ERR_VAL; switch(socket->family) { case SOCKET_DGRAM: { struct pbuf *pb = pbuf_alloc(PBUF_TRANSPORT,len,PBUF_RAM); socket_event_t e; socket_api_handler_t handler = socket->handler; err = pbuf_take(pb, buf, len); if (err != ERR_OK) break; err = udp_send(socket->impl, pb); pbuf_free(pb); if (err != ERR_OK) break; //Notify the application that the transfer is queued at the MAC layer e.event = SOCKET_EVENT_TX_DONE; e.sock = socket; e.i.t.sentbytes = len; socket->event = &e; handler(); socket->event = NULL; break; } case SOCKET_STREAM:{ struct tcp_pcb* pcb = socket->impl; err = tcp_write(pcb,buf,len,TCP_WRITE_FLAG_COPY); if (tcp_nagle_disabled(pcb)) { // TODO: Remove when sal-driver-lwip-k64f-eth/#8 is fixed #ifdef YOTTA_SAL_DRIVER_LWIP_K64F_ETH_VERSION_STRING emac_tcp_push_pcb = (struct pbuf * volatile)pcb; vIRQ_SetPendingIRQ(ENET_Receive_IRQn); #else tcp_output(pcb); #endif } break; } } return lwipv4_socket_error_remap(err); }
err_t irqTCPRecv(void * arg, struct tcp_pcb * tpcb, struct pbuf * p, err_t err) { struct socket_event e; struct socket *s = (struct socket *) arg; if(err != ERR_OK) { e.event = SOCKET_EVENT_ERROR; e.i.e = lwipv4_socket_error_remap(err); s->event = &e; ((socket_api_handler_t)(s->handler))(); s->event = NULL; return ERR_OK; } /* Check for a disconnect */ if (p == NULL) { e.event = SOCKET_EVENT_DISCONNECT; s->event = &e; ((socket_api_handler_t) (s->handler))(); s->event = NULL; /* if close has been called, we have to remove impl, since it could be freed */ switch (tpcb->state) { case FIN_WAIT_1: case FIN_WAIT_2: case TIME_WAIT: /* Zero the impl, since a disconnect will cause a free */ s->impl = NULL; break; default: break; } return ERR_OK; } rx_core(s, p); e.event = SOCKET_EVENT_RX_DONE; s->event = &e; ((socket_api_handler_t)(s->handler))(); s->event = NULL; return ERR_OK; }
static err_t irqConnect(void * arg, struct tcp_pcb * tpcb, err_t err) { struct socket *sock = (struct socket *) arg; socket_api_handler_t handler = (socket_api_handler_t) sock->handler; socket_event_t e; tcp_sent(tpcb,irqTCPSent); tcp_recv(tpcb, irqTCPRecv); if (err != ERR_OK) { e.event = SOCKET_EVENT_ERROR; e.i.e = lwipv4_socket_error_remap(err); } else { e.event = SOCKET_EVENT_CONNECT; } sock->event = &e; handler(); sock->event = NULL; return ERR_OK; }