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");
 
   85     setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (
const char*)&tv, 
sizeof tv);
 
   88     if (connect(fd, (
struct sockaddr*)&sa, addrlen))
 
   91         Utils::log(
"Socket  ", 
"Error connecting to server.\n");
 
  104 int Socket::sendData(
const char* data,
 
  107     int len = (int)send(fd, data, (
int)size, 0);
 
  120 void Socket::disconnect()
 
  133 #    define BUFFER_SIZE 500 
  134 int Socket::receive(
function<
int(
char* data, 
int size)> dataCB, 
int max)
 
  138     char buf[BUFFER_SIZE];
 
  141         if (max != 0 && max - n <= BUFFER_SIZE)
 
  143             len = (int)recv(fd, buf, max - n, 0);
 
  147                 if (errno != ECONNRESET)
 
  148                     len = (int)recv(fd, buf, max - n, 0);
 
  150                 len = (int)recv(fd, buf, max - n, 0);
 
  156             if (dataCB(buf, len) != 0)
 
  162             len = (int)recv(fd, buf, BUFFER_SIZE, 0);
 
  167                 if (errno != ECONNRESET)
 
  168                     len = (int)recv(fd, buf, BUFFER_SIZE, 0);
 
  170                 len = (int)recv(fd, buf, BUFFER_SIZE, 0);
 
  176             if (dataCB(buf, len) != 0)
 
  180     } 
while (!_interrupt && len > 0);
 
  191 int SecureSocket::connectTo(
string ip, 
int port)
 
  193     Socket::connectTo(ip, port);
 
  194     SSL_load_error_strings();
 
  195     const SSL_METHOD* meth = TLS_client_method();
 
  196     SSL_CTX*          ctx  = SSL_CTX_new(meth);
 
  200         Utils::log(
"SecureSocket", 
"Error creating SSL");
 
  205     int err = SSL_connect(ssl);
 
  208         Utils::log(
"SecureSocket", 
"Error creating SSL connection.  err = %d", err);
 
  221 int SecureSocket::sendData(
const char* data, 
size_t size)
 
  223     int len = SSL_write(ssl, data, (
int)size);
 
  226         int err = SSL_get_error(ssl, len);
 
  229             case SSL_ERROR_WANT_WRITE:
 
  231             case SSL_ERROR_WANT_READ:
 
  233             case SSL_ERROR_ZERO_RETURN:
 
  234             case SSL_ERROR_SYSCALL:
 
  248 int SecureSocket::receive(
function<
int(
char* data, 
int size)> dataCB,
 
  253     char buf[BUFFER_SIZE];
 
  256         if (max != 0 && max - n <= BUFFER_SIZE)
 
  258             len = SSL_read(ssl, buf, max - n);
 
  261                 len = SSL_read(ssl, buf, max - n); 
 
  264                     Utils::log(
"SecureSocket", 
"SSL_read return -1");
 
  269             if (dataCB(buf, len) != 0)
 
  275             len = SSL_read(ssl, buf, BUFFER_SIZE);
 
  278                 len = SSL_read(ssl, buf, BUFFER_SIZE); 
 
  281                     Utils::log(
"SecureSocket", 
"SSL_read return -1");
 
  287             if (dataCB(buf, len) != 0)
 
  290     } 
while (!_interrupt && len > 0);
 
  300 void SecureSocket::disconnect()
 
  311 DNSRequest::DNSRequest(
string host)
 
  313     char             s[250] = {
'\0'};
 
  315     struct hostent*  h = 
nullptr;
 
  316     struct addrinfo* res = NULL;
 
  317     int              ret = getaddrinfo(host.c_str(), NULL, NULL, &res);
 
  318     bool             prefer_ipv4 = 
true;
 
  328     for (
struct addrinfo* p = res; p != NULL; p = p->ai_next) {
 
