Skip to content
easy.c 31.2 KiB
Newer Older

    /* open an iconv conversion descriptor if necessary */
    if(data->utf8_cd == (iconv_t)-1) {
      data->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
                                 CURL_ICONV_CODESET_FOR_UTF8);
      if(data->utf8_cd == (iconv_t)-1) {
        failf(data,
              "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
Daniel Stenberg's avatar
Daniel Stenberg committed
              CURL_ICONV_CODESET_OF_HOST,
              CURL_ICONV_CODESET_FOR_UTF8,
              error, strerror(error));
        return CURLE_CONV_FAILED;
      }
    }
    /* call iconv */
    input_ptr = output_ptr = buffer;
    in_bytes = out_bytes = length;
    rc = iconv(data->utf8_cd, &input_ptr, &in_bytes,
Gisle Vanem's avatar
Gisle Vanem committed
               &output_ptr, &out_bytes);
    if((rc == ICONV_ERROR) || (in_bytes != 0)) {
Daniel Stenberg's avatar
Daniel Stenberg committed
            "The Curl_convert_from_utf8 iconv call failed with errno %i: %s",
            error, strerror(error));
      /* null terminate the now shorter output string */
      *output_ptr = 0x00;
    }
#else
    failf(data, "CURLOPT_CONV_FROM_UTF8_FUNCTION callback required");
    return CURLE_CONV_REQD;
#endif /* HAVE_ICONV */
  }

  return CURLE_OK;
}

#endif /* CURL_DOES_CONVERSIONS */

static CURLcode easy_connection(struct SessionHandle *data,
                                curl_socket_t *sfd,
                                struct connectdata **connp)
{
  CURLcode ret;
  long sockfd;

  if(data == NULL)
    return CURLE_BAD_FUNCTION_ARGUMENT;

  /* only allow these to be called on handles with CURLOPT_CONNECT_ONLY */
  if(!data->set.connect_only) {
    failf(data, "CONNECT_ONLY is required!");
    return CURLE_UNSUPPORTED_PROTOCOL;
  }

  ret = Curl_getconnectinfo(data, &sockfd, connp);
  if(ret != CURLE_OK)
    return ret;

  if(sockfd == -1) {
    failf(data, "Failed to get recent socket");
    return CURLE_UNSUPPORTED_PROTOCOL;
  }

  *sfd = (curl_socket_t)sockfd; /* we know that this is actually a socket
                                   descriptor so the typecast is fine here */

  return CURLE_OK;
}

/*
 * Receives data from the connected socket. Use after successful
 * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
 * Returns CURLE_OK on success, error code on error.
 */
CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, size_t *n)
{
  curl_socket_t sfd;
  CURLcode ret;
  int ret1;
  ssize_t n1;
  struct connectdata *c;
  struct SessionHandle *data = (struct SessionHandle *)curl;

  ret = easy_connection(data, &sfd, &c);
  if(ret)
    return ret;

  *n = 0;
  ret1 = Curl_read(c, sfd, buffer, buflen, &n1);

  if(ret1 == -1)
    return CURLE_AGAIN;


  *n = (size_t)n1;

  return CURLE_OK;
}

/*
 * Sends data over the connected socket. Use after successful
 * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
 */
CURLcode curl_easy_send(CURL *curl, const void *buffer, size_t buflen,
                        size_t *n)
{
  curl_socket_t sfd;
  CURLcode ret;
  ssize_t n1;
  struct connectdata *c = NULL;
  struct SessionHandle *data = (struct SessionHandle *)curl;

  ret = easy_connection(data, &sfd, &c);
  if(ret)
    return ret;

  *n = 0;
  ret = Curl_write(c, sfd, buffer, buflen, &n1);

  if(n1 == -1)
    return CURLE_SEND_ERROR;

  /* detect EAGAIN */
  if((CURLE_OK == ret) && (0 == n1))
    return CURLE_AGAIN;

  *n = (size_t)n1;

  return ret;
}