11 #ifdef SL_BUILD_WITH_OPENSSL
30 memset(&sa, 0,
sizeof(sa));
39 int Socket::connectTo(
string ip,
42 struct addrinfo* res = NULL;
43 int ret = getaddrinfo(ip.c_str(), NULL, NULL, &res);
50 if (res->ai_family == AF_INET)
52 memset(&sa, 0,
sizeof(sa));
53 sa.sin_family = AF_INET;
54 sa.sin_addr = (((
struct sockaddr_in*)res->ai_addr))->sin_addr;
55 sa.sin_port = htons(port);
58 else if (res->ai_family == AF_INET6)
60 memset(&sa6, 0,
sizeof(sa6));
61 sa6.sin6_family = AF_INET6;
62 sa6.sin6_addr = (((
struct sockaddr_in6*)res->ai_addr))->sin6_addr;
63 sa6.sin6_port = htons(port);
64 addrlen =
sizeof(sa6);
72 fd = (int)socket(res->ai_family, SOCK_STREAM, 0);
75 Utils::log(
"Socket ",
"Error creating socket");
86 setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (
const char*)&tv,
sizeof tv);
89 if (connect(fd, (
struct sockaddr*)&sa, addrlen))
91 Utils::log(
"Socket ",
"Error connecting to server.\n");
103 int Socket::sendData(
const char* data,
106 int len = (int)send(fd, data, (
int)size, 0);
119 void Socket::disconnect()
132 # define BUFFER_SIZE 500
133 int Socket::receive(
function<
int(
char* data,
int size)> dataCB,
int max)
137 char buf[BUFFER_SIZE];
140 if (max != 0 && max - n <= BUFFER_SIZE)
142 len = (int)recv(fd, buf, max - n, 0);
146 if (errno != ECONNRESET)
147 len = (int)recv(fd, buf, max - n, 0);
149 len = (int)recv(fd, buf, max - n, 0);
155 if (dataCB(buf, len) != 0)
161 len = (int)recv(fd, buf, BUFFER_SIZE, 0);
166 if (errno != ECONNRESET)
167 len = (int)recv(fd, buf, BUFFER_SIZE, 0);
169 len = (int)recv(fd, buf, BUFFER_SIZE, 0);
175 if (dataCB(buf, len) != 0)
179 }
while (!_interrupt && len > 0);
190 int SecureSocket::connectTo(
string ip,
int port)
192 Socket::connectTo(ip, port);
193 SSL_load_error_strings();
194 const SSL_METHOD* meth = TLS_client_method();
195 SSL_CTX* ctx = SSL_CTX_new(meth);
199 Utils::log(
"SecureSocket",
"Error creating SSL");
204 int err = SSL_connect(ssl);
207 Utils::log(
"SecureSocket",
"Error creating SSL connection. err = %d", err);
220 int SecureSocket::sendData(
const char* data,
size_t size)
222 int len = SSL_write(ssl, data, (
int)size);
225 int err = SSL_get_error(ssl, len);
228 case SSL_ERROR_WANT_WRITE:
230 case SSL_ERROR_WANT_READ:
232 case SSL_ERROR_ZERO_RETURN:
233 case SSL_ERROR_SYSCALL:
247 int SecureSocket::receive(
function<
int(
char* data,
int size)> dataCB,
252 char buf[BUFFER_SIZE];
255 if (max != 0 && max - n <= BUFFER_SIZE)
257 len = SSL_read(ssl, buf, max - n);
260 len = SSL_read(ssl, buf, max - n);
263 Utils::log(
"SecureSocket",
"SSL_read return -1");
268 if (dataCB(buf, len) != 0)
274 len = SSL_read(ssl, buf, BUFFER_SIZE);
277 len = SSL_read(ssl, buf, BUFFER_SIZE);
280 Utils::log(
"SecureSocket",
"SSL_read return -1");
286 if (dataCB(buf, len) != 0)
289 }
while (!_interrupt && len > 0);
299 void SecureSocket::disconnect()
310 DNSRequest::DNSRequest(
string host)
312 char s[250] = {
'\0'};
314 struct hostent* h =
nullptr;
315 struct addrinfo* res = NULL;
316 int ret = getaddrinfo(host.c_str(), NULL, NULL, &res);
326 if (res->ai_family == AF_INET)
328 struct sockaddr_in sa;
329 memset(&sa, 0,
sizeof(sa));
330 sa.sin_family = AF_INET;
331 sa.sin_addr = (((
struct sockaddr_in*)res->ai_addr))->sin_addr;
332 inet_ntop(AF_INET, &(((
struct sockaddr_in*)res->ai_addr))->sin_addr,
s, maxlen);
335 h = gethostbyaddr((
const char*)&sa.sin_addr,
sizeof(sa.sin_addr), sa.sin_family);
337 h = gethostbyaddr(&sa.sin_addr,
sizeof(sa.sin_addr), sa.sin_family);
340 else if (res->ai_family == AF_INET6)
342 struct sockaddr_in6 sa;
343 memset(&sa, 0,
sizeof(sa));
344 sa.sin6_family = AF_INET6;
345 sa.sin6_addr = (((
struct sockaddr_in6*)res->ai_addr))->sin6_addr;
346 inet_ntop(AF_INET6, &(((
struct sockaddr_in6*)res->ai_addr))->sin6_addr,
s, maxlen);
348 h = gethostbyaddr((
const char*)&sa.sin6_addr,
sizeof(sa.sin6_addr), sa.sin6_family);
350 h = gethostbyaddr(&sa.sin6_addr,
sizeof(sa.sin6_addr), sa.sin6_family);
354 if (h !=
nullptr && h->h_length > 0)
355 hostname = string(h->h_name);
366 string DNSRequest::getAddr()
375 string DNSRequest::getHostname()
385 static string base64(
const string data)
387 static constexpr
char sEncodingTable[] = {
'A',
452 size_t in_len = data.size();
453 size_t out_len = 4 * ((in_len + 2) / 3);
454 string ret(out_len,
'\0');
456 char* p =
const_cast<char*
>(ret.c_str());
458 for (i = 0; i < in_len - 2; i += 3)
460 *p++ = sEncodingTable[(data[i] >> 2) & 0x3F];
461 *p++ = sEncodingTable[((data[i] & 0x3) << 4) | ((int)(data[i + 1] & 0xF0) >> 4)];
462 *p++ = sEncodingTable[((data[i + 1] & 0xF) << 2) | ((int)(data[i + 2] & 0xC0) >> 6)];
463 *p++ = sEncodingTable[data[i + 2] & 0x3F];
467 *p++ = sEncodingTable[(data[i] >> 2) & 0x3F];
468 if (i == (in_len - 1))
470 *p++ = sEncodingTable[((data[i] & 0x3) << 4)];
475 *p++ = sEncodingTable[((data[i] & 0x3) << 4) | ((int)(data[i + 1] & 0xF0) >> 4)];
476 *p++ = sEncodingTable[((data[i + 1] & 0xF) << 2)];
492 static void parseURL(
string url,
504 if (url.find(
"https://") != string::npos)
509 else if (url.find(
"http://") != string::npos)
514 size_t pos = url.find(
"/", offset);
515 if (pos != string::npos)
517 path = url.substr(pos, url.length() - pos);
518 host = url.substr(offset, pos - offset);
523 host = url.substr(offset);
533 HttpUtils::GetRequest::GetRequest(
string url,
540 parseURL(url, host, path, isSecure);
542 DNSRequest dns(host);
543 host = dns.getHostname();
544 addr = dns.getAddr();
546 request =
"GET " + path +
" HTTP/1.1\r\n";
551 "Authorization: Basic " +
552 base64(user +
":" + pwd) +
"\r\n";
554 request = request +
"Host: " + host +
"\r\n\r\n";
558 s =
new SecureSocket();
573 int HttpUtils::GetRequest::processHttpHeaders(std::vector<char>& data)
575 string h = string(data.begin(),
577 (data.size() > 1000 ? 1000 : data.size()));
578 size_t contentPos = h.find(
"\r\n\r\n");
579 if (contentPos == string::npos)
581 Utils::log(
"HttpUtils",
"Invalid http response");
584 headers = string(data.begin(), data.begin() + contentPos);
587 std::cout << headers << std::endl;
588 size_t pos = headers.find(
"HTTP");
590 if (pos != string::npos)
592 string str = headers.substr(pos, headers.find(
"\r", pos) - pos);
594 for (codeIdx = 0; codeIdx < str.length() && !isdigit(str.at(codeIdx)); codeIdx++)
597 if (codeIdx == str.length())
599 Utils::log(
"HttpUtils",
"Invalid http response");
603 size_t endCodeIdx = str.find(
" ", codeIdx);
605 stoi(str.substr(codeIdx, endCodeIdx - codeIdx));
606 status = str.substr(endCodeIdx);
610 pos = headers.find(
"Content-Length:");
611 if (pos != string::npos)
613 string str = headers.substr(pos + 16,
614 headers.find(
"\r", pos + 16) - pos - 16);
618 pos = headers.find(
"Content-Type:");
619 if (pos != string::npos)
621 string str = headers.substr(pos + 13,
622 headers.find(
"\r", pos + 13) - pos - 13);
625 return (
int)contentPos;
632 int HttpUtils::GetRequest::send()
634 if (
s->connectTo(addr, port) < 0)
640 s->sendData(request.c_str(), request.length() + 1);
642 std::vector<char>* v = &firstBytes;
644 ret =
s->receive([v](
char* buf,
int size) ->
int
646 v->reserve(v->size() + size);
647 copy(&buf[0], &buf[size], back_inserter(*v));
651 contentOffset = processHttpHeaders(firstBytes);
662 int HttpUtils::GetRequest::getContent(
function<
int(
char* buf,
int size)> contentCB)
664 if (
s->connectTo(addr, port) < 0)
670 s->sendData(request.c_str(), request.length() + 1);
671 std::vector<char>* v = &firstBytes;
673 s->receive([v](
char* buf,
int size) ->
int
675 v->reserve(v->size() + size);
676 copy(&buf[0], &buf[size], back_inserter(*v));
680 int ret =
s->receive(contentCB, 0);
689 std::vector<string> HttpUtils::GetRequest::getListing()
691 std::vector<char> content;
692 getContent([&content](
char* buf,
int size) ->
int
694 content.reserve(content.size() + size);
695 copy(&buf[0], &buf[size], back_inserter(content));
698 string c = string(content.data());
699 std::vector<string> listing;
705 pos = c.find(
"<", pos);
706 end = c.find(
">", pos) + 1;
707 if (pos == string::npos || end == string::npos)
710 string token = c.substr(pos + 1, end - pos - 2);
713 if (
string(token.begin(), token.begin() + 2) ==
"a ")
715 size_t href = token.find(
"href");
716 if (href != string::npos)
718 href = token.find(
"\"", href);
719 size_t hrefend = token.find(
"\"", href + 1);
720 if (token.find(
"?") == string::npos)
722 token = token.substr(href + 1, hrefend - href - 1);
723 if (token ==
"../" || token ==
".")
728 listing.push_back(token);
747 int HttpUtils::download(
string url,
748 function<
int(
string path,
string file,
size_t size)> processFile,
749 function<
int(
char* data,
int size)> writeChunk,
750 function<
int(
string)> processDir,
755 HttpUtils::GetRequest req = HttpUtils::GetRequest(url, user, pwd);
757 return SERVER_NOT_REACHABLE;
760 if (req.contentType ==
"text/html")
762 if (url.back() !=
'/')
765 if (!processDir(base))
766 return CANT_CREATE_DIR;
768 std::vector<string> listing = req.getListing();
770 for (
string str : listing)
772 if (str.at(0) !=
'/')
773 return download(url + str,
784 string file = url.substr(url.rfind(
"/") + 1);
786 int possibleSplit = (int)base.rfind(file);
787 if (possibleSplit != string::npos && base.size() - possibleSplit - 1 == file.size())
788 base = base.substr(0, possibleSplit);
792 if (processFile(base, file, req.contentLength) != 0)
793 return CANT_CREATE_FILE;
795 if (req.getContent(writeChunk) == -1)
796 return CONNECTION_CLOSED;
811 int HttpUtils::download(
string url,
815 function<
int(
size_t curr,
size_t filesize)> progress)
818 size_t totalBytes = 0;
819 size_t writtenByte = 0;
821 bool dstIsDir =
true;
831 [&fs, &totalBytes, &dst, &dstIsDir](
string path,
838 fs.open(path + file, std::ios::out | std::ios::binary);
840 fs.open(dst, std::ios::out | std::ios::binary);
842 catch (std::exception& e)
844 std::cerr << e.what() <<
'\n';
850 [&fs, progress, &writtenByte, &totalBytes](
char* data,
int size) ->
int
856 fs.write(data, size);
857 if (progress && progress(writtenByte += size, totalBytes) != 0)
863 catch (
const std::exception& e)
865 std::cerr << e.what() <<
'\n';
873 progress(totalBytes, totalBytes);
878 [&dstIsDir](
string dir) ->
int
896 int HttpUtils::download(
string url,
898 function<
int(
size_t curr,
size_t filesize)> progress)
900 return download(url, dst,
"",
"", progress);
904 int HttpUtils::length(
string url,
string user,
string pwd)
906 HttpUtils::GetRequest req = HttpUtils::GetRequest(url, user, pwd);
910 return (
int)req.contentLength;
The SLScene class represents the top level instance holding the scene structure.
void close(SLIOStream *stream)
Closes and deletes a stream.
string unifySlashes(const string &inputDir, bool withTrailingSlash)
Returns the inputDir string with unified forward slashes, e.g.: "dirA/dirB/".
bool fileExists(const string &pathfilename)
Returns true if a file exists.
bool makeDir(const string &path)
Creates a directory with given path.
string trimString(const string &s, const string &drop)
Trims a string at both end.
bool makeDirRecurse(std::string path)
void log(const char *tag, const char *format,...)
logs a formatted string platform independently