22#include <openssl/ssl.h>
27#include <sys/socket.h>
28#include <netinet/in.h>
37static string format_error() {
40 len = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
41 nullptr, WSAGetLastError(), 0, (LPTSTR)&buffer, 0,
nullptr);
43 return string(
"Unknown error message");
46 const char *text = (
const char *)buffer;
47 while (len > 0 && isspace(text[len - 1])) {
51 string result(text, len);
56#define format_error() strerror(errno)
59#if defined(_WIN32) && defined(LIBRESSL_VERSION_NUMBER)
66sock_should_retry(
int i) {
67 if (i == 0 || i == -1) {
68 int err = WSAGetLastError();
83#define sock_should_retry(err) BIO_sock_should_retry(err)
92BioPtr(
const URLSpec &url) : _connecting(false) {
100 if (!filename.empty()) {
101 if (filename[0] ==
'/' || filename[0] ==
'\\') {
113 _bio = BIO_new_file(filename.c_str(),
"rb");
123 struct addrinfo hints, *res =
nullptr;
124 memset(&hints, 0,
sizeof(hints));
125 hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG;
126 hints.ai_family = support_ipv6 ? AF_UNSPEC : AF_INET;
127 hints.ai_socktype = SOCK_STREAM;
130 int result = getaddrinfo(_server_name.c_str(),
nullptr, &hints, &res);
134 if (result == EAI_SYSTEM && errno != 0) {
135 errmsg = strerror(errno);
139 errmsg = gai_strerror(result);
141 downloader_cat.error()
142 <<
"Failed to resolve " << url.
get_server() <<
": " << errmsg <<
"\n";
145 nassertv(res !=
nullptr && res->ai_addr !=
nullptr);
151 DWORD bufsize =
sizeof(buf);
152 WSAAddressToStringA(res->ai_addr, res->ai_addrlen,
nullptr, buf, &bufsize);
154 if (res->ai_addr->sa_family == AF_INET) {
155 inet_ntop(AF_INET, (
char *)&((sockaddr_in *)res->ai_addr)->sin_addr, buf,
sizeof(buf));
157 }
else if (res->ai_addr->sa_family == AF_INET6) {
158 inet_ntop(AF_INET6, (
char *)&((sockaddr_in6 *)res->ai_addr)->sin6_addr, buf,
sizeof(buf));
165 if (downloader_cat.is_debug()) {
166 downloader_cat.debug()
167 <<
"Resolved " << url.
get_server() <<
" to " << buf <<
"\n";
171 int fd = socket(res->ai_family, SOCK_STREAM, IPPROTO_TCP);
173 downloader_cat.error()
174 <<
"Failed to create socket: " << format_error() <<
"\n";
181 nassertv(res->ai_addrlen <=
sizeof(_addr));
182 memcpy(&_addr, res->ai_addr, res->ai_addrlen);
183 _addrlen = res->ai_addrlen;
187 if (_addr.ss_family == AF_INET) {
188 ((sockaddr_in &)_addr).sin_port = htons(_port);
189 }
else if (_addr.ss_family == AF_INET6) {
190 ((sockaddr_in6 &)_addr).sin6_port = htons(_port);
193 _bio = BIO_new_socket(fd, 1);
202 if (_bio ==
nullptr) {
207 BIO_get_fd(_bio, &fd);
208 nassertv_always(fd >= 0);
210 BIO_socket_nbio(fd, nbio);
218 if (_bio ==
nullptr) {
223 BIO_get_fd(_bio, &fd);
224 nassertr(fd >= 0,
false);
228 result = BIO_sock_error(fd);
230 result = ::connect(fd, (sockaddr *)&_addr, _addrlen);
231 if (result != 0 && sock_should_retry(-1)) {
234 BIO_set_flags(_bio, BIO_FLAGS_SHOULD_RETRY);
239 BIO_clear_retry_flags(_bio);
243 downloader_cat.warning()
244 <<
"Failed to connect to " << _server_name <<
" port " << _port
245 <<
": " << format_error() <<
"\n";
256should_retry()
const {
257 return (_bio !=
nullptr) && BIO_should_retry(_bio);
265 if (_bio !=
nullptr) {
266 if (downloader_cat.is_debug() && !_server_name.empty()) {
267 downloader_cat.debug()
268 <<
"Dropping connection to " << _server_name <<
" port " << _port <<
"\n";
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
The name of a file, such as a texture file or an Egg file.
std::string to_os_specific() const
Converts the filename from our generic Unix-like convention (forward slashes starting with the root a...
std::string get_fullpath() const
Returns the entire filename: directory, basename, extension.
static Filename from_os_specific(const std::string &os_specific, Type type=T_general)
This named constructor returns a Panda-style filename (that is, using forward slashes,...
bool is_local() const
Returns true if the filename is local, e.g.
A container for a URL, e.g.
get_server
Returns the server name specified by the URL, if any.
get_path
Returns the path specified by the URL, or "/" if no path is specified.
get_scheme
Returns the scheme specified by the URL, or empty string if no scheme is specified.
static std::string unquote(const std::string &source)
Reverses the operation of quote(): converts escaped characters of the form "%xx" to their ascii equiv...
get_port
Returns the port number specified by the URL, or the default port if not specified.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.