Exemplo n.º 1
0
/** 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;
}
Exemplo n.º 2
0
static void
altcp_mbedtls_remove_callbacks(struct altcp_pcb *inner_conn)
{
  altcp_arg(inner_conn, NULL);
  altcp_recv(inner_conn, NULL);
  altcp_sent(inner_conn, NULL);
  altcp_err(inner_conn, NULL);
  altcp_poll(inner_conn, NULL, inner_conn->pollinterval);
}
Exemplo n.º 3
0
static void
altcp_mbedtls_setup_callbacks(struct altcp_pcb *conn, struct altcp_pcb *inner_conn)
{
  altcp_arg(inner_conn, conn);
  altcp_recv(inner_conn, altcp_mbedtls_lower_recv);
  altcp_sent(inner_conn, altcp_mbedtls_lower_sent);
  altcp_err(inner_conn, altcp_mbedtls_lower_err);
  /* tcp_poll is set when interval is set by application */
  /* listen is set totally different :-) */
}
Exemplo n.º 4
0
/** 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);
    }
  }
}
Exemplo n.º 5
0
static struct altcp_pcb*
smtp_setup_pcb(struct smtp_session *s, const ip_addr_t* remote_ip)
{
  struct altcp_pcb* pcb;
  LWIP_UNUSED_ARG(remote_ip);

#if LWIP_ALTCP && LWIP_ALTCP_TLS
  if (smtp_server_tls_config) {
    pcb = altcp_tls_new(smtp_server_tls_config, IP_GET_TYPE(remote_ip));
  } else
#endif
  {
    pcb = altcp_tcp_new_ip_type(IP_GET_TYPE(remote_ip));
  }
  if (pcb != NULL) {
    altcp_arg(pcb, s);
    altcp_recv(pcb, smtp_tcp_recv);
    altcp_err(pcb, smtp_tcp_err);
    altcp_poll(pcb, smtp_tcp_poll, SMTP_POLL_INTERVAL);
    altcp_sent(pcb, smtp_tcp_sent);
  }
  return pcb;
}
Exemplo n.º 6
0
/** 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;
}
Exemplo n.º 7
0
/** State machine-like implementation of an SMTP client.
 */
