xref: /aosp_15_r20/external/curl/lib/pingpong.c (revision 6236dae45794135f37c4eb022389c904c8b0090d)
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