22 #include <openssl/ssl.h>
27 #include <sys/socket.h>
28 #include <netinet/in.h>
29 #include <arpa/inet.h>
37 static 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)
65 BioPtr(
const URLSpec &url) : _connecting(false) {
73 if (!filename.empty()) {
74 if (filename[0] ==
'/' || filename[0] ==
'\\') {
86 _bio = BIO_new_file(filename.c_str(),
"rb");
96 struct addrinfo hints, *res =
nullptr;
97 memset(&hints, 0,
sizeof(hints));
98 hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG;
99 hints.ai_family = support_ipv6 ? AF_UNSPEC : AF_INET;
100 hints.ai_socktype = SOCK_STREAM;
103 int result = getaddrinfo(_server_name.c_str(),
nullptr, &hints, &res);
107 if (result == EAI_SYSTEM && errno != 0) {
108 errmsg = strerror(errno);
112 errmsg = gai_strerror(result);
114 downloader_cat.error()
115 <<
"Failed to resolve " << url.
get_server() <<
": " << errmsg <<
"\n";
118 nassertv(res !=
nullptr && res->ai_addr !=
nullptr);
124 DWORD bufsize =
sizeof(buf);
125 WSAAddressToStringA(res->ai_addr, res->ai_addrlen,
nullptr, buf, &bufsize);
127 if (res->ai_addr->sa_family == AF_INET) {
128 inet_ntop(AF_INET, (
char *)&((sockaddr_in *)res->ai_addr)->sin_addr, buf,
sizeof(buf));
130 }
else if (res->ai_addr->sa_family == AF_INET6) {
131 inet_ntop(AF_INET6, (
char *)&((sockaddr_in6 *)res->ai_addr)->sin6_addr, buf,
sizeof(buf));
138 if (downloader_cat.is_debug()) {
139 downloader_cat.debug()
140 <<
"Resolved " << url.
get_server() <<
" to " << buf <<
"\n";
144 int fd = socket(res->ai_family, SOCK_STREAM, IPPROTO_TCP);
146 downloader_cat.error()
147 <<
"Failed to create socket: " << format_error() <<
"\n";
154 nassertv(res->ai_addrlen <=
sizeof(_addr));
155 memcpy(&_addr, res->ai_addr, res->ai_addrlen);
156 _addrlen = res->ai_addrlen;
160 if (_addr.ss_family == AF_INET) {
161 ((sockaddr_in &)_addr).sin_port = htons(_port);
162 }
else if (_addr.ss_family == AF_INET6) {
163 ((sockaddr_in6 &)_addr).sin6_port = htons(_port);
166 _bio = BIO_new_socket(fd, 1);
174 set_nbio(
bool nbio) {
175 if (_bio ==
nullptr) {
180 BIO_get_fd(_bio, &fd);
181 nassertv_always(fd >= 0);
183 BIO_socket_nbio(fd, nbio);
191 if (_bio ==
nullptr) {
196 BIO_get_fd(_bio, &fd);
197 nassertr(fd >= 0,
false);
201 result = BIO_sock_error(fd);
203 result = ::connect(fd, (sockaddr *)&_addr, _addrlen);
205 if (result != 0 && BIO_sock_should_retry(-1)) {
208 BIO_set_flags(_bio, BIO_FLAGS_SHOULD_RETRY);
213 BIO_clear_retry_flags(_bio);
217 downloader_cat.warning()
218 <<
"Failed to connect to " << _server_name <<
" port " << _port
219 <<
": " << format_error() <<
"\n";
230 should_retry()
const {
231 return (_bio !=
nullptr) && BIO_should_retry(_bio);
239 if (_bio !=
nullptr) {
240 if (downloader_cat.is_debug() && !_server_name.empty()) {
241 downloader_cat.debug()
242 <<
"Dropping connection to " << _server_name <<
" port " << _port <<
"\n";
250 #endif // HAVE_OPENSSL