err_t altcp_default_output(struct altcp_pcb *conn) { if (conn && conn->inner_conn) { return altcp_output(conn->inner_conn); } return ERR_VAL; }
/** Write data to a TLS connection. Calls into mbedTLS, which in turn calls into * @ref altcp_mbedtls_bio_send() to send the encrypted data */ static err_t altcp_mbedtls_write(struct altcp_pcb *conn, const void *dataptr, u16_t len, u8_t apiflags) { int ret; altcp_mbedtls_state_t *state; LWIP_UNUSED_ARG(apiflags); if (conn == NULL) { return ERR_VAL; } state = (altcp_mbedtls_state_t *)conn->state; if (state == NULL) { /* @todo: which error? */ return ERR_CLSD; } if (!(state->flags & ALTCP_MBEDTLS_FLAGS_HANDSHAKE_DONE)) { /* @todo: which error? */ return ERR_VAL; } /* HACK: if thre is something left to send, try to flush it and only allow sending more if this succeeded (this is a hack because neither returning 0 nor MBEDTLS_ERR_SSL_WANT_WRITE worked for me) */ if (state->ssl_context.out_left) { mbedtls_ssl_flush_output(&state->ssl_context); if (state->ssl_context.out_left) { return ERR_MEM; } } ret = mbedtls_ssl_write(&state->ssl_context, (const unsigned char *)dataptr, len); /* try to send data... */ altcp_output(conn->inner_conn); if (ret >= 0) { if (ret == len) { state->flags |= ALTCP_MBEDTLS_FLAGS_APPLDATA_SENT; return ERR_OK; } else { /* @todo/@fixme: assumption: either everything sent or error */ LWIP_ASSERT("ret <= 0", 0); return ERR_MEM; } } else { if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) { /* @todo: convert error to err_t */ return ERR_MEM; } LWIP_ASSERT("unhandled error", 0); return ERR_VAL; } }
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); }
/** http client tcp connected callback */ static err_t httpc_tcp_connected(void *arg, struct altcp_pcb *pcb, err_t err) { err_t r; httpc_state_t* req = (httpc_state_t*)arg; LWIP_UNUSED_ARG(pcb); LWIP_UNUSED_ARG(err); /* send request; last char is zero termination */ r = altcp_write(req->pcb, req->request->payload, req->request->len - 1, TCP_WRITE_FLAG_COPY); if (r != ERR_OK) { /* could not write the single small request -> fail, don't retry */ return httpc_close(req, HTTPC_RESULT_ERR_MEM, 0, r); } /* everything written, we can free the request */ pbuf_free(req->request); req->request = NULL; altcp_output(req->pcb); return ERR_OK; }
/** * Try send as many bytes as possible from output ring buffer * @param rb Output ring buffer * @param tpcb TCP connection handle */ static void mqtt_output_send(struct mqtt_ringbuf_t *rb, struct altcp_pcb *tpcb) { err_t err; u8_t wrap = 0; u16_t ringbuf_lin_len = mqtt_ringbuf_linear_read_length(rb); u16_t send_len = altcp_sndbuf(tpcb); LWIP_ASSERT("mqtt_output_send: tpcb != NULL", tpcb != NULL); if (send_len == 0 || ringbuf_lin_len == 0) { return; } LWIP_DEBUGF(MQTT_DEBUG_TRACE, ("mqtt_output_send: tcp_sndbuf: %d bytes, ringbuf_linear_available: %d, get %d, put %d\n", send_len, ringbuf_lin_len, rb->get, rb->put)); if (send_len > ringbuf_lin_len) { /* Space in TCP output buffer is larger than available in ring buffer linear portion */ send_len = ringbuf_lin_len; /* Wrap around if more data in ring buffer after linear portion */ wrap = (mqtt_ringbuf_len(rb) > ringbuf_lin_len); } err = altcp_write(tpcb, mqtt_ringbuf_get_ptr(rb), send_len, TCP_WRITE_FLAG_COPY | (wrap ? TCP_WRITE_FLAG_MORE : 0)); if ((err == ERR_OK) && wrap) { mqtt_ringbuf_advance_get_idx(rb, send_len); /* Use the lesser one of ring buffer linear length and TCP send buffer size */ send_len = LWIP_MIN(altcp_sndbuf(tpcb), mqtt_ringbuf_linear_read_length(rb)); err = altcp_write(tpcb, mqtt_ringbuf_get_ptr(rb), send_len, TCP_WRITE_FLAG_COPY); } if (err == ERR_OK) { mqtt_ringbuf_advance_get_idx(rb, send_len); /* Flush */ altcp_output(tpcb); } else { LWIP_DEBUGF(MQTT_DEBUG_WARN, ("mqtt_output_send: Send failed with err %d (\"%s\")\n", err, lwip_strerr(err))); } }