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