File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / tests / libtest / lib582.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 10:01:16 2020 UTC (5 years ago) by misho
Branches: curl, MAIN
CVS tags: v7_70_0p4, HEAD
curl

    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: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>