lib582.c
Go to the documentation of this file.
1 /***************************************************************************
2  * _ _ ____ _
3  * Project ___| | | | _ \| |
4  * / __| | | | |_) | |
5  * | (__| |_| | _ <| |___
6  * \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2016, 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 {
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 
40 {
41  struct Sockets read, write;
42 };
43 
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 
67 static void addFd(struct Sockets* sockets, curl_socket_t fd, const char *what)
68 {
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 
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 
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 
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 
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 
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 
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 
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 
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 
288  easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)file_info.st_size);
289 
290  multi_init(m);
291 
292  multi_setopt(m, CURLMOPT_SOCKETFUNCTION, curlSocketCallback);
293  multi_setopt(m, CURLMOPT_SOCKETDATA, &sockets);
294 
295  multi_setopt(m, CURLMOPT_TIMERFUNCTION, curlTimerCallback);
296  multi_setopt(m, CURLMOPT_TIMERDATA, &timeout);
297 
298  multi_add_handle(m, curl);
299 
300  while(!checkForCompletion(m, &success)) {
301  fd_set readSet, writeSet;
302  curl_socket_t maxFd = 0;
303  struct timeval tv = {10, 0};
304 
305  FD_ZERO(&readSet);
306  FD_ZERO(&writeSet);
307  updateFdSet(&sockets.read, &readSet, &maxFd);
308  updateFdSet(&sockets.write, &writeSet, &maxFd);
309 
310  if(timeout.tv_sec != -1) {
311  int usTimeout = getMicroSecondTimeout(&timeout);
312  tv.tv_sec = usTimeout / 1000000;
313  tv.tv_usec = usTimeout % 1000000;
314  }
315  else if(maxFd <= 0) {
316  tv.tv_sec = 0;
317  tv.tv_usec = 100000;
318  }
319 
320  select_test((int)maxFd, &readSet, &writeSet, NULL, &tv);
321 
322  /* Check the sockets for reading / writing */
323  checkFdSet(m, &sockets.read, &readSet, CURL_CSELECT_IN, "read");
324  checkFdSet(m, &sockets.write, &writeSet, CURL_CSELECT_OUT, "write");
325 
326  if(timeout.tv_sec != -1 && getMicroSecondTimeout(&timeout) == 0) {
327  /* Curl's timer has elapsed. */
328  notifyCurl(m, CURL_SOCKET_TIMEOUT, 0, "timeout");
329  }
330 
332  }
333 
334  if(!success) {
335  fprintf(stderr, "Error uploading file.\n");
336  res = TEST_ERR_MAJOR_BAD;
337  }
338 
339 test_cleanup:
340 
341  /* proper cleanup sequence - type PB */
342 
343  curl_multi_remove_handle(m, curl);
344  curl_easy_cleanup(curl);
347 
348  /* close the local file */
349  fclose(hd_src);
350 
351  /* free local memory */
352  free(sockets.read.sockets);
353  free(sockets.write.sockets);
354 
355  return res;
356 }
#define free(ptr)
Definition: curl_memory.h:130
#define select_test(A, B, C, D, E)
Definition: test.h:378
#define CURL_CSELECT_OUT
Definition: multi.h:265
static int curlSocketCallback(CURL *easy, curl_socket_t s, int action, void *userp, void *socketp)
Callback invoked by curl to poll reading / writing of a socket.
Definition: lib582.c:105
#define res_global_init(A)
Definition: test.h:419
static void updateFdSet(struct Sockets *sockets, fd_set *fdset, curl_socket_t *maxFd)
Update a fd_set with all of the sockets in use.
Definition: lib582.c:188
static void addFd(struct Sockets *sockets, curl_socket_t fd, const char *what)
Add a file descriptor to a sockets array.
Definition: lib582.c:67
#define easy_setopt(A, B, C)
Definition: test.h:190
uv_timer_t timeout
Definition: multi-uv.c:42
#define multi_add_handle(A, B)
Definition: test.h:238
Definition: multi.h:93
curl_socket_t * sockets
Definition: lib582.c:34
struct Sockets read write
Definition: lib582.c:41
static int res
#define realloc(ptr, size)
Definition: curl_memory.h:128
#define malloc(size)
Definition: curl_memory.h:124
CURL_EXTERN const char * curl_multi_strerror(CURLMcode)
Definition: strerror.c:352
#define CURL_POLL_OUT
Definition: multi.h:258
UNITTEST_START int result
Definition: unit1304.c:49
unsigned int i
Definition: unit1303.c:79
#define abort_on_test_timeout()
Definition: test.h:404
#define TEST_ERR_MAJOR_BAD
Definition: test.h:85
char * libtest_arg2
Definition: first.c:75
#define TEST_ERR_FSTAT
Definition: test.h:95
int test(char *URL)
Definition: lib582.c:225
#define CURL_CSELECT_IN
Definition: multi.h:264
#define CURL_POLL_REMOVE
Definition: multi.h:260
#define easy_init(A)
Definition: test.h:145
#define multi_setopt(A, B, C)
Definition: test.h:214
#define CURL_POLL_IN
Definition: multi.h:257
CURLMSG msg
Definition: multi.h:94
CURL_EXTERN void curl_easy_cleanup(CURL *curl)
CURL_TYPEOF_CURL_OFF_T curl_off_t
Definition: system.h:420
Definition: curl.h:455
#define TEST_ERR_USAGE
Definition: test.h:93
CURL_EXTERN CURLMcode curl_multi_remove_handle(CURLM *multi_handle, CURL *curl_handle)
#define multi_init(A)
Definition: test.h:166
static void removeFd(struct Sockets *sockets, curl_socket_t fd, int mention)
Remove a file descriptor from a sockets array.
Definition: lib582.c:47
CURLMcode
Definition: multi.h:61
#define TEST_ERR_FOPEN
Definition: test.h:94
char * libtest_arg3
Definition: first.c:76
static int curlTimerCallback(CURLM *multi, long timeout_ms, void *userp)
Callback invoked by curl to set a timeout.
Definition: lib582.c:130
#define CURL_SOCKET_TIMEOUT
Definition: multi.h:262
#define ssize_t
Definition: config-win32.h:382
int count
Definition: lib582.c:35
Definition: lib582.c:32
int curlx_sztosi(ssize_t sznum)
Definition: warnless.c:366
void CURLM
Definition: multi.h:58
void CURL
Definition: curl.h:102
CURL_EXTERN CURLMsg * curl_multi_info_read(CURLM *multi_handle, int *msgs_in_queue)
static int getMicroSecondTimeout(struct timeval *timeout)
Definition: lib582.c:172
Definition: multi.h:64
union CURLMsg::@6 data
#define fprintf
Definition: curl_printf.h:41
static CURL * easy[MAX_EASY_HANDLES]
CURL_EXTERN void curl_global_cleanup(void)
curl_global_cleanup() globally cleanups curl, uses the value of "init_flags" to determine what needs ...
Definition: easy.c:312
#define CURL_GLOBAL_ALL
Definition: curl.h:2519
int fileno(FILE *stream)
static void notifyCurl(CURLM *curl, curl_socket_t s, int evBitmask, const char *info)
Definition: lib582.c:200
static int checkForCompletion(CURLM *curl, int *success)
Check for curl completion.
Definition: lib582.c:148
#define CURL_POLL_INOUT
Definition: multi.h:259
CURLcode result
Definition: multi.h:98
int curl_socket_t
Definition: curl.h:130
const char * name
Definition: curl_sasl.c:54
static CURL * curl
Definition: sessioninfo.c:35
#define start_test_timing()
Definition: test.h:383
int max_count
Definition: lib582.c:36
static void checkFdSet(CURLM *curl, struct Sockets *sockets, fd_set *fdset, int evBitmask, const char *name)
Invoke curl when a file descriptor is set.
Definition: lib582.c:214
CURL_EXTERN CURLMcode curl_multi_socket_action(CURLM *multi_handle, curl_socket_t s, int ev_bitmask, int *running_handles)
CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle)
#define struct_stat
Definition: curl_setup.h:385
struct timeval tutil_tvnow(void)
Definition: testutil.c:93


rc_tagdetect_client
Author(s): Monika Florek-Jasinska , Raphael Schaller
autogenerated on Sat Feb 13 2021 03:42:15