Return to lib582.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / tests / libtest |
1.1 ! misho 1: /*************************************************************************** ! 2: * _ _ ____ _ ! 3: * Project ___| | | | _ \| | ! 4: * / __| | | | |_) | | ! 5: * | (__| |_| | _ <| |___ ! 6: * \___|\___/|_| \_\_____| ! 7: * ! 8: * Copyright (C) 1998 - 2020, 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.haxx.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: ***************************************************************************/ ! 22: #include "test.h" ! 23: ! 24: #include <fcntl.h> ! 25: ! 26: #include "testutil.h" ! 27: #include "warnless.h" ! 28: #include "memdebug.h" ! 29: ! 30: #define TEST_HANG_TIMEOUT 60 * 1000 ! 31: ! 32: struct Sockets ! 33: { ! 34: curl_socket_t *sockets; ! 35: int count; /* number of sockets actually stored in array */ ! 36: int max_count; /* max number of sockets that fit in allocated array */ ! 37: }; ! 38: ! 39: struct ReadWriteSockets ! 40: { ! 41: struct Sockets read, write; ! 42: }; ! 43: ! 44: /** ! 45: * Remove a file descriptor from a sockets array. ! 46: */ ! 47: static void removeFd(struct Sockets* sockets, curl_socket_t fd, int mention) ! 48: { ! 49: int i; ! 50: ! 51: if(mention) ! 52: fprintf(stderr, "Remove socket fd %d\n", (int) fd); ! 53: ! 54: for(i = 0; i < sockets->count; ++i) { ! 55: if(sockets->sockets[i] == fd) { ! 56: if(i < sockets->count - 1) ! 57: memmove(&sockets->sockets[i], &sockets->sockets[i + 1], ! 58: sizeof(curl_socket_t) * (sockets->count - (i + 1))); ! 59: --sockets->count; ! 60: } ! 61: } ! 62: } ! 63: ! 64: /** ! 65: * Add a file descriptor to a sockets array. ! 66: */ ! 67: static void addFd(struct Sockets* sockets, curl_socket_t fd, const char *what) ! 68: { ! 69: /** ! 70: * To ensure we only have each file descriptor once, we remove it then add ! 71: * it again. ! 72: */ ! 73: fprintf(stderr, "Add socket fd %d for %s\n", (int) fd, what); ! 74: removeFd(sockets, fd, 0); ! 75: /* ! 76: * Allocate array storage when required. ! 77: */ ! 78: if(!sockets->sockets) { ! 79: sockets->sockets = malloc(sizeof(curl_socket_t) * 20U); ! 80: if(!sockets->sockets) ! 81: return; ! 82: sockets->max_count = 20; ! 83: } ! 84: else if(sockets->count + 1 > sockets->max_count) { ! 85: curl_socket_t *oldptr = sockets->sockets; ! 86: sockets->sockets = realloc(oldptr, sizeof(curl_socket_t) * ! 87: (sockets->max_count + 20)); ! 88: if(!sockets->sockets) { ! 89: /* cleanup in test_cleanup */ ! 90: sockets->sockets = oldptr; ! 91: return; ! 92: } ! 93: sockets->max_count += 20; ! 94: } ! 95: /* ! 96: * Add file descriptor to array. ! 97: */ ! 98: sockets->sockets[sockets->count] = fd; ! 99: ++sockets->count; ! 100: } ! 101: ! 102: /** ! 103: * Callback invoked by curl to poll reading / writing of a socket. ! 104: */ ! 105: static int curlSocketCallback(CURL *easy, curl_socket_t s, int action, ! 106: void *userp, void *socketp) ! 107: { ! 108: struct ReadWriteSockets* sockets = userp; ! 109: ! 110: (void)easy; /* unused */ ! 111: (void)socketp; /* unused */ ! 112: ! 113: if(action == CURL_POLL_IN || action == CURL_POLL_INOUT) ! 114: addFd(&sockets->read, s, "read"); ! 115: ! 116: if(action == CURL_POLL_OUT || action == CURL_POLL_INOUT) ! 117: addFd(&sockets->write, s, "write"); ! 118: ! 119: if(action == CURL_POLL_REMOVE) { ! 120: removeFd(&sockets->read, s, 1); ! 121: removeFd(&sockets->write, s, 0); ! 122: } ! 123: ! 124: return 0; ! 125: } ! 126: ! 127: /** ! 128: * Callback invoked by curl to set a timeout. ! 129: */ ! 130: static int curlTimerCallback(CURLM *multi, long timeout_ms, void *userp) ! 131: { ! 132: struct timeval* timeout = userp; ! 133: ! 134: (void)multi; /* unused */ ! 135: if(timeout_ms != -1) { ! 136: *timeout = tutil_tvnow(); ! 137: timeout->tv_usec += timeout_ms * 1000; ! 138: } ! 139: else { ! 140: timeout->tv_sec = -1; ! 141: } ! 142: return 0; ! 143: } ! 144: ! 145: /** ! 146: * Check for curl completion. ! 147: */ ! 148: static int checkForCompletion(CURLM *curl, int *success) ! 149: { ! 150: int numMessages; ! 151: CURLMsg *message; ! 152: int result = 0; ! 153: *success = 0; ! 154: while((message = curl_multi_info_read(curl, &numMessages)) != NULL) { ! 155: if(message->msg == CURLMSG_DONE) { ! 156: result = 1; ! 157: if(message->data.result == CURLE_OK) ! 158: *success = 1; ! 159: else ! 160: *success = 0; ! 161: } ! 162: else { ! 163: fprintf(stderr, "Got an unexpected message from curl: %i\n", ! 164: (int)message->msg); ! 165: result = 1; ! 166: *success = 0; ! 167: } ! 168: } ! 169: return result; ! 170: } ! 171: ! 172: static int getMicroSecondTimeout(struct timeval* timeout) ! 173: { ! 174: struct timeval now; ! 175: ssize_t result; ! 176: now = tutil_tvnow(); ! 177: result = (ssize_t)((timeout->tv_sec - now.tv_sec) * 1000000 + ! 178: timeout->tv_usec - now.tv_usec); ! 179: if(result < 0) ! 180: result = 0; ! 181: ! 182: return curlx_sztosi(result); ! 183: } ! 184: ! 185: /** ! 186: * Update a fd_set with all of the sockets in use. ! 187: */ ! 188: static void updateFdSet(struct Sockets* sockets, fd_set* fdset, ! 189: curl_socket_t *maxFd) ! 190: { ! 191: int i; ! 192: for(i = 0; i < sockets->count; ++i) { ! 193: FD_SET(sockets->sockets[i], fdset); ! 194: if(*maxFd < sockets->sockets[i] + 1) { ! 195: *maxFd = sockets->sockets[i] + 1; ! 196: } ! 197: } ! 198: } ! 199: ! 200: static void notifyCurl(CURLM *curl, curl_socket_t s, int evBitmask, ! 201: const char *info) ! 202: { ! 203: int numhandles = 0; ! 204: CURLMcode result = curl_multi_socket_action(curl, s, evBitmask, &numhandles); ! 205: if(result != CURLM_OK) { ! 206: fprintf(stderr, "Curl error on %s: %i (%s)\n", ! 207: info, result, curl_multi_strerror(result)); ! 208: } ! 209: } ! 210: ! 211: /** ! 212: * Invoke curl when a file descriptor is set. ! 213: */ ! 214: static void checkFdSet(CURLM *curl, struct Sockets *sockets, fd_set *fdset, ! 215: int evBitmask, const char *name) ! 216: { ! 217: int i; ! 218: for(i = 0; i < sockets->count; ++i) { ! 219: if(FD_ISSET(sockets->sockets[i], fdset)) { ! 220: notifyCurl(curl, sockets->sockets[i], evBitmask, name); ! 221: } ! 222: } ! 223: } ! 224: ! 225: int test(char *URL) ! 226: { ! 227: int res = 0; ! 228: CURL *curl = NULL; ! 229: FILE *hd_src = NULL; ! 230: int hd; ! 231: struct_stat file_info; ! 232: CURLM *m = NULL; ! 233: struct ReadWriteSockets sockets = {{NULL, 0, 0}, {NULL, 0, 0}}; ! 234: struct timeval timeout = {-1, 0}; ! 235: int success = 0; ! 236: ! 237: start_test_timing(); ! 238: ! 239: if(!libtest_arg3) { ! 240: fprintf(stderr, "Usage: lib582 [url] [filename] [username]\n"); ! 241: return TEST_ERR_USAGE; ! 242: } ! 243: ! 244: hd_src = fopen(libtest_arg2, "rb"); ! 245: if(NULL == hd_src) { ! 246: fprintf(stderr, "fopen() failed with error: %d (%s)\n", ! 247: errno, strerror(errno)); ! 248: fprintf(stderr, "Error opening file: (%s)\n", libtest_arg2); ! 249: return TEST_ERR_FOPEN; ! 250: } ! 251: ! 252: /* get the file size of the local file */ ! 253: hd = fstat(fileno(hd_src), &file_info); ! 254: if(hd == -1) { ! 255: /* can't open file, bail out */ ! 256: fprintf(stderr, "fstat() failed with error: %d (%s)\n", ! 257: errno, strerror(errno)); ! 258: fprintf(stderr, "ERROR: cannot open file (%s)\n", libtest_arg2); ! 259: fclose(hd_src); ! 260: return TEST_ERR_FSTAT; ! 261: } ! 262: fprintf(stderr, "Set to upload %d bytes\n", (int)file_info.st_size); ! 263: ! 264: res_global_init(CURL_GLOBAL_ALL); ! 265: if(res) { ! 266: fclose(hd_src); ! 267: return res; ! 268: } ! 269: ! 270: easy_init(curl); ! 271: ! 272: /* enable uploading */ ! 273: easy_setopt(curl, CURLOPT_UPLOAD, 1L); ! 274: ! 275: /* specify target */ ! 276: easy_setopt(curl, CURLOPT_URL, URL); ! 277: ! 278: /* go verbose */ ! 279: easy_setopt(curl, CURLOPT_VERBOSE, 1L); ! 280: ! 281: /* now specify which file to upload */ ! 282: easy_setopt(curl, CURLOPT_READDATA, hd_src); ! 283: ! 284: easy_setopt(curl, CURLOPT_USERPWD, libtest_arg3); ! 285: easy_setopt(curl, CURLOPT_SSH_PUBLIC_KEYFILE, "curl_client_key.pub"); ! 286: easy_setopt(curl, CURLOPT_SSH_PRIVATE_KEYFILE, "curl_client_key"); ! 287: easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); ! 288: ! 289: easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)file_info.st_size); ! 290: ! 291: multi_init(m); ! 292: ! 293: multi_setopt(m, CURLMOPT_SOCKETFUNCTION, curlSocketCallback); ! 294: multi_setopt(m, CURLMOPT_SOCKETDATA, &sockets); ! 295: ! 296: multi_setopt(m, CURLMOPT_TIMERFUNCTION, curlTimerCallback); ! 297: multi_setopt(m, CURLMOPT_TIMERDATA, &timeout); ! 298: ! 299: multi_add_handle(m, curl); ! 300: ! 301: while(!checkForCompletion(m, &success)) { ! 302: fd_set readSet, writeSet; ! 303: curl_socket_t maxFd = 0; ! 304: struct timeval tv = {10, 0}; ! 305: ! 306: FD_ZERO(&readSet); ! 307: FD_ZERO(&writeSet); ! 308: updateFdSet(&sockets.read, &readSet, &maxFd); ! 309: updateFdSet(&sockets.write, &writeSet, &maxFd); ! 310: ! 311: if(timeout.tv_sec != -1) { ! 312: int usTimeout = getMicroSecondTimeout(&timeout); ! 313: tv.tv_sec = usTimeout / 1000000; ! 314: tv.tv_usec = usTimeout % 1000000; ! 315: } ! 316: else if(maxFd <= 0) { ! 317: tv.tv_sec = 0; ! 318: tv.tv_usec = 100000; ! 319: } ! 320: ! 321: select_test((int)maxFd, &readSet, &writeSet, NULL, &tv); ! 322: ! 323: /* Check the sockets for reading / writing */ ! 324: checkFdSet(m, &sockets.read, &readSet, CURL_CSELECT_IN, "read"); ! 325: checkFdSet(m, &sockets.write, &writeSet, CURL_CSELECT_OUT, "write"); ! 326: ! 327: if(timeout.tv_sec != -1 && getMicroSecondTimeout(&timeout) == 0) { ! 328: /* Curl's timer has elapsed. */ ! 329: notifyCurl(m, CURL_SOCKET_TIMEOUT, 0, "timeout"); ! 330: } ! 331: ! 332: abort_on_test_timeout(); ! 333: } ! 334: ! 335: if(!success) { ! 336: fprintf(stderr, "Error uploading file.\n"); ! 337: res = TEST_ERR_MAJOR_BAD; ! 338: } ! 339: ! 340: test_cleanup: ! 341: ! 342: /* proper cleanup sequence - type PB */ ! 343: ! 344: curl_multi_remove_handle(m, curl); ! 345: curl_easy_cleanup(curl); ! 346: curl_multi_cleanup(m); ! 347: curl_global_cleanup(); ! 348: ! 349: /* close the local file */ ! 350: fclose(hd_src); ! 351: ! 352: /* free local memory */ ! 353: free(sockets.read.sockets); ! 354: free(sockets.write.sockets); ! 355: ! 356: return res; ! 357: }