int Curl_resolv(struct connectdata *conn, const char *hostname, int port, struct Curl_dns_entry **entry) { char *entry_id = NULL; struct Curl_dns_entry *dns = NULL; size_t entry_len; struct SessionHandle *data = conn->data; CURLcode result; int rc = CURLRESOLV_ERROR; /* default to failure */ *entry = NULL; /* Create an entry id, based upon the hostname and port */ entry_id = create_hostcache_id(hostname, port); /* If we can't create the entry id, fail */ if(!entry_id) return rc; entry_len = strlen(entry_id); if(data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); /* See if its already in our dns cache */ dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1); /* free the allocated entry_id again */ free(entry_id); /* See whether the returned entry is stale. Done before we release lock */ if(remove_entry_if_stale(data, dns)) dns = NULL; /* the memory deallocation is being handled by the hash */ if(dns) { dns->inuse++; /* we use it! */ rc = CURLRESOLV_RESOLVED; } if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); if(!dns) { /* The entry was not in the cache. Resolve it to IP address */ Curl_addrinfo *addr; int respwait; /* Check what IP specifics the app has requested and if we can provide it. * If not, bail out. */ if(!Curl_ipvalid(conn)) return CURLRESOLV_ERROR; /* If Curl_getaddrinfo() returns NULL, 'respwait' might be set to a non-zero value indicating that we need to wait for the response to the resolve call */ addr = Curl_getaddrinfo(conn, #ifdef DEBUGBUILD (data->set.str[STRING_DEVICE] && !strcmp(data->set.str[STRING_DEVICE], "LocalHost"))?"localhost": #endif hostname, port, &respwait); if(!addr) { if(respwait) { /* the response to our resolve call will come asynchronously at a later time, good or bad */ /* First, check that we haven't received the info by now */ result = Curl_resolver_is_resolved(conn, &dns); if(result) /* error detected */ return CURLRESOLV_ERROR; if(dns) rc = CURLRESOLV_RESOLVED; /* pointer provided */ else rc = CURLRESOLV_PENDING; /* no info yet */ } } else { if(data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); /* we got a response, store it in the cache */ dns = Curl_cache_addr(data, addr, hostname, port); if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); if(!dns) /* returned failure, bail out nicely */ Curl_freeaddrinfo(addr); else rc = CURLRESOLV_RESOLVED; } } *entry = dns; return rc; }
CURLcode Curl_loadhostpairs(struct SessionHandle *data) { struct curl_slist *hostp; char hostname[256]; char address[256]; int port; for(hostp = data->change.resolve; hostp; hostp = hostp->next ) { if(!hostp->data) continue; if(hostp->data[0] == '-') { /* TODO: mark an entry for removal */ } else if(3 == sscanf(hostp->data, "%255[^:]:%d:%255s", hostname, &port, address)) { struct Curl_dns_entry *dns; Curl_addrinfo *addr; char *entry_id; size_t entry_len; addr = Curl_str2addr(address, port); if(!addr) { infof(data, "Resolve %s found illegal!\n", hostp->data); continue; } /* Create an entry id, based upon the hostname and port */ entry_id = create_hostcache_id(hostname, port); /* If we can't create the entry id, fail */ if(!entry_id) { Curl_freeaddrinfo(addr); return CURLE_OUT_OF_MEMORY; } entry_len = strlen(entry_id); if(data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); /* See if its already in our dns cache */ dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1); /* free the allocated entry_id again */ free(entry_id); if(!dns) /* if not in the cache already, put this host in the cache */ dns = Curl_cache_addr(data, addr, hostname, port); else /* this is a duplicate, free it again */ Curl_freeaddrinfo(addr); if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); if(!dns) { Curl_freeaddrinfo(addr); return CURLE_OUT_OF_MEMORY; } infof(data, "Added %s:%d:%s to DNS cache\n", hostname, port, address); } } data->change.resolve = NULL; /* dealt with now */ return CURLE_OK; }
CURLcode Curl_loadhostpairs(struct SessionHandle *data) { struct curl_slist *hostp; char hostname[256]; char address[256]; int port; for(hostp = data->change.resolve; hostp; hostp = hostp->next ) { if(!hostp->data) continue; if(hostp->data[0] == '-') { char *entry_id; size_t entry_len; if(2 != sscanf(hostp->data + 1, "%255[^:]:%d", hostname, &port)) { infof(data, "Couldn't parse CURLOPT_RESOLVE removal entry '%s'!\n", hostp->data); continue; } /* Create an entry id, based upon the hostname and port */ entry_id = create_hostcache_id(hostname, port); /* If we can't create the entry id, fail */ if(!entry_id) { return CURLE_OUT_OF_MEMORY; } entry_len = strlen(entry_id); if(data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); /* delete entry, ignore if it didn't exist */ Curl_hash_delete(data->dns.hostcache, entry_id, entry_len+1); if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); /* free the allocated entry_id again */ free(entry_id); } else { struct Curl_dns_entry *dns; Curl_addrinfo *addr; char *entry_id; size_t entry_len; if(3 != sscanf(hostp->data, "%255[^:]:%d:%255s", hostname, &port, address)) { infof(data, "Couldn't parse CURLOPT_RESOLVE entry '%s'!\n", hostp->data); continue; } addr = Curl_str2addr(address, port); if(!addr) { infof(data, "Address in '%s' found illegal!\n", hostp->data); continue; } /* Create an entry id, based upon the hostname and port */ entry_id = create_hostcache_id(hostname, port); /* If we can't create the entry id, fail */ if(!entry_id) { Curl_freeaddrinfo(addr); return CURLE_OUT_OF_MEMORY; } entry_len = strlen(entry_id); if(data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); /* See if its already in our dns cache */ dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1); /* free the allocated entry_id again */ free(entry_id); if(!dns) { /* if not in the cache already, put this host in the cache */ dns = Curl_cache_addr(data, addr, hostname, port); if(dns) { dns->timestamp = 0; /* mark as added by CURLOPT_RESOLVE */ /* release the returned reference; the cache itself will keep the * entry alive: */ dns->inuse--; } } else /* this is a duplicate, free it again */ Curl_freeaddrinfo(addr); if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); if(!dns) { Curl_freeaddrinfo(addr); return CURLE_OUT_OF_MEMORY; } infof(data, "Added %s:%d:%s to DNS cache\n", hostname, port, address); } } data->change.resolve = NULL; /* dealt with now */ return CURLE_OK; }
int Curl_resolv(struct connectdata *conn, const char *hostname, int port, struct Curl_dns_entry **entry) { struct Curl_dns_entry *dns = NULL; struct SessionHandle *data = conn->data; CURLcode result; int rc = CURLRESOLV_ERROR; /* default to failure */ *entry = NULL; if(data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); dns = fetch_addr(conn, hostname, port); if(dns) { infof(data, "Hostname %s was found in DNS cache\n", hostname); dns->inuse++; /* we use it! */ rc = CURLRESOLV_RESOLVED; } if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); if(!dns) { /* The entry was not in the cache. Resolve it to IP address */ Curl_addrinfo *addr; int respwait; /* Check what IP specifics the app has requested and if we can provide it. * If not, bail out. */ if(!Curl_ipvalid(conn)) return CURLRESOLV_ERROR; /* If Curl_getaddrinfo() returns NULL, 'respwait' might be set to a non-zero value indicating that we need to wait for the response to the resolve call */ addr = Curl_getaddrinfo(conn, #ifdef DEBUGBUILD (data->set.str[STRING_DEVICE] && !strcmp(data->set.str[STRING_DEVICE], "LocalHost"))?"localhost": #endif hostname, port, &respwait); if(!addr) { if(respwait) { /* the response to our resolve call will come asynchronously at a later time, good or bad */ /* First, check that we haven't received the info by now */ result = Curl_resolver_is_resolved(conn, &dns); if(result) /* error detected */ return CURLRESOLV_ERROR; if(dns) rc = CURLRESOLV_RESOLVED; /* pointer provided */ else rc = CURLRESOLV_PENDING; /* no info yet */ } } else { if(data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); /* we got a response, store it in the cache */ dns = Curl_cache_addr(data, addr, hostname, port); if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); if(!dns) /* returned failure, bail out nicely */ Curl_freeaddrinfo(addr); else rc = CURLRESOLV_RESOLVED; } } *entry = dns; return rc; }
/* * Lock shared SSL session data */ void Curl_ssl_sessionid_lock(struct connectdata *conn) { if(SSLSESSION_SHARED(conn->data)) Curl_share_lock(conn->data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE); }
int Curl_resolv(struct connectdata *conn, const char *hostname, int port, struct Curl_dns_entry **entry) { char *entry_id = NULL; struct Curl_dns_entry *dns = NULL; size_t entry_len; int wait; struct SessionHandle *data = conn->data; CURLcode result; int rc; *entry = NULL; #ifdef HAVE_SIGSETJMP /* this allows us to time-out from the name resolver, as the timeout will generate a signal and we will siglongjmp() from that here */ if(!data->set.no_signal) { if (sigsetjmp(curl_jmpenv, 1)) { /* this is coming from a siglongjmp() */ failf(data, "name lookup timed out"); return CURLRESOLV_ERROR; } } #endif /* Create an entry id, based upon the hostname and port */ entry_id = create_hostcache_id(hostname, port); /* If we can't create the entry id, fail */ if (!entry_id) return CURLRESOLV_ERROR; entry_len = strlen(entry_id); if(data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); /* See if its already in our dns cache */ dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1); if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); /* free the allocated entry_id again */ free(entry_id); /* See whether the returned entry is stale. Deliberately done after the locked block */ if ( remove_entry_if_stale(data,dns) ) dns = NULL; /* the memory deallocation is being handled by the hash */ rc = CURLRESOLV_ERROR; /* default to failure */ if (!dns) { /* The entry was not in the cache. Resolve it to IP address */ Curl_addrinfo *addr; /* Check what IP specifics the app has requested and if we can provide it. * If not, bail out. */ if(!Curl_ipvalid(data)) return CURLRESOLV_ERROR; /* If Curl_getaddrinfo() returns NULL, 'wait' might be set to a non-zero value indicating that we need to wait for the response to the resolve call */ addr = Curl_getaddrinfo(conn, hostname, port, &wait); if (!addr) { if(wait) { /* the response to our resolve call will come asynchronously at a later time, good or bad */ /* First, check that we haven't received the info by now */ result = Curl_is_resolved(conn, &dns); if(result) /* error detected */ return CURLRESOLV_ERROR; if(dns) rc = CURLRESOLV_RESOLVED; /* pointer provided */ else rc = CURLRESOLV_PENDING; /* no info yet */ } } else { if(data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); /* we got a response, store it in the cache */ dns = Curl_cache_addr(data, addr, hostname, port); if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); if(!dns) /* returned failure, bail out nicely */ Curl_freeaddrinfo(addr); else rc = CURLRESOLV_RESOLVED; } } else { if(data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); dns->inuse++; /* we use it! */ if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); rc = CURLRESOLV_RESOLVED; } *entry = dns; return rc; }
/* * Store session id in the session cache. The ID passed on to this function * must already have been extracted and allocated the proper way for the SSL * layer. Curl_XXXX_session_free() will be called to free/kill the session ID * later on. */ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, void *ssl_sessionid, size_t idsize) { size_t i; struct SessionHandle *data=conn->data; /* the mother of all structs */ struct curl_ssl_session *store = &data->state.session[0]; long oldest_age=data->state.session[0].age; /* zero if unused */ char *clone_host; long *general_age; /* Even though session ID re-use might be disabled, that only disables USING IT. We still store it here in case the re-using is again enabled for an upcoming transfer */ clone_host = strdup(conn->host.name); if(!clone_host) return CURLE_OUT_OF_MEMORY; /* bail out */ /* Now we should add the session ID and the host name to the cache, (remove the oldest if necessary) */ /* If using shared SSL session, lock! */ if(SSLSESSION_SHARED(data)) { Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE); general_age = &data->share->sessionage; } else { general_age = &data->state.sessionage; } /* find an empty slot for us, or find the oldest */ for(i = 1; (i < data->set.ssl.max_ssl_sessions) && data->state.session[i].sessionid; i++) { if(data->state.session[i].age < oldest_age) { oldest_age = data->state.session[i].age; store = &data->state.session[i]; } } if(i == data->set.ssl.max_ssl_sessions) /* cache is full, we must "kill" the oldest entry! */ Curl_ssl_kill_session(store); else store = &data->state.session[i]; /* use this slot */ /* now init the session struct wisely */ store->sessionid = ssl_sessionid; store->idsize = idsize; store->age = *general_age; /* set current age */ if(store->name) /* free it if there's one already present */ free(store->name); store->name = clone_host; /* clone host name */ store->remote_port = conn->remote_port; /* port number */ /* Unlock */ if(SSLSESSION_SHARED(data)) Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION); if(!Curl_clone_ssl_config(&conn->ssl_config, &store->ssl_config)) { store->sessionid = NULL; /* let caller free sessionid */ free(clone_host); return CURLE_OUT_OF_MEMORY; } return CURLE_OK; }