📄 url.c
字号:
Curl_safefree(conn->allocptr.uagent); Curl_safefree(conn->allocptr.userpwd); Curl_safefree(conn->allocptr.accept_encoding); Curl_safefree(conn->allocptr.rangeline); Curl_safefree(conn->allocptr.ref); Curl_safefree(conn->allocptr.cookie); Curl_safefree(conn->allocptr.host); Curl_safefree(conn->allocptr.cookiehost); Curl_safefree(conn->proxyhost);#ifdef USE_ARES /* possible left-overs from the async name resolve */ Curl_safefree(conn->async.hostname);#endif Curl_free_ssl_config(&conn->ssl_config); free(conn); /* free all the connection oriented data */ return CURLE_OK;}/* * This function should return TRUE if the socket is to be assumed to * be dead. Most commonly this happens when the server has closed the * connection due to inactivity. */static bool SocketIsDead(int sock){ int sval; bool ret_val = TRUE; fd_set check_set; struct timeval to; FD_ZERO(&check_set); FD_SET(sock,&check_set); to.tv_sec = 0; to.tv_usec = 0; sval = select(sock + 1, &check_set, 0, 0, &to); if(sval == 0) /* timeout */ ret_val = FALSE; return ret_val;}/* * Given one filled in connection struct (named needle), this function should * detect if there already is one that have all the significant details * exactly the same and thus should be used instead. */static boolConnectionExists(struct SessionHandle *data, struct connectdata *needle, struct connectdata **usethis){ long i; struct connectdata *check; for(i=0; i< data->state.numconnects; i++) { bool match = FALSE; /* * Note that if we use a HTTP proxy, we check connections to that * proxy and not to the actual remote server. */ check = data->state.connects[i]; if(!check) /* NULL pointer means not filled-in entry */ continue; if((needle->protocol&PROT_SSL) != (check->protocol&PROT_SSL)) /* don't do mixed SSL and non-SSL connections */ continue; if(!needle->bits.httpproxy || needle->protocol&PROT_SSL) { /* The requested connection does not use a HTTP proxy or it uses SSL. */ if(!(needle->protocol&PROT_SSL) && check->bits.httpproxy) /* we don't do SSL but the cached connection has a proxy, then don't match this */ continue; if(strequal(needle->protostr, check->protostr) && strequal(needle->name, check->name) && (needle->remote_port == check->remote_port) ) { if(needle->protocol & PROT_SSL) { /* This is SSL, verify that we're using the same ssl options as well */ if(!Curl_ssl_config_matches(&needle->ssl_config, &check->ssl_config)) { continue; } } if((needle->protocol & PROT_FTP) || ((needle->protocol & PROT_HTTP) && (needle->data->state.authwant==CURLAUTH_NTLM))) { /* This is FTP or HTTP+NTLM, verify that we're using the same name and password as well */ if(!strequal(needle->user, check->user) || !strequal(needle->passwd, check->passwd)) { /* one of them was different */ continue; } } match = TRUE; } } else { /* The requested needle connection is using a proxy, is the checked one using the same? */ if(check->bits.httpproxy && strequal(needle->proxyhost, check->proxyhost) && needle->port == check->port) { /* This is the same proxy connection, use it! */ match = TRUE; } } if(match) { bool dead = SocketIsDead(check->firstsocket); if(dead) { /* */ infof(data, "Connection %d seems to be dead!\n", i); Curl_disconnect(check); /* disconnect resources */ data->state.connects[i]=NULL; /* nothing here */ /* There's no need to continue searching, because we only store one connection for each unique set of identifiers */ return FALSE; } *usethis = check; return TRUE; /* yes, we found one to use! */ } } return FALSE; /* no matching connecting exists */}/* * This function frees/closes a connection in the connection cache. This * should take the previously set policy into account when deciding which * of the connections to kill. */static intConnectionKillOne(struct SessionHandle *data){ long i; struct connectdata *conn; int highscore=-1; int connindex=-1; int score; CURLcode result; struct timeval now; now = Curl_tvnow(); for(i=0; i< data->state.numconnects; i++) { conn = data->state.connects[i]; if(!conn) continue; /* * By using the set policy, we score each connection. */ switch(data->set.closepolicy) { case CURLCLOSEPOLICY_LEAST_RECENTLY_USED: default: /* * Set higher score for the age passed since the connection * was used. */ score = Curl_tvdiff(now, conn->now); break; case CURLCLOSEPOLICY_OLDEST: /* * Set higher score for the age passed since the connection * was created. */ score = Curl_tvdiff(now, conn->created); break; } if(score > highscore) { highscore = score; connindex = i; } } if(connindex >= 0) { /* the winner gets the honour of being disconnected */ result = Curl_disconnect(data->state.connects[connindex]); /* clean the array entry */ data->state.connects[connindex] = NULL; } return connindex; /* return the available index or -1 */}/* * The given input connection struct pointer is to be stored. If the "cache" * is already full, we must clean out the most suitable using the previously * set policy. * * The given connection should be unique. That must've been checked prior to * this call. */static unsigned intConnectionStore(struct SessionHandle *data, struct connectdata *conn){ long i; for(i=0; i< data->state.numconnects; i++) { if(!data->state.connects[i]) break; } if(i == data->state.numconnects) { /* there was no room available, kill one */ i = ConnectionKillOne(data); infof(data, "Connection (#%d) was killed to make room\n", i); } if(-1 != i) { /* only do this if a true index was returned, if -1 was returned there is no room in the cache for an unknown reason and we cannot store this there. */ data->state.connects[i] = conn; /* fill in this */ conn->connectindex = i; /* make the child know where the pointer to this particular data is stored */ } return i;}/* * This function logs in to a SOCKS5 proxy and sends the specifies the final * desitination server. */static int handleSock5Proxy( const char *proxy_name, const char *proxy_password, struct connectdata *conn, int sock){ unsigned char socksreq[600]; /* room for large user/pw (255 max each) */ ssize_t actualread; ssize_t written; CURLcode result; Curl_nonblock(sock, FALSE); socksreq[0] = 5; /* version */ socksreq[1] = (char)(proxy_name[0] ? 2 : 1); /* number of methods (below) */ socksreq[2] = 0; /* no authentication */ socksreq[3] = 2; /* username/password */ result = Curl_write(conn, sock, (char *)socksreq, (2 + (int)socksreq[1]), &written); if ((result != CURLE_OK) || (written != (2 + (int)socksreq[1]))) { failf(conn->data, "Unable to send initial SOCKS5 request."); return 1; } result=Curl_read(conn, sock, (char *)socksreq, 2, &actualread); if ((result != CURLE_OK) || (actualread != 2)) { failf(conn->data, "Unable to receive initial SOCKS5 response."); return 1; } if (socksreq[0] != 5) { failf(conn->data, "Received invalid version in initial SOCKS5 response."); return 1; } if (socksreq[1] == 0) { /* Nothing to do, no authentication needed */ ; } else if (socksreq[1] == 2) { /* Needs user name and password */ int userlen, pwlen, len; userlen = strlen(proxy_name); pwlen = strlen(proxy_password); /* username/password request looks like * +----+------+----------+------+----------+ * |VER | ULEN | UNAME | PLEN | PASSWD | * +----+------+----------+------+----------+ * | 1 | 1 | 1 to 255 | 1 | 1 to 255 | * +----+------+----------+------+----------+ */ len = 0; socksreq[len++] = 1; /* username/pw subnegotiation version */ socksreq[len++] = (char) userlen; memcpy(socksreq + len, proxy_name, (int) userlen); len += userlen; socksreq[len++] = (char) pwlen; memcpy(socksreq + len, proxy_password, (int) pwlen); len += pwlen; result = Curl_write(conn, sock, (char *)socksreq, len, &written); if ((result != CURLE_OK) || (len != written)) { failf(conn->data, "Failed to send SOCKS5 sub-negotiation request."); return 1; } result=Curl_read(conn, sock, (char *)socksreq, 2, &actualread); if ((result != CURLE_OK) || (actualread != 2)) { failf(conn->data, "Unable to receive SOCKS5 sub-negotiation response."); return 1; } if ((socksreq[0] != 1) || /* version */ (socksreq[1] != 0)) { /* status */ failf(conn->data, "User was rejected by the SOCKS5 server (%d %d).", socksreq[0], socksreq[1]); return 1; } /* Everything is good so far, user was authenticated! */ } else { /* error */ if (socksreq[1] == 1) { failf(conn->data, "SOCKS5 GSSAPI per-message authentication is not supported."); return 1; } else if (socksreq[1] == 255) { if (proxy_name[0] == 0) { failf(conn->data, "No authentication method was acceptable. (It is quite likely" " that the SOCKS5 server wanted a username/password, since none" " was supplied to the server on this connection.)"); } else { failf(conn->data, "No authentication method was acceptable."); } return 1; } else { failf(conn->data, "Undocumented SOCKS5 mode attempted to be used by server."); return 1; } } /* Authentication is complete, now specify destination to the proxy */ socksreq[0] = 5; /* version (SOCKS5) */ socksreq[1] = 1; /* connect */ socksreq[2] = 0; /* must be zero */ socksreq[3] = 1; /* IPv4 = 1 */ {#ifndef ENABLE_IPV6 struct Curl_dns_entry *dns; Curl_addrinfo *hp=NULL; int rc = Curl_resolv(conn, conn->hostname, conn->remote_port, &dns); if(rc == -1) return CURLE_COULDNT_RESOLVE_HOST; if(rc == 1) /* this requires that we're in "wait for resolve" state */ rc = Curl_wait_for_resolv(conn, &dns); /* * We cannot use 'hostent' as a struct that Curl_resolv() returns. It * returns a Curl_addrinfo pointer that may not always look the same. */ if(dns) hp=dns->addr; if (hp && hp->h_addr_list[0]) { socksreq[4] = ((char*)hp->h_addr_list[0])[0]; socksreq[5] = ((char*)hp->h_addr_list[0])[1]; socksreq[6] = ((char*)hp->h_addr_list[0])[2]; socksreq[7] = ((char*)hp->h_addr_list[0])[3]; Curl_resolv_unlock(conn->data, dns); /* not used anymore from now on */ } else { failf(conn->data, "Failed to resolve \"%s\" for SOCKS5 connect.", conn->hostname); return 1; }#else failf(conn->data, "%s:%d has an internal error an needs to be fixed to work", __FILE__, __LINE__); return 1;#endif } *((unsigned short*)&socksreq[8]) = htons(conn->remote_port); { const int packetsize = 10; result = Curl_write(conn, sock, (char *)socksreq, packetsize, &written); if ((result != CURLE_OK) || (written != packetsize)) { failf(conn->data, "Failed to send SOCKS5 connect request."); return 1; } result = Curl_read(conn, sock, (char *)socksreq, packetsize, &actualread); if ((result != CURLE_OK) || (actualread != packetsize)) { failf(conn->data, "Failed to receive SOCKS5 connect request ack."); return 1; } if (socksreq[0] != 5) { /* version */ failf(conn->data, "SOCKS5 reply has wrong version, version should be 5."); return 1; } if (socksreq[1] != 0) { /* Anything besides 0 is an error */ failf(conn->data, "Can't complete SOCKS5 connection to %d.%d.%d.%d:%d. (%d)", (unsigned char)socksreq[4], (unsigned char)socksreq[5], (unsigned char)socksreq[6], (unsigned char)socksreq[7], (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])), socksreq[1]); return 1; } } Curl_nonblock(sock, TRUE); return 0; /* Proxy was successful! */}static CURLcode ConnectPlease(struct connectdata *conn, struct Curl_dns_entry *hostaddr, bool *connected)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -