00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "curl_setup.h"
00027
00028 #include "urldata.h"
00029 #include "sendf.h"
00030 #include "select.h"
00031 #include "progress.h"
00032 #include "speedcheck.h"
00033 #include "pingpong.h"
00034 #include "multiif.h"
00035 #include "non-ascii.h"
00036 #include "vtls/vtls.h"
00037
00038
00039 #include "curl_printf.h"
00040 #include "curl_memory.h"
00041 #include "memdebug.h"
00042
00043 #ifdef USE_PINGPONG
00044
00045
00046
00047 time_t Curl_pp_state_timeout(struct pingpong *pp)
00048 {
00049 struct connectdata *conn = pp->conn;
00050 struct Curl_easy *data=conn->data;
00051 time_t timeout_ms;
00052 time_t timeout2_ms;
00053 long response_time= (data->set.server_response_timeout)?
00054 data->set.server_response_timeout: pp->response_time;
00055
00056
00057
00058
00059
00060
00061
00062
00063 timeout_ms = response_time -
00064 Curl_tvdiff(Curl_tvnow(), pp->response);
00065
00066 if(data->set.timeout) {
00067
00068 timeout2_ms = data->set.timeout -
00069 Curl_tvdiff(Curl_tvnow(), conn->now);
00070
00071
00072 timeout_ms = CURLMIN(timeout_ms, timeout2_ms);
00073 }
00074
00075 return timeout_ms;
00076 }
00077
00078
00079
00080
00081 CURLcode Curl_pp_statemach(struct pingpong *pp, bool block)
00082 {
00083 struct connectdata *conn = pp->conn;
00084 curl_socket_t sock = conn->sock[FIRSTSOCKET];
00085 int rc;
00086 time_t interval_ms;
00087 time_t timeout_ms = Curl_pp_state_timeout(pp);
00088 struct Curl_easy *data=conn->data;
00089 CURLcode result = CURLE_OK;
00090
00091 if(timeout_ms <=0) {
00092 failf(data, "server response timeout");
00093 return CURLE_OPERATION_TIMEDOUT;
00094 }
00095
00096 if(block) {
00097 interval_ms = 1000;
00098 if(timeout_ms < interval_ms)
00099 interval_ms = timeout_ms;
00100 }
00101 else
00102 interval_ms = 0;
00103
00104 if(Curl_ssl_data_pending(conn, FIRSTSOCKET))
00105 rc = 1;
00106 else if(Curl_pp_moredata(pp))
00107
00108 rc = 1;
00109 else if(!pp->sendleft && Curl_ssl_data_pending(conn, FIRSTSOCKET))
00110
00111 rc = 1;
00112 else
00113 rc = Curl_socket_check(pp->sendleft?CURL_SOCKET_BAD:sock,
00114 CURL_SOCKET_BAD,
00115 pp->sendleft?sock:CURL_SOCKET_BAD,
00116 interval_ms);
00117
00118 if(block) {
00119
00120 if(Curl_pgrsUpdate(conn))
00121 result = CURLE_ABORTED_BY_CALLBACK;
00122 else
00123 result = Curl_speedcheck(data, Curl_tvnow());
00124
00125 if(result)
00126 return result;
00127 }
00128
00129 if(rc == -1) {
00130 failf(data, "select/poll error");
00131 result = CURLE_OUT_OF_MEMORY;
00132 }
00133 else if(rc)
00134 result = pp->statemach_act(conn);
00135
00136 return result;
00137 }
00138
00139
00140 void Curl_pp_init(struct pingpong *pp)
00141 {
00142 struct connectdata *conn = pp->conn;
00143 pp->nread_resp = 0;
00144 pp->linestart_resp = conn->data->state.buffer;
00145 pp->pending_resp = TRUE;
00146 pp->response = Curl_tvnow();
00147 }
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161 CURLcode Curl_pp_vsendf(struct pingpong *pp,
00162 const char *fmt,
00163 va_list args)
00164 {
00165 ssize_t bytes_written;
00166 size_t write_len;
00167 char *fmt_crlf;
00168 char *s;
00169 CURLcode result;
00170 struct connectdata *conn = pp->conn;
00171 struct Curl_easy *data = conn->data;
00172
00173 #ifdef HAVE_GSSAPI
00174 enum protection_level data_sec = conn->data_prot;
00175 #endif
00176
00177 DEBUGASSERT(pp->sendleft == 0);
00178 DEBUGASSERT(pp->sendsize == 0);
00179 DEBUGASSERT(pp->sendthis == NULL);
00180
00181 fmt_crlf = aprintf("%s\r\n", fmt);
00182 if(!fmt_crlf)
00183 return CURLE_OUT_OF_MEMORY;
00184
00185 s = vaprintf(fmt_crlf, args);
00186 free(fmt_crlf);
00187 if(!s)
00188 return CURLE_OUT_OF_MEMORY;
00189
00190 bytes_written = 0;
00191 write_len = strlen(s);
00192
00193 Curl_pp_init(pp);
00194
00195 result = Curl_convert_to_network(data, s, write_len);
00196
00197 if(result) {
00198 free(s);
00199 return result;
00200 }
00201
00202 #ifdef HAVE_GSSAPI
00203 conn->data_prot = PROT_CMD;
00204 #endif
00205 result = Curl_write(conn, conn->sock[FIRSTSOCKET], s, write_len,
00206 &bytes_written);
00207 #ifdef HAVE_GSSAPI
00208 DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
00209 conn->data_prot = data_sec;
00210 #endif
00211
00212 if(result) {
00213 free(s);
00214 return result;
00215 }
00216
00217 if(conn->data->set.verbose)
00218 Curl_debug(conn->data, CURLINFO_HEADER_OUT,
00219 s, (size_t)bytes_written, conn);
00220
00221 if(bytes_written != (ssize_t)write_len) {
00222
00223 pp->sendthis = s;
00224 pp->sendsize = write_len;
00225 pp->sendleft = write_len - bytes_written;
00226 }
00227 else {
00228 free(s);
00229 pp->sendthis = NULL;
00230 pp->sendleft = pp->sendsize = 0;
00231 pp->response = Curl_tvnow();
00232 }
00233
00234 return CURLE_OK;
00235 }
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248 CURLcode Curl_pp_sendf(struct pingpong *pp,
00249 const char *fmt, ...)
00250 {
00251 CURLcode result;
00252 va_list ap;
00253 va_start(ap, fmt);
00254
00255 result = Curl_pp_vsendf(pp, fmt, ap);
00256
00257 va_end(ap);
00258
00259 return result;
00260 }
00261
00262
00263
00264
00265
00266
00267 CURLcode Curl_pp_readresp(curl_socket_t sockfd,
00268 struct pingpong *pp,
00269 int *code,
00270 size_t *size)
00271 {
00272 ssize_t perline;
00273 bool keepon=TRUE;
00274 ssize_t gotbytes;
00275 char *ptr;
00276 struct connectdata *conn = pp->conn;
00277 struct Curl_easy *data = conn->data;
00278 char * const buf = data->state.buffer;
00279 CURLcode result = CURLE_OK;
00280
00281 *code = 0;
00282 *size = 0;
00283
00284 ptr=buf + pp->nread_resp;
00285
00286
00287 perline = (ssize_t)(ptr-pp->linestart_resp);
00288
00289 while((pp->nread_resp<BUFSIZE) && (keepon && !result)) {
00290
00291 if(pp->cache) {
00292
00293
00294
00295
00296
00297
00298
00299 DEBUGASSERT((ptr+pp->cache_size) <= (buf+BUFSIZE+1));
00300 memcpy(ptr, pp->cache, pp->cache_size);
00301 gotbytes = (ssize_t)pp->cache_size;
00302 free(pp->cache);
00303 pp->cache = NULL;
00304 pp->cache_size = 0;
00305 }
00306 else {
00307 #ifdef HAVE_GSSAPI
00308 enum protection_level prot = conn->data_prot;
00309 conn->data_prot = PROT_CLEAR;
00310 #endif
00311 DEBUGASSERT((ptr+BUFSIZE-pp->nread_resp) <= (buf+BUFSIZE+1));
00312 result = Curl_read(conn, sockfd, ptr, BUFSIZE-pp->nread_resp,
00313 &gotbytes);
00314 #ifdef HAVE_GSSAPI
00315 DEBUGASSERT(prot > PROT_NONE && prot < PROT_LAST);
00316 conn->data_prot = prot;
00317 #endif
00318 if(result == CURLE_AGAIN)
00319 return CURLE_OK;
00320
00321 if(!result && (gotbytes > 0))
00322
00323 result = Curl_convert_from_network(data, ptr, gotbytes);
00324
00325
00326 if(result)
00327
00328 keepon = FALSE;
00329 }
00330
00331 if(!keepon)
00332 ;
00333 else if(gotbytes <= 0) {
00334 keepon = FALSE;
00335 result = CURLE_RECV_ERROR;
00336 failf(data, "response reading failed");
00337 }
00338 else {
00339
00340
00341
00342 ssize_t i;
00343 ssize_t clipamount = 0;
00344 bool restart = FALSE;
00345
00346 data->req.headerbytecount += (long)gotbytes;
00347
00348 pp->nread_resp += gotbytes;
00349 for(i = 0; i < gotbytes; ptr++, i++) {
00350 perline++;
00351 if(*ptr=='\n') {
00352
00353
00354
00355
00356 #ifdef HAVE_GSSAPI
00357 if(!conn->sec_complete)
00358 #endif
00359 if(data->set.verbose)
00360 Curl_debug(data, CURLINFO_HEADER_IN,
00361 pp->linestart_resp, (size_t)perline, conn);
00362
00363
00364
00365
00366
00367
00368 result = Curl_client_write(conn, CLIENTWRITE_HEADER,
00369 pp->linestart_resp, perline);
00370 if(result)
00371 return result;
00372
00373 if(pp->endofresp(conn, pp->linestart_resp, perline, code)) {
00374
00375
00376 size_t n = ptr - pp->linestart_resp;
00377 memmove(buf, pp->linestart_resp, n);
00378 buf[n]=0;
00379 keepon=FALSE;
00380 pp->linestart_resp = ptr+1;
00381 i++;
00382
00383 *size = pp->nread_resp;
00384 pp->nread_resp = 0;
00385 break;
00386 }
00387 perline=0;
00388 pp->linestart_resp = ptr+1;
00389 }
00390 }
00391
00392 if(!keepon && (i != gotbytes)) {
00393
00394
00395
00396
00397 clipamount = gotbytes - i;
00398 restart = TRUE;
00399 DEBUGF(infof(data, "Curl_pp_readresp_ %d bytes of trailing "
00400 "server response left\n",
00401 (int)clipamount));
00402 }
00403 else if(keepon) {
00404
00405 if((perline == gotbytes) && (gotbytes > BUFSIZE/2)) {
00406
00407
00408
00409 infof(data, "Excessive server response line length received, "
00410 "%zd bytes. Stripping\n", gotbytes);
00411 restart = TRUE;
00412
00413
00414
00415 clipamount = 40;
00416 }
00417 else if(pp->nread_resp > BUFSIZE/2) {
00418
00419
00420
00421 clipamount = perline;
00422 restart = TRUE;
00423 }
00424 }
00425 else if(i == gotbytes)
00426 restart = TRUE;
00427
00428 if(clipamount) {
00429 pp->cache_size = clipamount;
00430 pp->cache = malloc(pp->cache_size);
00431 if(pp->cache)
00432 memcpy(pp->cache, pp->linestart_resp, pp->cache_size);
00433 else
00434 return CURLE_OUT_OF_MEMORY;
00435 }
00436 if(restart) {
00437
00438
00439 pp->nread_resp = 0;
00440 ptr = pp->linestart_resp = buf;
00441 perline = 0;
00442 }
00443
00444 }
00445
00446 }
00447
00448 pp->pending_resp = FALSE;
00449
00450 return result;
00451 }
00452
00453 int Curl_pp_getsock(struct pingpong *pp,
00454 curl_socket_t *socks,
00455 int numsocks)
00456 {
00457 struct connectdata *conn = pp->conn;
00458
00459 if(!numsocks)
00460 return GETSOCK_BLANK;
00461
00462 socks[0] = conn->sock[FIRSTSOCKET];
00463
00464 if(pp->sendleft) {
00465
00466 return GETSOCK_WRITESOCK(0);
00467 }
00468
00469
00470 return GETSOCK_READSOCK(0);
00471 }
00472
00473 CURLcode Curl_pp_flushsend(struct pingpong *pp)
00474 {
00475
00476 struct connectdata *conn = pp->conn;
00477 ssize_t written;
00478 curl_socket_t sock = conn->sock[FIRSTSOCKET];
00479 CURLcode result = Curl_write(conn, sock, pp->sendthis + pp->sendsize -
00480 pp->sendleft, pp->sendleft, &written);
00481 if(result)
00482 return result;
00483
00484 if(written != (ssize_t)pp->sendleft) {
00485
00486 pp->sendleft -= written;
00487 }
00488 else {
00489 free(pp->sendthis);
00490 pp->sendthis=NULL;
00491 pp->sendleft = pp->sendsize = 0;
00492 pp->response = Curl_tvnow();
00493 }
00494 return CURLE_OK;
00495 }
00496
00497 CURLcode Curl_pp_disconnect(struct pingpong *pp)
00498 {
00499 free(pp->cache);
00500 pp->cache = NULL;
00501 return CURLE_OK;
00502 }
00503
00504 bool Curl_pp_moredata(struct pingpong *pp)
00505 {
00506 return (!pp->sendleft && pp->cache && pp->nread_resp < pp->cache_size) ?
00507 TRUE : FALSE;
00508 }
00509
00510 #endif