static err_t altcp_mbedtls_close(struct altcp_pcb *conn) { struct altcp_pcb *inner_conn; if (conn == NULL) { return ERR_VAL; } inner_conn = conn->inner_conn; if (inner_conn) { err_t err; altcp_poll_fn oldpoll = inner_conn->poll; altcp_mbedtls_remove_callbacks(conn->inner_conn); err = altcp_close(conn->inner_conn); if (err != ERR_OK) { /* not closed, set up all callbacks again */ altcp_mbedtls_setup_callbacks(conn, inner_conn); /* poll callback is not included in the above */ altcp_poll(inner_conn, oldpoll, inner_conn->pollinterval); return err; } conn->inner_conn = NULL; } altcp_free(conn); return ERR_OK; }
/** Free http client state and deallocate all resources within */ static err_t httpc_free_state(httpc_state_t* req) { struct altcp_pcb* tpcb; if (req->request != NULL) { pbuf_free(req->request); req->request = NULL; } if (req->rx_hdrs != NULL) { pbuf_free(req->rx_hdrs); req->rx_hdrs = NULL; } tpcb = req->pcb; mem_free(req); req = NULL; if (tpcb != NULL) { err_t r; altcp_arg(tpcb, NULL); altcp_recv(tpcb, NULL); altcp_err(tpcb, NULL); altcp_poll(tpcb, NULL, 0); altcp_sent(tpcb, NULL); r = altcp_close(tpcb); if (r != ERR_OK) { altcp_abort(tpcb); return ERR_ABRT; } } return ERR_OK; }
static err_t altcp_mbedtls_lower_recv_process(struct altcp_pcb *conn, altcp_mbedtls_state_t *state) { if (!(state->flags & ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE)) { /* handle connection setup (handshake not done) */ int ret = mbedtls_ssl_handshake(&state->ssl_context); /* try to send data... */ altcp_output(conn->inner_conn); if (state->bio_bytes_read) { /* acknowledge all bytes read */ altcp_mbedtls_lower_recved(conn->inner_conn, state->bio_bytes_read); state->bio_bytes_read = 0; } if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) { /* handshake not done, wait for more recv calls */ LWIP_ASSERT("in this state, the rx chain should be empty", state->rx == NULL); return ERR_OK; } if (ret != 0) { LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_ssl_handshake failed: %d\n", ret)); /* handshake failed, connection has to be closed */ if (conn->err) { conn->err(conn->arg, ERR_CLSD); } if (altcp_close(conn) != ERR_OK) { altcp_abort(conn); } return ERR_OK; } /* If we come here, handshake succeeded. */ LWIP_ASSERT("state", state->bio_bytes_read == 0); LWIP_ASSERT("state", state->bio_bytes_appl == 0); state->flags |= ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE; /* issue "connect" callback" to upper connection (this can only happen for active open) */ if (conn->connected) { err_t err; err = conn->connected(conn->arg, conn, ERR_OK); if (err != ERR_OK) { return err; } } if (state->rx == NULL) { return ERR_OK; } } /* handle application data */ return altcp_mbedtls_handle_rx_appldata(conn, state); }
/** Try to close a pcb and free the arg if successful */ static void smtp_close(struct smtp_session *s, struct altcp_pcb *pcb, u8_t result, u16_t srv_err, err_t err) { if (pcb != NULL) { altcp_arg(pcb, NULL); if (altcp_close(pcb) == ERR_OK) { if (s != NULL) { smtp_free(s, result, srv_err, err); } } else { /* close failed, set back arg */ altcp_arg(pcb, s); } } else { if (s != NULL) { smtp_free(s, result, srv_err, err); } } }
/** Recv callback from lower connection (i.e. TCP) * This one mainly differs between connection setup/handshake (data is fed into mbedTLS only) * and application phase (data is decoded by mbedTLS and passed on to the application). */ static err_t altcp_mbedtls_lower_recv(void *arg, struct altcp_pcb *inner_conn, struct pbuf *p, err_t err) { altcp_mbedtls_state_t *state; struct altcp_pcb *conn = (struct altcp_pcb *)arg; LWIP_ASSERT("no err expected", err == ERR_OK); LWIP_UNUSED_ARG(err); if (!conn) { /* no connection given as arg? should not happen, but prevent pbuf/conn leaks */ if (p != NULL) { pbuf_free(p); } altcp_close(inner_conn); return ERR_CLSD; } state = (altcp_mbedtls_state_t *)conn->state; LWIP_ASSERT("pcb mismatch", conn->inner_conn == inner_conn); if (!state) { /* already closed */ if (p != NULL) { pbuf_free(p); } altcp_close(inner_conn); return ERR_CLSD; } /* handle NULL pbuf (inner connection closed) */ if (p == NULL) { /* remote host sent FIN, remember this (SSL state is destroyed when both sides are closed only!) */ if ((state->flags & (ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE | ALTCP_MBEDTLS_FLAGS_UPPER_CALLED)) == (ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE | ALTCP_MBEDTLS_FLAGS_UPPER_CALLED)) { /* need to notify upper layer (e.g. 'accept' called or 'connect' succeeded) */ if ((state->rx != NULL) || (state->rx_app != NULL)) { state->flags |= ALTCP_MBEDTLS_FLAGS_RX_CLOSE_QUEUED; /* this is a normal close (FIN) but we have unprocessed data, so delay the FIN */ altcp_mbedtls_handle_rx_appldata(conn, state); return ERR_OK; } state->flags |= ALTCP_MBEDTLS_FLAGS_RX_CLOSED; if (conn->recv) { return conn->recv(conn->arg, conn, NULL, ERR_OK); } } else { /* before connection setup is done: call 'err' */ if (conn->err) { conn->err(conn->arg, ERR_CLSD); } altcp_close(conn); } return ERR_OK; } /* If we come here, the connection is in good state (handshake phase or application data phase). Queue up the pbuf for processing as handshake data or application data. */ if (state->rx == NULL) { state->rx = p; } else { LWIP_ASSERT("rx pbuf overflow", (int)p->tot_len + (int)p->len <= 0xFFFF); pbuf_cat(state->rx, p); } return altcp_mbedtls_lower_recv_process(conn, state); }
/** The actual mail-sending function, called by smtp_send_mail and * smtp_send_mail_static after setting up the struct smtp_session. */ static err_t smtp_send_mail_alloced(struct smtp_session *s) { err_t err; struct altcp_pcb* pcb = NULL; ip_addr_t addr; LWIP_ASSERT("no smtp_session supplied", s != NULL); #if SMTP_CHECK_DATA /* check that body conforms to RFC: * - convert all single-CR or -LF in body to CRLF * - only 7-bit ASCII is allowed */ if (smtp_verify(s->to, s->to_len, 0) != ERR_OK) { err = ERR_ARG; goto leave; } if (smtp_verify(s->from, s->from_len, 0) != ERR_OK) { err = ERR_ARG; goto leave; } if (smtp_verify(s->subject, s->subject_len, 0) != ERR_OK) { err = ERR_ARG; goto leave; } #if SMTP_BODYDH if (s->bodydh == NULL) #endif /* SMTP_BODYDH */ { if (smtp_verify(s->body, s->body_len, 0) != ERR_OK) { err = ERR_ARG; goto leave; } } #endif /* SMTP_CHECK_DATA */ #if SMTP_COPY_AUTHDATA /* copy auth data, ensuring the first byte is always zero */ MEMCPY(s->auth_plain + 1, smtp_auth_plain + 1, smtp_auth_plain_len - 1); s->auth_plain_len = smtp_auth_plain_len; /* default username and pass is empty string */ s->username = s->auth_plain; s->pass = s->auth_plain; if (smtp_username != NULL) { s->username += smtp_username - smtp_auth_plain; } if (smtp_pass != NULL) { s->pass += smtp_pass - smtp_auth_plain; } #endif /* SMTP_COPY_AUTHDATA */ s->state = SMTP_NULL; s->timer = SMTP_TIMEOUT; #if LWIP_DNS err = dns_gethostbyname(smtp_server, &addr, smtp_dns_found, s); #else /* LWIP_DNS */ err = ipaddr_aton(smtp_server, &addr) ? ERR_OK : ERR_ARG; #endif /* LWIP_DNS */ if (err == ERR_OK) { pcb = smtp_setup_pcb(s, &addr); if (pcb == NULL) { err = ERR_MEM; goto leave; } err = altcp_connect(pcb, &addr, smtp_server_port, smtp_tcp_connected); if (err != ERR_OK) { LWIP_DEBUGF(SMTP_DEBUG_WARN_STATE, ("tcp_connect failed: %d\n", (int)err)); goto deallocate_and_leave; } } else if (err != ERR_INPROGRESS) { LWIP_DEBUGF(SMTP_DEBUG_WARN_STATE, ("dns_gethostbyname failed: %d\n", (int)err)); goto deallocate_and_leave; } return ERR_OK; deallocate_and_leave: if (pcb != NULL) { altcp_arg(pcb, NULL); altcp_close(pcb); } leave: smtp_free_struct(s); /* no need to call the callback here since we return != ERR_OK */ return err; }