int httpd_send(httpd_req_t *r, const char *buf, size_t buf_len)
{
if (r == NULL || buf == NULL) {
- return -1;
+ return HTTPD_SOCK_ERR_INVALID;
}
if (!httpd_valid_req(r)) {
- return -1;
+ return HTTPD_SOCK_ERR_INVALID;
}
struct httpd_req_aux *ra = r->aux;
int ret = ra->sd->send_fn(ra->sd->fd, buf, buf_len, 0);
if (ret < 0) {
ESP_LOGD(TAG, LOG_FMT("error in send_fn"));
- return -1;
+ return ret;
}
return ret;
}
int ret = ra->sd->recv_fn(ra->sd->fd, buf, buf_len, 0);
if (ret < 0) {
ESP_LOGD(TAG, LOG_FMT("error in recv_fn"));
- return -1;
+ if ((ret == HTTPD_SOCK_ERR_TIMEOUT) && (pending_len != 0)) {
+ /* If recv() timeout occurred, but pending data is
+ * present, return length of pending data.
+ * This behavior is similar to that of socket recv()
+ * function, which, in case has only partially read the
+ * requested length, due to timeout, returns with read
+ * length, rather than error */
+ return pending_len;
+ }
+ return ret;
}
ESP_LOGD(TAG, LOG_FMT("received length = %d"), ret + pending_len);
int httpd_req_recv(httpd_req_t *r, char *buf, size_t buf_len)
{
if (r == NULL || buf == NULL) {
- return -1;
+ return HTTPD_SOCK_ERR_INVALID;
}
if (!httpd_valid_req(r)) {
ESP_LOGW(TAG, LOG_FMT("invalid request"));
- return -1;
+ return HTTPD_SOCK_ERR_INVALID;
}
struct httpd_req_aux *ra = r->aux;
int ret = httpd_recv(r, buf, buf_len);
if (ret < 0) {
ESP_LOGD(TAG, LOG_FMT("error in httpd_recv"));
- ra->remaining_len = 0;
- return -1;
+ return ret;
}
ra->remaining_len -= ret;
ESP_LOGD(TAG, LOG_FMT("received length = %d"), ret);
return ra->sd->fd;
}
+static int httpd_sock_err(const char *ctx, int sockfd)
+{
+ int errval;
+ int sock_err;
+ size_t sock_err_len = sizeof(sock_err);
+
+ if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &sock_err, &sock_err_len) < 0) {
+ ESP_LOGE(TAG, LOG_FMT("error calling getsockopt : %d"), errno);
+ return HTTPD_SOCK_ERR_FAIL;
+ }
+ ESP_LOGW(TAG, LOG_FMT("error in %s : %d"), ctx, sock_err);
+
+ switch(sock_err) {
+ case EAGAIN:
+ case EINTR:
+ errval = HTTPD_SOCK_ERR_TIMEOUT;
+ break;
+ case EINVAL:
+ case EBADF:
+ case EFAULT:
+ case ENOTSOCK:
+ errval = HTTPD_SOCK_ERR_INVALID;
+ break;
+ default:
+ errval = HTTPD_SOCK_ERR_FAIL;
+ }
+ return errval;
+}
+
int httpd_default_send(int sockfd, const char *buf, size_t buf_len, int flags)
{
if (buf == NULL) {
- return ESP_ERR_INVALID_ARG;
+ return HTTPD_SOCK_ERR_INVALID;
}
int ret = send(sockfd, buf, buf_len, flags);
if (ret < 0) {
- ESP_LOGW(TAG, LOG_FMT("error in send = %d"), errno);
+ return httpd_sock_err("send", sockfd);
}
return ret;
}
int httpd_default_recv(int sockfd, char *buf, size_t buf_len, int flags)
{
if (buf == NULL) {
- return ESP_ERR_INVALID_ARG;
+ return HTTPD_SOCK_ERR_INVALID;
}
int ret = recv(sockfd, buf, buf_len, flags);
if (ret < 0) {
- ESP_LOGW(TAG, LOG_FMT("error in recv = %d"), errno);
+ return httpd_sock_err("recv", sockfd);
}
return ret;
}