  331             if (p->ai_family == AF_INET) {
 
  338             if (p->ai_family == AF_INET6) {
 
  345     if (res->ai_family == AF_INET)
 
  347         struct sockaddr_in sa;
 
  348         memset(&sa, 0, 
sizeof(sa));
 
  349         sa.sin_family = AF_INET;
 
  350         sa.sin_addr   = (((
struct sockaddr_in*)res->ai_addr))->sin_addr;
 
  351         inet_ntop(AF_INET, &(((
struct sockaddr_in*)res->ai_addr))->sin_addr, 
s, maxlen);
 
  354         h = gethostbyaddr((
const char*)&sa.sin_addr, 
sizeof(sa.sin_addr), sa.sin_family);
 
  356         h = gethostbyaddr(&sa.sin_addr, 
sizeof(sa.sin_addr), sa.sin_family);
 
  359     else if (res->ai_family == AF_INET6)
 
  361         struct sockaddr_in6 sa;
 
  362         memset(&sa, 0, 
sizeof(sa));
 
  363         sa.sin6_family = AF_INET6;
 
  364         sa.sin6_addr   = (((
struct sockaddr_in6*)res->ai_addr))->sin6_addr;
 
  365         inet_ntop(AF_INET6, &(((
struct sockaddr_in6*)res->ai_addr))->sin6_addr, 
s, maxlen);
 
  367         h = gethostbyaddr((
const char*)&sa.sin6_addr, 
sizeof(sa.sin6_addr), sa.sin6_family);
 
  369         h = gethostbyaddr(&sa.sin6_addr, 
sizeof(sa.sin6_addr), sa.sin6_family);
 
  373     if (h != 
nullptr && h->h_length > 0)
 
  374         hostname = string(h->h_name);
 
  387 string DNSRequest::getAddr()
 
  396 string DNSRequest::getHostname()
 
  406 static string base64(
const string data)
 
  408     static constexpr 
char sEncodingTable[] = {
'A',
 
  473     size_t in_len  = data.size();
 
  474     size_t out_len = 4 * ((in_len + 2) / 3);
 
  475     string ret(out_len, 
'\0');
 
  477     char*  p = 
const_cast<char*
>(ret.c_str());
 
  479     for (i = 0; i < in_len - 2; i += 3)
 
  481         *p++ = sEncodingTable[(data[i] >> 2) & 0x3F];
 
  482         *p++ = sEncodingTable[((data[i] & 0x3) << 4) | ((int)(data[i + 1] & 0xF0) >> 4)];
 
  483         *p++ = sEncodingTable[((data[i + 1] & 0xF) << 2) | ((int)(data[i + 2] & 0xC0) >> 6)];
 
  484         *p++ = sEncodingTable[data[i + 2] & 0x3F];
 
  488         *p++ = sEncodingTable[(data[i] >> 2) & 0x3F];
 
  489         if (i == (in_len - 1))
 
  491             *p++ = sEncodingTable[((data[i] & 0x3) << 4)];
 
  496             *p++ = sEncodingTable[((data[i] & 0x3) << 4) | ((int)(data[i + 1] & 0xF0) >> 4)];
 
  497             *p++ = sEncodingTable[((data[i + 1] & 0xF) << 2)];
 
  513 static void parseURL(
string  url,
 
  525     if (url.find(
"https://") != string::npos)
 
  530     else if (url.find(
"http://") != string::npos)
 
  535     size_t pos = url.find(
"/", offset);
 
  536     if (pos != string::npos)
 
  538         path = url.substr(pos, url.length() - pos);
 
  539         host = url.substr(offset, pos - offset);
 
  544         host = url.substr(offset);
 
  554 HttpUtils::GetRequest::GetRequest(
string url,
 
  561     parseURL(url, host, path, isSecure);
 
  563     DNSRequest dns(host);
 
  564     host = dns.getHostname();
 
  565     addr = dns.getAddr();
 
  567     request = 
"GET " + path + 
" HTTP/1.1\r\n";
 
  572                   "Authorization: Basic " +
 
  573                   base64(user + 
":" + pwd) + 
"\r\n";
 
  575     request = request + 
"Host: " + host + 
"\r\n\r\n";
 
  579         s    = 
new SecureSocket();
 
  594 int HttpUtils::GetRequest::processHttpHeaders(std::vector<char>& data)
 
  596     string h          = string(data.begin(),
 
  598                         (data.size() > 1000 ? 1000 : data.size()));
 
  599     size_t contentPos = h.find(
"\r\n\r\n");
 
  600     if (contentPos == string::npos)
 
  602         Utils::log(
"HttpUtils", 
"Invalid http response");
 
  605     headers = string(data.begin(), data.begin() + contentPos);
 
  608     std::cout << headers << std::endl;
 
  609     size_t pos = headers.find(
"HTTP");
 
  611     if (pos != string::npos)
 
  613         string str = headers.substr(pos, headers.find(
"\r", pos) - pos);
 
  615         for (codeIdx = 0; codeIdx < str.length() && !isdigit(str.at(codeIdx)); codeIdx++)
 
  618         if (codeIdx == str.length())
 
  620             Utils::log(
"HttpUtils", 
"Invalid http response");
 
  624         size_t endCodeIdx = str.find(
" ", codeIdx);
 
  626         stoi(str.substr(codeIdx, endCodeIdx - codeIdx));
 
  627         status     = str.substr(endCodeIdx);
 
  631     pos = headers.find(
"Content-Length:");
 
  632     if (pos != string::npos)
 
  634         string str    = headers.substr(pos + 16,
 
  635                                     headers.find(
"\r", pos + 16) - pos - 16);
 
  639     pos = headers.find(
"Content-Type:");
 
  640     if (pos != string::npos)
 
  642         string str  = headers.substr(pos + 13,
 
  643                                     headers.find(
"\r", pos + 13) - pos - 13);
 
  646     return (
int)contentPos;
 
  653 int HttpUtils::GetRequest::send()
 
  655     if (
s->connectTo(addr, port) < 0)
 
  661     s->sendData(request.c_str(), request.length() + 1);
 
  663     std::vector<char>* v = &firstBytes;
 
  665     ret = 
s->receive([v](
char* buf, 
int size) -> 
int 
  667         v->reserve(v->size() + size);
 
  668         copy(&buf[0], &buf[size], back_inserter(*v));
 
  672     contentOffset = processHttpHeaders(firstBytes);
 
  683 int HttpUtils::GetRequest::getContent(
function<
int(
char* buf, 
int size)> contentCB)
 
  685     if (
s->connectTo(addr, port) < 0)
 
  691     s->sendData(request.c_str(), request.length() + 1);
 
  692     std::vector<char>* v = &firstBytes;
 
  694     s->receive([v](
char* buf, 
int size) -> 
int 
  696         v->reserve(v->size() + size);
 
  697         copy(&buf[0], &buf[size], back_inserter(*v));
 
  701     int ret = 
s->receive(contentCB, 0);
 
  710 std::vector<string> HttpUtils::GetRequest::getListing()
 
  712     std::vector<char> content;
 
  713     getContent([&content](
char* buf, 
int size) -> 
int 
  715         content.reserve(content.size() + size);
 
  716         copy(&buf[0], &buf[size], back_inserter(content));
 
  719     string              c = string(content.data());
 
  720     std::vector<string> listing;
 
  726         pos = c.find(
"<", pos);
 
  727         end = c.find(
">", pos) + 1;
 
  728         if (pos == string::npos || end == string::npos)
 
  731         string token = c.substr(pos + 1, end - pos - 2);
 
  734         if (
string(token.begin(), token.begin() + 2) == 
"a ")
 
  736             size_t href = token.find(
"href");
 
  737             if (href != string::npos)
 
  739                 href           = token.find(
"\"", href);
 
  740                 size_t hrefend = token.find(
"\"", href + 1);
 
  741                 if (token.find(
"?") == string::npos)
 
  743                     token = token.substr(href + 1, hrefend - href - 1);
 
  744                     if (token == 
"../" || token == 
".")
 
  749                     listing.push_back(token);
 
  768 int HttpUtils::download(
string                                               url,
 
  769                         function<
int(
string path, 
string file, 
size_t size)> processFile,
 
  770                         function<
int(
char* data, 
int size)>                  writeChunk,
 
  771                         function<
int(
string)>                                processDir,
 
  776     HttpUtils::GetRequest req = HttpUtils::GetRequest(url, user, pwd);
 
  778         return SERVER_NOT_REACHABLE;
 
  781     if (req.contentType == 
"text/html")
 
  783         if (url.back() != 
'/')
 
  786         if (!processDir(base))
 
  787             return CANT_CREATE_DIR;
 
  789         std::vector<string> listing = req.getListing();
 
  791         for (
string str : listing)
 
  793             if (str.at(0) != 
'/')
 
  794                 return download(url + str,
 
  805         string file = url.substr(url.rfind(
"/") + 1);
 
  807         int possibleSplit = (int)base.rfind(file);
 
  808         if (possibleSplit != string::npos && base.size() - possibleSplit - 1 == file.size())
 
  809             base = base.substr(0, possibleSplit);
 
  813         if (processFile(base, file, req.contentLength) != 0)
 
  814             return CANT_CREATE_FILE;
 
  816         if (req.getContent(writeChunk) == -1)
 
  817             return CONNECTION_CLOSED;
 
  832 int HttpUtils::download(
string                                      url,
 
  836                         function<
int(
size_t curr, 
size_t filesize)> progress)
 
  839     size_t        totalBytes  = 0;
 
  840     size_t        writtenByte = 0;
 
  842     bool dstIsDir = 
true;
 
  852       [&fs, &totalBytes, &dst, &dstIsDir](
string path,
 
  859                   fs.open(path + file, std::ios::out | std::ios::binary);
 
  861                   fs.open(dst, std::ios::out | std::ios::binary);
 
  863           catch (std::exception& e)
 
  865               std::cerr << e.what() << 
'\n';
 
  871       [&fs, progress, &writtenByte, &totalBytes](
char* data, 
int size) -> 
int 
  877                   fs.write(data, size);
 
  878                   if (progress && progress(writtenByte += size, totalBytes) != 0)
 
  884               catch (
const std::exception& e)
 
  886                   std::cerr << e.what() << 
'\n';
 
  894                   progress(totalBytes, totalBytes);
 
  899       [&dstIsDir](
string dir) -> 
int 
  917 int HttpUtils::download(
string                                      url,
 
  919                         function<
int(
size_t curr, 
size_t filesize)> progress)
 
  921     return download(url, dst, 
"", 
"", progress);
 
  925 int HttpUtils::length(
string url, 
string user, 
string pwd)
 
  927     HttpUtils::GetRequest req = HttpUtils::GetRequest(url, user, pwd);
 
  931     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