static void
smtp_process(void *arg, struct altcp_pcb *pcb, struct pbuf *p)
{
  struct smtp_session* s = (struct smtp_session*)arg;
  u16_t response_code = 0;
  u16_t tx_buf_len = 0;
  enum smtp_session_state next_state;

  if (arg == NULL) {
    /* already closed SMTP connection */
    if (p != NULL) {
      LWIP_DEBUGF(SMTP_DEBUG_TRACE, ("Received %d bytes after closing: %s\n",
        p->tot_len, smtp_pbuf_str(p)));
      pbuf_free(p);
    }
    return;
  }

  next_state = s->state;

  if (p != NULL) {
    /* received data */
    if (s->p == NULL) {
      s->p = p;
    } else {
      pbuf_cat(s->p, p);
    }
  } else {
    /* idle timer, close connection if timed out */
    if (s->timer == 0) {
      LWIP_DEBUGF(SMTP_DEBUG_WARN_STATE, ("smtp_process: connection timed out, closing\n"));
      smtp_close(s, pcb, SMTP_RESULT_ERR_TIMEOUT, 0, ERR_TIMEOUT);
      return;
    }
    if (s->state == SMTP_BODY) {
      smtp_send_body(s, pcb);
      return;
    }
  }
  response_code = smtp_is_response(s);
  if (response_code) {
    LWIP_DEBUGF(SMTP_DEBUG_TRACE, ("smtp_process: received response code: %d\n", response_code));
    if (smtp_is_response_finished(s) != ERR_OK) {
      LWIP_DEBUGF(SMTP_DEBUG_TRACE, ("smtp_process: partly received response code: %d\n", response_code));
      /* wait for next packet to complete the respone */
      return;
    }
  } else {
    if (s->p != NULL) {
      LWIP_DEBUGF(SMTP_DEBUG_WARN, ("smtp_process: unknown data received (%s)\n",
        smtp_pbuf_str(s->p)));
      pbuf_free(s->p);
      s->p = NULL;
    }
    return;
  }

  switch(s->state)
  {
  case(SMTP_NULL):
    /* wait for 220 */
    if (response_code == 220) {
      /* then send EHLO */
      next_state = smtp_prepare_helo(s, &tx_buf_len, pcb);
    }
    break;
  case(SMTP_HELO):
    /* wait for 250 */
    if (response_code == 250) {
#if SMTP_SUPPORT_AUTH_PLAIN || SMTP_SUPPORT_AUTH_LOGIN
      /* then send AUTH or MAIL */
      next_state = smtp_prepare_auth_or_mail(s, &tx_buf_len);
    }
    break;
  case(SMTP_AUTH_LOGIN):
  case(SMTP_AUTH_PLAIN):
    /* wait for 235 */
    if (response_code == 235) {
#endif /* SMTP_SUPPORT_AUTH_PLAIN || SMTP_SUPPORT_AUTH_LOGIN */
      /* send MAIL */
      next_state = smtp_prepare_mail(s, &tx_buf_len);
    }
    break;
#if SMTP_SUPPORT_AUTH_LOGIN
  case(SMTP_AUTH_LOGIN_UNAME):
    /* wait for 334 Username */
    if (response_code == 334) {
      if (pbuf_strstr(s->p, SMTP_RESP_LOGIN_UNAME) != 0xFFFF) {
        /* send username */
        next_state = smtp_prepare_auth_login_uname(s, &tx_buf_len);
      }
    }
    break;
  case(SMTP_AUTH_LOGIN_PASS):
    /* wait for 334 Password */
    if (response_code == 334) {
      if (pbuf_strstr(s->p, SMTP_RESP_LOGIN_PASS) != 0xFFFF) {
        /* send username */
        next_state = smtp_prepare_auth_login_pass(s, &tx_buf_len);
      }
    }
    break;
#endif /* SMTP_SUPPORT_AUTH_LOGIN */
  case(SMTP_MAIL):
    /* wait for 250 */
    if (response_code == 250) {
      /* send RCPT */
      next_state = smtp_prepare_rcpt(s, &tx_buf_len);
    }
    break;
  case(SMTP_RCPT):
    /* wait for 250 */
    if (response_code == 250) {
      /* send DATA */
      SMEMCPY(s->tx_buf, SMTP_CMD_DATA, SMTP_CMD_DATA_LEN);
      tx_buf_len = SMTP_CMD_DATA_LEN;
      next_state = SMTP_DATA;
    }
    break;
  case(SMTP_DATA):
    /* wait for 354 */
    if (response_code == 354) {
      /* send email header */
      next_state = smtp_prepare_header(s, &tx_buf_len);
    }
    break;
  case(SMTP_BODY):
    /* nothing to be done here, handled somewhere else */
    break;
  case(SMTP_QUIT):
    /* wait for 250 */
    if (response_code == 250) {
      /* send QUIT */
      next_state = smtp_prepare_quit(s, &tx_buf_len);
    }
    break;
  case(SMTP_CLOSED):
    /* nothing to do, wait for connection closed from server */
    return;
  default:
    LWIP_DEBUGF(SMTP_DEBUG_SERIOUS, ("Invalid state: %d/%s\n", (int)s->state,
      smtp_state_str[s->state]));
    break;
  }
  if (s->state == next_state) {
    LWIP_DEBUGF(SMTP_DEBUG_WARN_STATE, ("smtp_process[%s]: unexpected response_code, closing: %d (%s)\n",
      smtp_state_str[s->state], response_code, smtp_pbuf_str(s->p)));
    /* close connection */
    smtp_close(s, pcb, SMTP_RESULT_ERR_SVR_RESP, response_code, ERR_OK);
    return;
  }
  if (tx_buf_len > 0) {
    SMTP_TX_BUF_MAX(tx_buf_len);
    if (altcp_write(pcb, s->tx_buf, tx_buf_len, TCP_WRITE_FLAG_COPY) == ERR_OK) {
      LWIP_DEBUGF(SMTP_DEBUG_TRACE, ("smtp_process[%s]: received command %d (%s)\n",
        smtp_state_str[s->state], response_code, smtp_pbuf_str(s->p)));
      LWIP_DEBUGF(SMTP_DEBUG_TRACE, ("smtp_process[%s]: sent %"U16_F" bytes: \"%s\"\n",
        smtp_state_str[s->state], tx_buf_len, s->tx_buf));
      s->timer = SMTP_TIMEOUT;
      pbuf_free(s->p);
      s->p = NULL;
      LWIP_DEBUGF(SMTP_DEBUG_STATE, ("smtp_process: changing state from %s to %s\n",
        smtp_state_str[s->state], smtp_state_str[next_state]));
      s->state = next_state;
      if (next_state == SMTP_BODY) {
        /* try to stream-send body data right now */
        smtp_send_body(s, pcb);
      } else if (next_state == SMTP_CLOSED) {
        /* sent out all data, delete structure */
        altcp_arg(pcb, NULL);
        smtp_free(s, SMTP_RESULT_OK, 0, ERR_OK);
      }
    }
  }
}
Exemplo n.º 8
0
/** Initialize the connection struct */
static err_t
httpc_init_connection_common(httpc_state_t **connection, const httpc_connection_t *settings, const char* server_name,
                      u16_t server_port, const char* uri, altcp_recv_fn recv_fn, void* callback_arg, int use_host)
{
  size_t alloc_len;
  mem_size_t mem_alloc_len;
  int req_len, req_len2;
  httpc_state_t *req;
#if HTTPC_DEBUG_REQUEST
  size_t server_name_len, uri_len;
#endif

  LWIP_ASSERT("uri != NULL", uri != NULL);

  /* get request len */
  req_len = httpc_create_request_string(settings, server_name, server_port, uri, use_host, NULL, 0);
  if ((req_len < 0) || (req_len > 0xFFFF)) {
    return ERR_VAL;
  }
  /* alloc state and request in one block */
  alloc_len = sizeof(httpc_state_t);
#if HTTPC_DEBUG_REQUEST
  server_name_len = server_name ? strlen(server_name) : 0;
  uri_len = strlen(uri);
  alloc_len += server_name_len + 1 + uri_len + 1;
#endif
  mem_alloc_len = (mem_size_t)alloc_len;
  if ((mem_alloc_len < alloc_len) || (req_len + 1 > 0xFFFF)) {
    return ERR_VAL;
  }

  req = (httpc_state_t*)mem_malloc((mem_size_t)alloc_len);
  if(req == NULL) {
    return ERR_MEM;
  }
  memset(req, 0, sizeof(httpc_state_t));
  req->timeout_ticks = HTTPC_POLL_TIMEOUT;
  req->request = pbuf_alloc(PBUF_RAW, (u16_t)(req_len + 1), PBUF_RAM);
  if (req->request == NULL) {
    httpc_free_state(req);
    return ERR_MEM;
  }
  if (req->request->next != NULL) {
    /* need a pbuf in one piece */
    httpc_free_state(req);
    return ERR_MEM;
  }
  req->hdr_content_len = HTTPC_CONTENT_LEN_INVALID;
#if HTTPC_DEBUG_REQUEST
  req->server_name = (char*)(req + 1);
  if (server_name) {
    memcpy(req->server_name, server_name, server_name_len + 1);
  }
  req->uri = req->server_name + server_name_len + 1;
  memcpy(req->uri, uri, uri_len + 1);
#endif
  req->pcb = altcp_new(settings->altcp_allocator);
  if(req->pcb == NULL) {
    httpc_free_state(req);
    return ERR_MEM;
  }
  req->remote_port = settings->use_proxy ? settings->proxy_port : server_port;
  altcp_arg(req->pcb, req);
  altcp_recv(req->pcb, httpc_tcp_recv);
  altcp_err(req->pcb, httpc_tcp_err);
  altcp_poll(req->pcb, httpc_tcp_poll, HTTPC_POLL_INTERVAL);
  altcp_sent(req->pcb, httpc_tcp_sent);

  /* set up request buffer */
  req_len2 = httpc_create_request_string(settings, server_name, server_port, uri, use_host,
    (char *)req->request->payload, req_len + 1);
  if (req_len2 != req_len) {
    httpc_free_state(req);
    return ERR_VAL;
  }

  req->recv_fn = recv_fn;
  req->conn_settings = settings;
  req->callback_arg = callback_arg;

  *connection = req;
  return ERR_OK;
}