00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "test.h"
00023
00024 #include <fcntl.h>
00025
00026 #include "testutil.h"
00027 #include "warnless.h"
00028 #include "memdebug.h"
00029
00030 #define TEST_HANG_TIMEOUT 60 * 1000
00031
00032 struct Sockets
00033 {
00034 curl_socket_t *sockets;
00035 int count;
00036 int max_count;
00037 };
00038
00039 struct ReadWriteSockets
00040 {
00041 struct Sockets read, write;
00042 };
00043
00047 static void removeFd(struct Sockets* sockets, curl_socket_t fd, int mention)
00048 {
00049 int i;
00050
00051 if(mention)
00052 fprintf(stderr, "Remove socket fd %d\n", (int) fd);
00053
00054 for(i = 0; i < sockets->count; ++i) {
00055 if(sockets->sockets[i] == fd) {
00056 if(i < sockets->count - 1)
00057 memmove(&sockets->sockets[i], &sockets->sockets[i + 1],
00058 sizeof(curl_socket_t) * (sockets->count - (i + 1)));
00059 --sockets->count;
00060 }
00061 }
00062 }
00063
00067 static void addFd(struct Sockets* sockets, curl_socket_t fd, const char *what)
00068 {
00073 fprintf(stderr, "Add socket fd %d for %s\n", (int) fd, what);
00074 removeFd(sockets, fd, 0);
00075
00076
00077
00078 if(!sockets->sockets) {
00079 sockets->sockets = malloc(sizeof(curl_socket_t) * 20U);
00080 if(!sockets->sockets)
00081 return;
00082 sockets->max_count = 20;
00083 }
00084 else if(sockets->count + 1 > sockets->max_count) {
00085 curl_socket_t *oldptr = sockets->sockets;
00086 sockets->sockets = realloc(oldptr, sizeof(curl_socket_t) *
00087 (sockets->max_count + 20));
00088 if(!sockets->sockets) {
00089
00090 sockets->sockets = oldptr;
00091 return;
00092 }
00093 sockets->max_count += 20;
00094 }
00095
00096
00097
00098 sockets->sockets[sockets->count] = fd;
00099 ++sockets->count;
00100 }
00101
00105 static int curlSocketCallback(CURL *easy, curl_socket_t s, int action,
00106 void *userp, void *socketp)
00107 {
00108 struct ReadWriteSockets* sockets = userp;
00109
00110 (void)easy;
00111 (void)socketp;
00112
00113 if(action == CURL_POLL_IN || action == CURL_POLL_INOUT)
00114 addFd(&sockets->read, s, "read");
00115
00116 if(action == CURL_POLL_OUT || action == CURL_POLL_INOUT)
00117 addFd(&sockets->write, s, "write");
00118
00119 if(action == CURL_POLL_REMOVE) {
00120 removeFd(&sockets->read, s, 1);
00121 removeFd(&sockets->write, s, 0);
00122 }
00123
00124 return 0;
00125 }
00126
00130 static int curlTimerCallback(CURLM *multi, long timeout_ms, void *userp)
00131 {
00132 struct timeval* timeout = userp;
00133
00134 (void)multi;
00135 if(timeout_ms != -1) {
00136 *timeout = tutil_tvnow();
00137 timeout->tv_usec += timeout_ms * 1000;
00138 }
00139 else {
00140 timeout->tv_sec = -1;
00141 }
00142 return 0;
00143 }
00144
00148 static int checkForCompletion(CURLM *curl, int *success)
00149 {
00150 int numMessages;
00151 CURLMsg *message;
00152 int result = 0;
00153 *success = 0;
00154 while((message = curl_multi_info_read(curl, &numMessages)) != NULL) {
00155 if(message->msg == CURLMSG_DONE) {
00156 result = 1;
00157 if(message->data.result == CURLE_OK)
00158 *success = 1;
00159 else
00160 *success = 0;
00161 }
00162 else {
00163 fprintf(stderr, "Got an unexpected message from curl: %i\n",
00164 (int)message->msg);
00165 result = 1;
00166 *success = 0;
00167 }
00168 }
00169 return result;
00170 }
00171
00172 static int getMicroSecondTimeout(struct timeval* timeout)
00173 {
00174 struct timeval now;
00175 ssize_t result;
00176 now = tutil_tvnow();
00177 result = (timeout->tv_sec - now.tv_sec) * 1000000 +
00178 timeout->tv_usec - now.tv_usec;
00179 if(result < 0)
00180 result = 0;
00181
00182 return curlx_sztosi(result);
00183 }
00184
00188 static void updateFdSet(struct Sockets* sockets, fd_set* fdset,
00189 curl_socket_t *maxFd)
00190 {
00191 int i;
00192 for(i = 0; i < sockets->count; ++i) {
00193 FD_SET(sockets->sockets[i], fdset);
00194 if(*maxFd < sockets->sockets[i] + 1) {
00195 *maxFd = sockets->sockets[i] + 1;
00196 }
00197 }
00198 }
00199
00200 static void notifyCurl(CURLM *curl, curl_socket_t s, int evBitmask,
00201 const char *info)
00202 {
00203 int numhandles = 0;
00204 CURLMcode result = curl_multi_socket_action(curl, s, evBitmask, &numhandles);
00205 if(result != CURLM_OK) {
00206 fprintf(stderr, "Curl error on %s: %i (%s)\n",
00207 info, result, curl_multi_strerror(result));
00208 }
00209 }
00210
00214 static void checkFdSet(CURLM *curl, struct Sockets *sockets, fd_set *fdset,
00215 int evBitmask, const char *name)
00216 {
00217 int i;
00218 for(i = 0; i < sockets->count; ++i) {
00219 if(FD_ISSET(sockets->sockets[i], fdset)) {
00220 notifyCurl(curl, sockets->sockets[i], evBitmask, name);
00221 }
00222 }
00223 }
00224
00225 int test(char *URL)
00226 {
00227 int res = 0;
00228 CURL *curl = NULL;
00229 FILE *hd_src = NULL;
00230 int hd;
00231 int error;
00232 struct_stat file_info;
00233 CURLM *m = NULL;
00234 struct ReadWriteSockets sockets = {{NULL, 0, 0}, {NULL, 0, 0}};
00235 struct timeval timeout = {-1, 0};
00236 int success = 0;
00237
00238 start_test_timing();
00239
00240 if(!libtest_arg3) {
00241 fprintf(stderr, "Usage: lib582 [url] [filename] [username]\n");
00242 return TEST_ERR_USAGE;
00243 }
00244
00245 hd_src = fopen(libtest_arg2, "rb");
00246 if(NULL == hd_src) {
00247 error = ERRNO;
00248 fprintf(stderr, "fopen() failed with error: %d (%s)\n",
00249 error, strerror(error));
00250 fprintf(stderr, "Error opening file: (%s)\n", libtest_arg2);
00251 return TEST_ERR_FOPEN;
00252 }
00253
00254
00255 hd = fstat(fileno(hd_src), &file_info);
00256 if(hd == -1) {
00257
00258 error = ERRNO;
00259 fprintf(stderr, "fstat() failed with error: %d (%s)\n",
00260 error, strerror(error));
00261 fprintf(stderr, "ERROR: cannot open file (%s)\n", libtest_arg2);
00262 fclose(hd_src);
00263 return TEST_ERR_FSTAT;
00264 }
00265 fprintf(stderr, "Set to upload %d bytes\n", (int)file_info.st_size);
00266
00267 res_global_init(CURL_GLOBAL_ALL);
00268 if(res) {
00269 fclose(hd_src);
00270 return res;
00271 }
00272
00273 easy_init(curl);
00274
00275
00276 easy_setopt(curl, CURLOPT_UPLOAD, 1L);
00277
00278
00279 easy_setopt(curl, CURLOPT_URL, URL);
00280
00281
00282 easy_setopt(curl, CURLOPT_VERBOSE, 1L);
00283
00284
00285 easy_setopt(curl, CURLOPT_READDATA, hd_src);
00286
00287 easy_setopt(curl, CURLOPT_USERPWD, libtest_arg3);
00288 easy_setopt(curl, CURLOPT_SSH_PUBLIC_KEYFILE, "curl_client_key.pub");
00289 easy_setopt(curl, CURLOPT_SSH_PRIVATE_KEYFILE, "curl_client_key");
00290
00291 easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)file_info.st_size);
00292
00293 multi_init(m);
00294
00295 multi_setopt(m, CURLMOPT_SOCKETFUNCTION, curlSocketCallback);
00296 multi_setopt(m, CURLMOPT_SOCKETDATA, &sockets);
00297
00298 multi_setopt(m, CURLMOPT_TIMERFUNCTION, curlTimerCallback);
00299 multi_setopt(m, CURLMOPT_TIMERDATA, &timeout);
00300
00301 multi_add_handle(m, curl);
00302
00303 while(!checkForCompletion(m, &success)) {
00304 fd_set readSet, writeSet;
00305 curl_socket_t maxFd = 0;
00306 struct timeval tv = {10, 0};
00307
00308 FD_ZERO(&readSet);
00309 FD_ZERO(&writeSet);
00310 updateFdSet(&sockets.read, &readSet, &maxFd);
00311 updateFdSet(&sockets.write, &writeSet, &maxFd);
00312
00313 if(timeout.tv_sec != -1) {
00314 int usTimeout = getMicroSecondTimeout(&timeout);
00315 tv.tv_sec = usTimeout / 1000000;
00316 tv.tv_usec = usTimeout % 1000000;
00317 }
00318 else if(maxFd <= 0) {
00319 tv.tv_sec = 0;
00320 tv.tv_usec = 100000;
00321 }
00322
00323 select_test(maxFd, &readSet, &writeSet, NULL, &tv);
00324
00325
00326 checkFdSet(m, &sockets.read, &readSet, CURL_CSELECT_IN, "read");
00327 checkFdSet(m, &sockets.write, &writeSet, CURL_CSELECT_OUT, "write");
00328
00329 if(timeout.tv_sec != -1 && getMicroSecondTimeout(&timeout) == 0) {
00330
00331 notifyCurl(m, CURL_SOCKET_TIMEOUT, 0, "timeout");
00332 }
00333
00334 abort_on_test_timeout();
00335 }
00336
00337 if(!success) {
00338 fprintf(stderr, "Error uploading file.\n");
00339 res = TEST_ERR_MAJOR_BAD;
00340 }
00341
00342 test_cleanup:
00343
00344
00345
00346 curl_multi_remove_handle(m, curl);
00347 curl_easy_cleanup(curl);
00348 curl_multi_cleanup(m);
00349 curl_global_cleanup();
00350
00351
00352 fclose(hd_src);
00353
00354
00355 free(sockets.read.sockets);
00356 free(sockets.write.sockets);
00357
00358 return res;
00359 }