1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at https://curl.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 * SPDX-License-Identifier: curl 22 * 23 ***************************************************************************/ 24#include "tool_setup.h" 25 26#ifdef HAVE_SYS_SELECT_H 27#include <sys/select.h> 28#endif 29 30#define ENABLE_CURLX_PRINTF 31/* use our own printf() functions */ 32#include "curlx.h" 33 34#include "tool_cfgable.h" 35#include "tool_cb_rea.h" 36#include "tool_operate.h" 37#include "tool_util.h" 38#include "tool_msgs.h" 39 40#include "memdebug.h" /* keep this as LAST include */ 41 42/* 43** callback for CURLOPT_READFUNCTION 44*/ 45 46size_t tool_read_cb(char *buffer, size_t sz, size_t nmemb, void *userdata) 47{ 48 ssize_t rc = 0; 49 struct per_transfer *per = userdata; 50 struct OperationConfig *config = per->config; 51 52 if((per->uploadfilesize != -1) && 53 (per->uploadedsofar == per->uploadfilesize)) { 54 /* done */ 55 return 0; 56 } 57 58 if(config->timeout_ms) { 59 struct timeval now = tvnow(); 60 long msdelta = tvdiff(now, per->start); 61 62 if(msdelta > config->timeout_ms) 63 /* timeout */ 64 return 0; 65#ifndef _WIN32 66 /* this logic waits on read activity on a file descriptor that is not a 67 socket which makes it not work with select() on Windows */ 68 else { 69 fd_set bits; 70 struct timeval timeout; 71 long wait = config->timeout_ms - msdelta; 72 73 /* wait this long at the most */ 74 timeout.tv_sec = wait/1000; 75 timeout.tv_usec = (int)((wait%1000)*1000); 76 77 FD_ZERO(&bits); 78 FD_SET(per->infd, &bits); 79 if(!select(per->infd + 1, &bits, NULL, NULL, &timeout)) 80 return 0; /* timeout */ 81 } 82#endif 83 } 84 85 rc = read(per->infd, buffer, sz*nmemb); 86 if(rc < 0) { 87 if(errno == EAGAIN) { 88 errno = 0; 89 config->readbusy = TRUE; 90 return CURL_READFUNC_PAUSE; 91 } 92 /* since size_t is unsigned we can't return negative values fine */ 93 rc = 0; 94 } 95 if((per->uploadfilesize != -1) && 96 (per->uploadedsofar + rc > per->uploadfilesize)) { 97 /* do not allow uploading more than originally set out to do */ 98 curl_off_t delta = per->uploadedsofar + rc - per->uploadfilesize; 99 warnf(per->config->global, "File size larger in the end than when " 100 "started. Dropping at least %" CURL_FORMAT_CURL_OFF_T " bytes", 101 delta); 102 rc = (ssize_t)(per->uploadfilesize - per->uploadedsofar); 103 } 104 config->readbusy = FALSE; 105 106 /* when select() returned zero here, it timed out */ 107 return (size_t)rc; 108} 109 110/* 111** callback for CURLOPT_XFERINFOFUNCTION used to unpause busy reads 112*/ 113 114int tool_readbusy_cb(void *clientp, 115 curl_off_t dltotal, curl_off_t dlnow, 116 curl_off_t ultotal, curl_off_t ulnow) 117{ 118 struct per_transfer *per = clientp; 119 struct OperationConfig *config = per->config; 120 121 (void)dltotal; /* unused */ 122 (void)dlnow; /* unused */ 123 (void)ultotal; /* unused */ 124 (void)ulnow; /* unused */ 125 126 if(config->readbusy) { 127 config->readbusy = FALSE; 128 curl_easy_pause(per->curl, CURLPAUSE_CONT); 129 } 130 131 return per->noprogress? 0 : CURL_PROGRESSFUNC_CONTINUE; 132} 133