/////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance"). // All rights reserved. // // This software and its documentation and related materials are owned by // the Alliance. The software may only be incorporated into application // programs owned by members of the Alliance, subject to a signed // Membership Agreement and Supplemental Software License Agreement with the // Alliance. The structure and organization of this software are the valuable // trade secrets of the Alliance and its suppliers. The software is also // protected by copyright law and international treaty provisions. Application // programs incorporating this software must include the following statement // with their copyright notices: // // This application incorporates Open Design Alliance software pursuant to a license // agreement with Open Design Alliance. // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance. // All rights reserved. // // By use of this software, its documentation or related materials, you // acknowledge and accept the above terms. /////////////////////////////////////////////////////////////////////////////// #include "OdGeoMapCurlRequstHelper.h" #include "DynamicLinker.h" #include "RxRasterServices.h" #include "FlatMemStream.h" #include size_t OdGeoMapCurlRequstHelper::requstCallback(void* buffer, size_t size, size_t nmemb, void* param) { //param - input to CURLOPT_WRITEDATA option OdBinaryData* binData = (OdBinaryData*)param; binData->setLogicalLength(binData->logicalLength() + unsigned(size * nmemb)); memcpy(binData->asArrayPtr() + binData->logicalLength() - size * nmemb, buffer, size * nmemb * sizeof(OdInt8)); return size * nmemb; } OdResult OdGeoMapCurlRequstHelper::multiRequst(const OdAnsiStringArray& addr, OdArray& arrRes, OdUInt32 uRequestsCount) { OdResult res = eOk; const OdUInt32 uRequestCount = addr.size(); OdArray arrBufRes; arrBufRes.resize(uRequestCount); curl_global_init(CURL_GLOBAL_DEFAULT); //array of addresses can be bigger than GEO_CURL_MAX_CONNECTION_NUM, so we must do request in several steps for (OdUInt32 uShift = 0; uShift < uRequestCount; uShift += uRequestsCount) { const int nConnectionsNumber = odmin(uRequestCount - uShift, uRequestsCount); OdArray m_arrHandles; m_arrHandles.resize(uRequestsCount, nullptr); // Allocate one CURL handle per transfer for (int i = 0; i < nConnectionsNumber; ++i) { CURL* eh = curl_easy_init(); curl_easy_setopt(eh, CURLOPT_WRITEFUNCTION, requstCallback); curl_easy_setopt(eh, CURLOPT_HEADER, 0L); curl_easy_setopt(eh, CURLOPT_URL, addr[i + uShift].c_str()); // don't verify the peer in ssl handshake curl_easy_setopt(eh, CURLOPT_SSL_VERIFYPEER, 0L); curl_easy_setopt(eh, CURLOPT_PRIVATE, addr[i + uShift].c_str()); curl_easy_setopt(eh, CURLOPT_VERBOSE, 0L); curl_easy_setopt(eh, CURLOPT_WRITEDATA, &arrBufRes[i + uShift]); m_arrHandles[i] = eh; } // init a multi stack CURLM* multi_handle = curl_multi_init(); // we can optionally limit the total amount of connections this multi handle uses curl_multi_setopt(multi_handle, CURLMOPT_MAXCONNECTS, uRequestsCount); // add the individual transfers for (int i = 0; i < nConnectionsNumber; ++i) { curl_multi_add_handle(multi_handle, m_arrHandles[i]); } int still_running = 0; // keep number of running handles do { CURLMcode mc = curl_multi_perform(multi_handle, &still_running); if (still_running) { // wait for activity, timeout or "nothing" mc = curl_multi_poll(multi_handle, NULL, 0, 1000, NULL); } if (mc) { break; } } while (still_running); // see how the transfers went CURLMsg* msg; // for picking up messages with the transfer status int msgs_left; // how many messages are left while ((msg = curl_multi_info_read(multi_handle, &msgs_left)) != nullptr) { if (msg->msg == CURLMSG_DONE) { if (CURLE_OK != msg->data.result) { fprintf(stderr, "HTTP transfer completed with status %d\n", msg->data.result); res = eInternetUnknownError; } } } for (int i = 0; i < nConnectionsNumber; ++i) { curl_multi_remove_handle(multi_handle, m_arrHandles[i]); curl_easy_cleanup(m_arrHandles[i]); } curl_multi_cleanup(multi_handle); } curl_global_cleanup(); // put images to result: OdRxRasterServicesPtr pRasterSvcs = odrxDynamicLinker()->loadModule(RX_RASTER_SERVICES_APPNAME); arrRes.resize(uRequestCount); for (OdUInt32 i = 0; i < uRequestCount; ++i) { try { const OdBinaryData& imageData = arrBufRes[i]; OdStreamBufPtr pStream = OdFlatMemStream::createNew((void*)imageData.asArrayPtr(), imageData.size()); arrRes[i] = pRasterSvcs->loadRasterImage(pStream); } catch (...) { //in case of error responce } } return res; } OdResult OdGeoMapCurlRequstHelper::simpleRequst(const OdAnsiString& addr, OdBinaryData& buffer) { curl_global_init(CURL_GLOBAL_DEFAULT); CURL* curl = curl_easy_init(); if (!curl) { return eInvalidContext; } curl_easy_setopt(curl, CURLOPT_URL, addr.c_str()); // don't verify the peer in ssl handshake curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, requstCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer); OdResult res = eOk; if (CURLE_OK != curl_easy_perform(curl)) { res = eInternetUnknownError; } curl_easy_cleanup(curl); curl_global_cleanup(); return res; }