VirtualBox

source: vbox/trunk/src/libs/curl-8.7.1/lib/pingpong.c@ 106542

最後變更 在這個檔案從106542是 104083,由 vboxsync 提交於 11 月 前

curl-8.7.1: Applied and adjusted our curl changes to 8.4.0. bugref:10639

  • 屬性 svn:eol-style 設為 native
檔案大小: 12.2 KB
 
1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) Daniel Stenberg, <[email protected]>, 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 * 'pingpong' is for generic back-and-forth support functions used by FTP,
24 * IMAP, POP3, SMTP and whatever more that likes them.
25 *
26 ***************************************************************************/
27
28#include "curl_setup.h"
29
30#include "urldata.h"
31#include "cfilters.h"
32#include "sendf.h"
33#include "select.h"
34#include "progress.h"
35#include "speedcheck.h"
36#include "pingpong.h"
37#include "multiif.h"
38#include "vtls/vtls.h"
39#include "strdup.h"
40
41/* The last 3 #include files should be in this order */
42#include "curl_printf.h"
43#include "curl_memory.h"
44#include "memdebug.h"
45
46#ifdef USE_PINGPONG
47
48/* Returns timeout in ms. 0 or negative number means the timeout has already
49 triggered */
50timediff_t Curl_pp_state_timeout(struct Curl_easy *data,
51 struct pingpong *pp, bool disconnecting)
52{
53 struct connectdata *conn = data->conn;
54 timediff_t timeout_ms; /* in milliseconds */
55 timediff_t response_time = (data->set.server_response_timeout)?
56 data->set.server_response_timeout: pp->response_time;
57
58 /* if CURLOPT_SERVER_RESPONSE_TIMEOUT is set, use that to determine
59 remaining time, or use pp->response because SERVER_RESPONSE_TIMEOUT is
60 supposed to govern the response for any given server response, not for
61 the time from connect to the given server response. */
62
63 /* Without a requested timeout, we only wait 'response_time' seconds for the
64 full response to arrive before we bail out */
65 timeout_ms = response_time -
66 Curl_timediff(Curl_now(), pp->response); /* spent time */
67
68 if(data->set.timeout && !disconnecting) {
69 /* if timeout is requested, find out how much remaining time we have */
70 timediff_t timeout2_ms = data->set.timeout - /* timeout time */
71 Curl_timediff(Curl_now(), conn->now); /* spent time */
72
73 /* pick the lowest number */
74 timeout_ms = CURLMIN(timeout_ms, timeout2_ms);
75 }
76
77 return timeout_ms;
78}
79
80/*
81 * Curl_pp_statemach()
82 */
83CURLcode Curl_pp_statemach(struct Curl_easy *data,
84 struct pingpong *pp, bool block,
85 bool disconnecting)
86{
87 struct connectdata *conn = data->conn;
88 curl_socket_t sock = conn->sock[FIRSTSOCKET];
89 int rc;
90 timediff_t interval_ms;
91 timediff_t timeout_ms = Curl_pp_state_timeout(data, pp, disconnecting);
92 CURLcode result = CURLE_OK;
93
94 if(timeout_ms <= 0) {
95 failf(data, "server response timeout");
96 return CURLE_OPERATION_TIMEDOUT; /* already too little time */
97 }
98
99 if(block) {
100 interval_ms = 1000; /* use 1 second timeout intervals */
101 if(timeout_ms < interval_ms)
102 interval_ms = timeout_ms;
103 }
104 else
105 interval_ms = 0; /* immediate */
106
107 if(Curl_conn_data_pending(data, FIRSTSOCKET))
108 rc = 1;
109 else if(pp->overflow)
110 /* We are receiving and there is data in the cache so just read it */
111 rc = 1;
112 else if(!pp->sendleft && Curl_conn_data_pending(data, FIRSTSOCKET))
113 /* We are receiving and there is data ready in the SSL library */
114 rc = 1;
115 else
116 rc = Curl_socket_check(pp->sendleft?CURL_SOCKET_BAD:sock, /* reading */
117 CURL_SOCKET_BAD,
118 pp->sendleft?sock:CURL_SOCKET_BAD, /* writing */
119 interval_ms);
120
121 if(block) {
122 /* if we didn't wait, we don't have to spend time on this now */
123 if(Curl_pgrsUpdate(data))
124 result = CURLE_ABORTED_BY_CALLBACK;
125 else
126 result = Curl_speedcheck(data, Curl_now());
127
128 if(result)
129 return result;
130 }
131
132 if(rc == -1) {
133 failf(data, "select/poll error");
134 result = CURLE_OUT_OF_MEMORY;
135 }
136 else if(rc)
137 result = pp->statemachine(data, data->conn);
138
139 return result;
140}
141
142/* initialize stuff to prepare for reading a fresh new response */
143void Curl_pp_init(struct pingpong *pp)
144{
145 pp->nread_resp = 0;
146 pp->response = Curl_now(); /* start response time-out now! */
147 pp->pending_resp = TRUE;
148 Curl_dyn_init(&pp->sendbuf, DYN_PINGPPONG_CMD);
149 Curl_dyn_init(&pp->recvbuf, DYN_PINGPPONG_CMD);
150}
151
152/***********************************************************************
153 *
154 * Curl_pp_vsendf()
155 *
156 * Send the formatted string as a command to a pingpong server. Note that
157 * the string should not have any CRLF appended, as this function will
158 * append the necessary things itself.
159 *
160 * made to never block
161 */
162CURLcode Curl_pp_vsendf(struct Curl_easy *data,
163 struct pingpong *pp,
164 const char *fmt,
165 va_list args)
166{
167 size_t bytes_written = 0;
168 size_t write_len;
169 char *s;
170 CURLcode result;
171 struct connectdata *conn = data->conn;
172
173#ifdef HAVE_GSSAPI
174 enum protection_level data_sec;
175#endif
176
177 DEBUGASSERT(pp->sendleft == 0);
178 DEBUGASSERT(pp->sendsize == 0);
179 DEBUGASSERT(pp->sendthis == NULL);
180
181 if(!conn)
182 /* can't send without a connection! */
183 return CURLE_SEND_ERROR;
184
185 Curl_dyn_reset(&pp->sendbuf);
186 result = Curl_dyn_vaddf(&pp->sendbuf, fmt, args);
187 if(result)
188 return result;
189
190 /* append CRLF */
191 result = Curl_dyn_addn(&pp->sendbuf, "\r\n", 2);
192 if(result)
193 return result;
194
195 pp->pending_resp = TRUE;
196 write_len = Curl_dyn_len(&pp->sendbuf);
197 s = Curl_dyn_ptr(&pp->sendbuf);
198
199#ifdef HAVE_GSSAPI
200 conn->data_prot = PROT_CMD;
201#endif
202 result = Curl_conn_send(data, FIRSTSOCKET, s, write_len, &bytes_written);
203 if(result == CURLE_AGAIN) {
204 bytes_written = 0;
205 }
206 else if(result)
207 return result;
208#ifdef HAVE_GSSAPI
209 data_sec = conn->data_prot;
210 DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
211 conn->data_prot = (unsigned char)data_sec;
212#endif
213
214 Curl_debug(data, CURLINFO_HEADER_OUT, s, bytes_written);
215
216 if(bytes_written != write_len) {
217 /* the whole chunk was not sent, keep it around and adjust sizes */
218 pp->sendthis = s;
219 pp->sendsize = write_len;
220 pp->sendleft = write_len - bytes_written;
221 }
222 else {
223 pp->sendthis = NULL;
224 pp->sendleft = pp->sendsize = 0;
225 pp->response = Curl_now();
226 }
227
228 return CURLE_OK;
229}
230
231
232/***********************************************************************
233 *
234 * Curl_pp_sendf()
235 *
236 * Send the formatted string as a command to a pingpong server. Note that
237 * the string should not have any CRLF appended, as this function will
238 * append the necessary things itself.
239 *
240 * made to never block
241 */
242CURLcode Curl_pp_sendf(struct Curl_easy *data, struct pingpong *pp,
243 const char *fmt, ...)
244{
245 CURLcode result;
246 va_list ap;
247 va_start(ap, fmt);
248
249 result = Curl_pp_vsendf(data, pp, fmt, ap);
250
251 va_end(ap);
252
253 return result;
254}
255
256static CURLcode pingpong_read(struct Curl_easy *data,
257 int sockindex,
258 char *buffer,
259 size_t buflen,
260 ssize_t *nread)
261{
262 CURLcode result;
263#ifdef HAVE_GSSAPI
264 enum protection_level prot = data->conn->data_prot;
265 data->conn->data_prot = PROT_CLEAR;
266#endif
267 result = Curl_conn_recv(data, sockindex, buffer, buflen, nread);
268#ifdef HAVE_GSSAPI
269 DEBUGASSERT(prot > PROT_NONE && prot < PROT_LAST);
270 data->conn->data_prot = (unsigned char)prot;
271#endif
272 return result;
273}
274
275/*
276 * Curl_pp_readresp()
277 *
278 * Reads a piece of a server response.
279 */
280CURLcode Curl_pp_readresp(struct Curl_easy *data,
281 int sockindex,
282 struct pingpong *pp,
283 int *code, /* return the server code if done */
284 size_t *size) /* size of the response */
285{
286 struct connectdata *conn = data->conn;
287 CURLcode result = CURLE_OK;
288
289 *code = 0; /* 0 for errors or not done */
290 *size = 0;
291
292 if(pp->nfinal) {
293 /* a previous call left this many bytes in the beginning of the buffer as
294 that was the final line; now ditch that */
295 size_t full = Curl_dyn_len(&pp->recvbuf);
296
297 /* trim off the "final" leading part */
298 Curl_dyn_tail(&pp->recvbuf, full - pp->nfinal);
299
300 pp->nfinal = 0; /* now gone */
301 }
302 if(!pp->overflow) {
303 ssize_t gotbytes = 0;
304 char buffer[900];
305
306 result = pingpong_read(data, sockindex, buffer, sizeof(buffer), &gotbytes);
307 if(result == CURLE_AGAIN)
308 return CURLE_OK;
309
310 if(result)
311 return result;
312
313 if(gotbytes <= 0) {
314 failf(data, "response reading failed (errno: %d)", SOCKERRNO);
315 return CURLE_RECV_ERROR;
316 }
317
318 result = Curl_dyn_addn(&pp->recvbuf, buffer, gotbytes);
319 if(result)
320 return result;
321
322 data->req.headerbytecount += (unsigned int)gotbytes;
323
324 pp->nread_resp += gotbytes;
325 }
326
327 do {
328 char *line = Curl_dyn_ptr(&pp->recvbuf);
329 char *nl = memchr(line, '\n', Curl_dyn_len(&pp->recvbuf));
330 if(nl) {
331 /* a newline is CRLF in pp-talk, so the CR is ignored as
332 the line isn't really terminated until the LF comes */
333 size_t length = nl - line + 1;
334
335 /* output debug output if that is requested */
336#ifdef HAVE_GSSAPI
337 if(!conn->sec_complete)
338#endif
339 Curl_debug(data, CURLINFO_HEADER_IN, line, length);
340
341 /*
342 * Pass all response-lines to the callback function registered for
343 * "headers". The response lines can be seen as a kind of headers.
344 */
345 result = Curl_client_write(data, CLIENTWRITE_INFO, line, length);
346 if(result)
347 return result;
348
349 if(pp->endofresp(data, conn, line, length, code)) {
350 /* When at "end of response", keep the endofresp line first in the
351 buffer since it will be accessed outside (by pingpong
352 parsers). Store the overflow counter to inform about additional
353 data in this buffer after the endofresp line. */
354 pp->nfinal = length;
355 if(Curl_dyn_len(&pp->recvbuf) > length)
356 pp->overflow = Curl_dyn_len(&pp->recvbuf) - length;
357 else
358 pp->overflow = 0;
359 *size = pp->nread_resp; /* size of the response */
360 pp->nread_resp = 0; /* restart */
361 break;
362 }
363 if(Curl_dyn_len(&pp->recvbuf) > length)
364 /* keep the remaining piece */
365 Curl_dyn_tail((&pp->recvbuf), Curl_dyn_len(&pp->recvbuf) - length);
366 else
367 Curl_dyn_reset(&pp->recvbuf);
368 }
369 else {
370 /* without a newline, there is no overflow */
371 pp->overflow = 0;
372 break;
373 }
374
375 } while(1); /* while there's buffer left to scan */
376
377 pp->pending_resp = FALSE;
378
379 return result;
380}
381
382int Curl_pp_getsock(struct Curl_easy *data,
383 struct pingpong *pp, curl_socket_t *socks)
384{
385 struct connectdata *conn = data->conn;
386 socks[0] = conn->sock[FIRSTSOCKET];
387
388 if(pp->sendleft) {
389 /* write mode */
390 return GETSOCK_WRITESOCK(0);
391 }
392
393 /* read mode */
394 return GETSOCK_READSOCK(0);
395}
396
397CURLcode Curl_pp_flushsend(struct Curl_easy *data,
398 struct pingpong *pp)
399{
400 /* we have a piece of a command still left to send */
401 size_t written;
402 CURLcode result;
403
404 result = Curl_conn_send(data, FIRSTSOCKET,
405 pp->sendthis + pp->sendsize - pp->sendleft,
406 pp->sendleft, &written);
407 if(result == CURLE_AGAIN) {
408 result = CURLE_OK;
409 written = 0;
410 }
411 if(result)
412 return result;
413
414 if(written != pp->sendleft) {
415 /* only a fraction was sent */
416 pp->sendleft -= written;
417 }
418 else {
419 pp->sendthis = NULL;
420 pp->sendleft = pp->sendsize = 0;
421 pp->response = Curl_now();
422 }
423 return CURLE_OK;
424}
425
426CURLcode Curl_pp_disconnect(struct pingpong *pp)
427{
428 Curl_dyn_free(&pp->sendbuf);
429 Curl_dyn_free(&pp->recvbuf);
430 return CURLE_OK;
431}
432
433bool Curl_pp_moredata(struct pingpong *pp)
434{
435 return (!pp->sendleft && Curl_dyn_len(&pp->recvbuf) > pp->nfinal);
436}
437
438#endif
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette