void VSICurlStreamingHandle::StopDownload() { if (hThread) { //if (ENABLE_DEBUG) CPLDebug("VSICURL", "Stop download for %s", pszURL); AcquireMutex(); /* Signal to the producer that we ask for download interruption */ bAskDownloadEnd = TRUE; CPLCondSignal(hCondConsumer); /* Wait for the producer to have finished */ while(bDownloadInProgress) CPLCondWait(hCondProducer, hRingBufferMutex); bAskDownloadEnd = FALSE; ReleaseMutex(); CPLJoinThread(hThread); hThread = NULL; curl_easy_cleanup(hCurlHandle); hCurlHandle = NULL; } oRingBuffer.Reset(); bDownloadStopped = FALSE; }
int VSICurlStreamingHandle::Seek( vsi_l_offset nOffset, int nWhence ) { if( curOffset >= BKGND_BUFFER_SIZE ) { if (ENABLE_DEBUG) CPLDebug("VSICURL", "Invalidating cache and file size due to Seek() beyond caching zone"); CPLFree(pCachedData); pCachedData = NULL; nCachedSize = 0; AcquireMutex(); bHastComputedFileSize = FALSE; fileSize = 0; ReleaseMutex(); } if (nWhence == SEEK_SET) { curOffset = nOffset; } else if (nWhence == SEEK_CUR) { curOffset = curOffset + nOffset; } else { curOffset = GetFileSize() + nOffset; } bEOF = FALSE; return 0; }
void VSICurlStreamingHandle::PutRingBufferInCache() { if (nRingBufferFileOffset >= BKGND_BUFFER_SIZE) return; AcquireMutex(); /* Cache any remaining bytes available in the ring buffer */ size_t nBufSize = oRingBuffer.GetSize(); if ( nBufSize > 0 ) { if (nRingBufferFileOffset + nBufSize > BKGND_BUFFER_SIZE) nBufSize = (size_t) (BKGND_BUFFER_SIZE - nRingBufferFileOffset); GByte* pabyTmp = (GByte*) CPLMalloc(nBufSize); oRingBuffer.Read(pabyTmp, nBufSize); /* Signal to the producer that we have ingested some bytes */ CPLCondSignal(hCondConsumer); AddRegion(nRingBufferFileOffset, nBufSize, pabyTmp); nRingBufferFileOffset += nBufSize; CPLFree(pabyTmp); } ReleaseMutex(); }
void VSICurlStreamingHandle::DownloadInThread() { VSICurlSetOptions(hCurlHandle, pszURL); static int bHasCheckVersion = FALSE; static int bSupportGZip = FALSE; if (!bHasCheckVersion) { bSupportGZip = strstr(curl_version(), "zlib/") != NULL; bHasCheckVersion = TRUE; } if (bSupportGZip && CSLTestBoolean(CPLGetConfigOption("CPL_CURL_GZIP", "YES"))) { curl_easy_setopt(hCurlHandle, CURLOPT_ENCODING, "gzip"); } if (pabyHeaderData == NULL) pabyHeaderData = (GByte*) CPLMalloc(HEADER_SIZE + 1); nHeaderSize = 0; nBodySize = 0; nHTTPCode = 0; curl_easy_setopt(hCurlHandle, CURLOPT_HEADERDATA, this); curl_easy_setopt(hCurlHandle, CURLOPT_HEADERFUNCTION, VSICurlStreamingHandleReceivedBytesHeader); curl_easy_setopt(hCurlHandle, CURLOPT_WRITEDATA, this); curl_easy_setopt(hCurlHandle, CURLOPT_WRITEFUNCTION, VSICurlStreamingHandleReceivedBytes); char szCurlErrBuf[CURL_ERROR_SIZE+1]; szCurlErrBuf[0] = '\0'; curl_easy_setopt(hCurlHandle, CURLOPT_ERRORBUFFER, szCurlErrBuf ); CURLcode eRet = curl_easy_perform(hCurlHandle); curl_easy_setopt(hCurlHandle, CURLOPT_WRITEDATA, NULL); curl_easy_setopt(hCurlHandle, CURLOPT_WRITEFUNCTION, NULL); curl_easy_setopt(hCurlHandle, CURLOPT_HEADERDATA, NULL); curl_easy_setopt(hCurlHandle, CURLOPT_HEADERFUNCTION, NULL); AcquireMutex(); if (!bAskDownloadEnd && eRet == 0 && !bHastComputedFileSize) { poFS->AcquireMutex(); CachedFileProp* cachedFileProp = poFS->GetCachedFileProp(pszURL); cachedFileProp->fileSize = fileSize = nBodySize; cachedFileProp->bHastComputedFileSize = bHastComputedFileSize = TRUE; if (ENABLE_DEBUG) CPLDebug("VSICURL", "File size = " CPL_FRMT_GUIB, fileSize); poFS->ReleaseMutex(); } bDownloadInProgress = FALSE; bDownloadStopped = TRUE; /* Signal to the consumer that the download has ended */ CPLCondSignal(hCondProducer); ReleaseMutex(); }
task main () { // resets odometry AcquireMutex(semaphore_odometry); set_position(robot_odometry, 0, 0, 0); ReleaseMutex(semaphore_odometry); // resets motor encoders hogCPU(); nMotorEncoder[motorA] = 0; nMotorEncoder[motorC] = 0; releaseCPU(); StartTask(updateOdometry); track_wall(); StopTask(updateOdometry); }
/* * Sets speed to motors */ int setSpeedBase(float v, float w) { // Start the motors so that the robot gets // v m/s linear speed and w RADIAN/s angular speed float w_r = (L * w + 2 * v)/(2*R); float w_l = (2*v - R*w_r)/R; // Parameters of power/speed transfer float mR = 5.5058, mL = 5.5092, nR = 1.4976, nL = 1.8269; //float mR = 5.80117, mL = 5.76965, nR = -0.20796, nL = 0.138482; float motorPowerRight, motorPowerLeft; // Sets the power for both motors if(v == 0 && w == 0){ motorPowerLeft = 0; motorPowerRight = 0; } else{ motorPowerLeft = mL * w_l + nL; motorPowerRight = mR * w_r + nR + 1.15; } // Set current speed with semaphore AcquireMutex(access_speed); curV = v; curW = w; ReleaseMutex(access_speed); // Checks if calculated power exceeds the motors capacity if (motorPowerLeft <= 80 && motorPowerRight <= 80) { hogCPU(); motor[motorA] = motorPowerLeft; motor[motorC] = motorPowerRight; releaseCPU(); return 1; } else { // Too much power, sets the power to the maximum possible hogCPU(); motor[motorA] = 80; motor[motorC] = 80; releaseCPU(); return 0; } }
//the program below uses feedback from encoders to determine how much the robot turns. task main() { int trayectoria = 1; // chooses trajectory to run float thetaINIT = 0; // initial theta (different for each trajectory) if (trayectoria == 1) { thetaINIT = (PI)/2; } else if (trayectoria == 2) { thetaINIT = 0; } // reset odometry values and motor encoders // resets odometry AcquireMutex(semaphore_odometry); set_position(robot_odometry, 0, 0, thetaINIT); ReleaseMutex(semaphore_odometry); // resets motor encoders hogCPU(); nMotorEncoder[motorA] = 0; nMotorEncoder[motorC] = 0; releaseCPU(); StartTask(updateOdometry); // executes the required trajectory if (trayectoria == 1) { ejecutarTrayectoria1(); } else if (trayectoria == 2) { ejecutarTrayectoria2(); } StopTask(updateOdometry); Close(hFileHandle, nIoResult); }
// TASK TO BE LAUNCHED SIMULTANEOUSLY to "main"!! task updateOdometry(){ float cycle = 0.01; // we want to update odometry every 0.01 s int step = 20; // we want to write odometry data each 20 steps float dSl,dSr,dS,dx,dy,dT; float x, y, th; string odometryString = ""; strcat(odometryString, "odometry = ["); // concatenate string2 into string1 string sFileName = "odometrylog.txt"; CloseAllHandles(nIoResult); // // Deletes the file if it already exists // Delete(sFileName, nIoResult); hFileHandle = 0; OpenWrite(hFileHandle, nIoResult, sFileName, nFileSize); WriteText(hFileHandle, nIoResult, odometryString); while (true){ // show each step on screen and write in the string float timeAux = nPgmTime; float timeAux2; // read tachometers, and estimate how many m. each wheel has moved since last update // RESET tachometer right after to start including the "moved" degrees turned in next iteration // locks the cpu to modify the motors power // CPU LOCKED hogCPU(); dSl = nMotorEncoder[motorA]; dSr = nMotorEncoder[motorC]; nMotorEncoder[motorA] = 0; nMotorEncoder[motorC] = 0; releaseCPU(); // CPU RELEASED // calculates odometry dSl = R * degToRad(dSl); dSr = R * degToRad(dSr); dS = (dSr + dSl) / 2; dT = (dSr - dSl) / L; dx = dS * cos(robot_odometry.th + (dT/2)); dy = dS * sin(robot_odometry.th + (dT/2)); x = robot_odometry.x + dx; y = robot_odometry.y + dy; th = normTheta(robot_odometry.th + dT); // updates odometry AcquireMutex(semaphore_odometry); set_position(robot_odometry, x, y, th); ReleaseMutex(semaphore_odometry); // Write final string into file if(step==20){ step = 0; string temp, temp2; StringFormat(temp, "%.2f, %.2f,", x, y); StringFormat(temp2, "%.2f; \n", th); strcat(temp,temp2); WriteText(hFileHandle, nIoResult, temp); } step++; // Wait until cycle is completed timeAux2 = nPgmTime; if ((timeAux2 - timeAux) < (cycle * 1000)) { Sleep( (cycle * 1000) - (timeAux2 - timeAux) ); } } }
void track_wall() { float distanciaParaParar = 20; float distanciaAlMuro = 20; float umbral = 0; float v = 0.2; float w = 0; // Para evitar el esmorramiento contra un muro frontal while(SensorValue[sonarSensorFrontal] > distanciaParaParar) { AcquireMutex(semaphore_odometry); float x = robot_odometry.x; float y = robot_odometry.y; float th = robot_odometry.th; ReleaseMutex(semaphore_odometry); float sval = SensorValue[sonarSensorLateral]; string temp; StringFormat(temp, "%.2f", sval); nxtDisplayBigTextLine(2, temp); string temp2; StringFormat(temp2, "%.2f", th); nxtDisplayBigTextLine(5, temp2); // Oscila a una distancia segura de la pared lateral // Debe girar a la derecha porque se esta alejando if (SensorValue[sonarSensorLateral] > distanciaAlMuro + umbral) { w = -v; if(th < -0.2){ w = 0; } } // Debe girar a la izquierda porque se esta acercando else if(SensorValue[sonarSensorLateral] < distanciaAlMuro - umbral) { w = v; if(th > 0.2){ w = 0; } } else { if(th > 0.2){ w = -(v*0.9); } else if(th < -0.2){ w = v*0.9; } else{ w = 0; } } setSpeed(v,w); } // Gira al encontrarse con un muro de frente float theta, thetaFinal; float errorTheta = 0.005; // turn 90 degrees on the robot setSpeed(0,0); // condicion de parada AcquireMutex(semaphore_odometry); float x = robot_odometry.x; float y = robot_odometry.y; float th = robot_odometry.th; ReleaseMutex(semaphore_odometry); theta = th; thetaFinal = (PI)/2; PlaySoundFile("wilhelmA.rso"); Sleep(1200); v = 0; w = 1.5; setSpeed(v,w); while(abs(theta - thetaFinal) > errorTheta) { //nxtDisplayTextLine(3, "dist %2.2f", euclideanDistance(x,xFinal,y,yFinal)); //nxtDisplayTextLine(4, "Theta: %2.2f", abs(theta - thetaFinal)); AcquireMutex(semaphore_odometry); theta = robot_odometry.th; ReleaseMutex(semaphore_odometry); } }
void ejecutarTrayectoria2() { float x, y, xFinal, yFinal, theta, thetaFinal; float errorTheta = 0.008; float errorDist = 0.01; // turn 90 degrees on the robot float v = 0; float w = 1; setSpeed(v,w); // condicion de parada theta = 0; thetaFinal = (PI)/2; while(abs(theta - thetaFinal) > errorTheta) { AcquireMutex(semaphore_odometry); x = robot_odometry.x; y = robot_odometry.y; theta = robot_odometry.th; ReleaseMutex(semaphore_odometry); } nxtDisplayBigTextLine(2, "Tramo 1"); // generate 1st part of trayectory v = 0.2; w = 1.33333; setSpeed(v,-w); xFinal = 0.1061; yFinal = 0.1434; thetaFinal = degToRad(17); while( euclideanDistance(x,xFinal,y,yFinal) > errorDist && abs(theta - thetaFinal) > errorTheta) { AcquireMutex(semaphore_odometry); x = robot_odometry.x; y = robot_odometry.y; theta = robot_odometry.th; ReleaseMutex(semaphore_odometry); } nxtDisplayBigTextLine(2, "Tramo 2"); // generate 2nd part of trayectory v = 0.2; w = 0; setSpeed(v,w); errorDist = 0.05; xFinal = 0.8711; yFinal = 0.3773; thetaFinal = degToRad(17); while( euclideanDistance(x,xFinal,y,yFinal) > errorDist) { nxtDisplayTextLine(3, "dist %2.2f", euclideanDistance(x,xFinal,y,yFinal)); nxtDisplayTextLine(4, "x,y: %2.2f %2.2f", x,y); AcquireMutex(semaphore_odometry); x = robot_odometry.x; y = robot_odometry.y; theta = robot_odometry.th; ReleaseMutex(semaphore_odometry); } nxtDisplayBigTextLine(2, "Tramo 3"); // generate 3rd part of trayectory v = 0.2; w = 0.5; setSpeed(v,-w); errorDist = 0.01; xFinal = 0.8711; yFinal = -0.3877; thetaFinal = normTheta(degToRad(-197)); while( euclideanDistance(x,xFinal,y,yFinal) > errorDist && abs(theta - thetaFinal) > errorTheta) { AcquireMutex(semaphore_odometry); x = robot_odometry.x; y = robot_odometry.y; theta = robot_odometry.th; ReleaseMutex(semaphore_odometry); } nxtDisplayBigTextLine(2, "Tramo 4"); // generate 4th part of trayectory v = 0.2; w = 0; setSpeed(v,w); errorDist = 0.05; xFinal = 0.1061; yFinal = -0.1538; thetaFinal = normTheta(degToRad(-197)); while( euclideanDistance(x,xFinal,y,yFinal) > errorDist) { AcquireMutex(semaphore_odometry); x = robot_odometry.x; y = robot_odometry.y; theta = robot_odometry.th; ReleaseMutex(semaphore_odometry); } nxtDisplayBigTextLine(2, "Tramo 5"); // generate 5th part of trayectory v = 0.2; w = 1.33333; setSpeed(v,-w); errorDist = 0.01; xFinal = 0; yFinal = 0; thetaFinal = (PI)/2; while( euclideanDistance(x,xFinal,y,yFinal) > errorDist && abs(theta - thetaFinal) > errorTheta) { AcquireMutex(semaphore_odometry); x = robot_odometry.x; y = robot_odometry.y; theta = robot_odometry.th; ReleaseMutex(semaphore_odometry); } nxtDisplayBigTextLine(2, "FIN"); }
void ejecutarTrayectoria1() { float x, y, xFinal, yFinal, theta, thetaFinal; float errorTheta = 0.005; float errorDist = 0.005; // turn 90 degrees on the robot float v = 0; float w = 1; setSpeed(v,-w); // condicion de parada theta = (PI)/2; thetaFinal = 0; while(abs(theta - thetaFinal) > errorTheta) { //nxtDisplayTextLine(3, "dist %2.2f", euclideanDistance(x,xFinal,y,yFinal)); //nxtDisplayTextLine(4, "Theta: %2.2f", abs(theta - thetaFinal)); AcquireMutex(semaphore_odometry); x = robot_odometry.x; y = robot_odometry.y; theta = robot_odometry.th; ReleaseMutex(semaphore_odometry); } nxtDisplayBigTextLine(2, "Tramo 1"); // generate 1st part of trayectory v = 0.2; w = 0.5; setSpeed(v,w); xFinal = 0; yFinal = 0.8; thetaFinal = (PI); while( euclideanDistance(x,xFinal,y,yFinal) > errorDist && abs(theta - thetaFinal) > errorTheta) { //nxtDisplayTextLine(3, "dist %2.2f", euclideanDistance(x,xFinal,y,yFinal)); //nxtDisplayTextLine(4, "Theta: %2.2f", abs(theta - thetaFinal)); AcquireMutex(semaphore_odometry); x = robot_odometry.x; y = robot_odometry.y; theta = robot_odometry.th; ReleaseMutex(semaphore_odometry); } nxtDisplayBigTextLine(2, "Tramo 2"); // generate 2nd part of trayectory setSpeed(v,-w); xFinal = 0; yFinal = 1.6; thetaFinal = 0; while( euclideanDistance(x,xFinal,y,yFinal) > errorDist && abs(theta - thetaFinal) > errorTheta) { //nxtDisplayTextLine(3, "dist %2.2f", euclideanDistance(x,xFinal,y,yFinal)); //nxtDisplayTextLine(4, "Theta: %2.2f", abs(theta - thetaFinal)); AcquireMutex(semaphore_odometry); x = robot_odometry.x; y = robot_odometry.y; theta = robot_odometry.th; ReleaseMutex(semaphore_odometry); } nxtDisplayBigTextLine(2, "Tramo 3"); // generate 3rd part of trayectory setSpeed(v,-w); xFinal = 0; yFinal = 0.8; thetaFinal = -(PI); while( euclideanDistance(x,xFinal,y,yFinal) > errorDist && abs(theta - thetaFinal) > errorTheta) { //nxtDisplayTextLine(3, "dist %2.2f", euclideanDistance(x,xFinal,y,yFinal)); //nxtDisplayTextLine(4, "Theta: %2.2f", abs(theta - thetaFinal)); AcquireMutex(semaphore_odometry); x = robot_odometry.x; y = robot_odometry.y; theta = robot_odometry.th; ReleaseMutex(semaphore_odometry); } nxtDisplayBigTextLine(2, "Tramo 4"); // generate 4th part of trayectory setSpeed(v,w); xFinal = 0; yFinal = 0; thetaFinal = 0; while( euclideanDistance(x,xFinal,y,yFinal) > errorDist && abs(theta - thetaFinal) > errorTheta) { //nxtDisplayTextLine(3, "dist %2.2f", euclideanDistance(x,xFinal,y,yFinal)); //nxtDisplayTextLine(4, "Theta: %2.2f", abs(theta - thetaFinal)); AcquireMutex(semaphore_odometry); x = robot_odometry.x; y = robot_odometry.y; theta = robot_odometry.th; ReleaseMutex(semaphore_odometry); } nxtDisplayBigTextLine(2, "FIN"); }
int VSICurlStreamingHandle::ReceivedBytesHeader(GByte *buffer, size_t count, size_t nmemb) { size_t nSize = count * nmemb; if (ENABLE_DEBUG) CPLDebug("VSICURL", "Receiving %d bytes for header...", (int)nSize); /* Reset buffer if we have followed link after a redirect */ if (nSize >=9 && (nHTTPCode == 301 || nHTTPCode == 302) && (EQUALN((const char*)buffer, "HTTP/1.0 ", 9) || EQUALN((const char*)buffer, "HTTP/1.1 ", 9))) { nHeaderSize = 0; nHTTPCode = 0; } if (nHeaderSize < HEADER_SIZE) { size_t nSz = MIN(nSize, HEADER_SIZE - nHeaderSize); memcpy(pabyHeaderData + nHeaderSize, buffer, nSz); pabyHeaderData[nHeaderSize + nSz] = '\0'; nHeaderSize += nSz; //CPLDebug("VSICURL", "Header : %s", pabyHeaderData); AcquireMutex(); if (eExists == EXIST_UNKNOWN && nHTTPCode == 0 && strchr((const char*)pabyHeaderData, '\n') != NULL && (EQUALN((const char*)pabyHeaderData, "HTTP/1.0 ", 9) || EQUALN((const char*)pabyHeaderData, "HTTP/1.1 ", 9))) { nHTTPCode = atoi((const char*)pabyHeaderData + 9); if (ENABLE_DEBUG) CPLDebug("VSICURL", "HTTP code = %d", nHTTPCode); /* If moved permanently/temporarily, go on */ if( !(nHTTPCode == 301 || nHTTPCode == 302) ) { poFS->AcquireMutex(); CachedFileProp* cachedFileProp = poFS->GetCachedFileProp(pszURL); cachedFileProp->eExists = eExists = (nHTTPCode == 200) ? EXIST_YES : EXIST_NO; poFS->ReleaseMutex(); } } if ( !(nHTTPCode == 301 || nHTTPCode == 302) && !bHastComputedFileSize) { /* Caution: when gzip compression is enabled, the content-length is the compressed */ /* size, which we are not interested in, so we must not take it into account. */ const char* pszContentLength = strstr((const char*)pabyHeaderData, "Content-Length: "); const char* pszEndOfLine = pszContentLength ? strchr(pszContentLength, '\n') : NULL; if( bCanTrustCandidateFileSize && pszEndOfLine != NULL ) { const char* pszVal = pszContentLength + strlen("Content-Length: "); bHasCandidateFileSize = TRUE; nCandidateFileSize = CPLScanUIntBig(pszVal, pszEndOfLine - pszVal); if (ENABLE_DEBUG) CPLDebug("VSICURL", "Has found candidate file size = " CPL_FRMT_GUIB, nCandidateFileSize); } const char* pszContentEncoding = strstr((const char*)pabyHeaderData, "Content-Encoding: "); pszEndOfLine = pszContentEncoding ? strchr(pszContentEncoding, '\n') : NULL; if( bHasCandidateFileSize && pszEndOfLine != NULL ) { const char* pszVal = pszContentEncoding + strlen("Content-Encoding: "); if( strncmp(pszVal, "gzip", 4) == 0 ) { if (ENABLE_DEBUG) CPLDebug("VSICURL", "GZip compression enabled --> cannot trust candidate file size"); bCanTrustCandidateFileSize = FALSE; } } } ReleaseMutex(); } return nmemb; }
int VSICurlStreamingHandle::ReceivedBytes(GByte *buffer, size_t count, size_t nmemb) { size_t nSize = count * nmemb; nBodySize += nSize; if (ENABLE_DEBUG) CPLDebug("VSICURL", "Receiving %d bytes...", (int)nSize); if( bHasCandidateFileSize && bCanTrustCandidateFileSize && !bHastComputedFileSize ) { poFS->AcquireMutex(); CachedFileProp* cachedFileProp = poFS->GetCachedFileProp(pszURL); cachedFileProp->fileSize = fileSize = nCandidateFileSize; cachedFileProp->bHastComputedFileSize = bHastComputedFileSize = TRUE; if (ENABLE_DEBUG) CPLDebug("VSICURL", "File size = " CPL_FRMT_GUIB, fileSize); poFS->ReleaseMutex(); } AcquireMutex(); if (eExists == EXIST_UNKNOWN) { poFS->AcquireMutex(); CachedFileProp* cachedFileProp = poFS->GetCachedFileProp(pszURL); cachedFileProp->eExists = eExists = EXIST_YES; poFS->ReleaseMutex(); } else if (eExists == EXIST_NO) { ReleaseMutex(); return 0; } while(TRUE) { size_t nFree = oRingBuffer.GetCapacity() - oRingBuffer.GetSize(); if (nSize <= nFree) { oRingBuffer.Write(buffer, nSize); /* Signal to the consumer that we have added bytes to the buffer */ CPLCondSignal(hCondProducer); if (bAskDownloadEnd) { if (ENABLE_DEBUG) CPLDebug("VSICURL", "Download interruption asked"); ReleaseMutex(); return 0; } break; } else { oRingBuffer.Write(buffer, nFree); buffer += nFree; nSize -= nFree; /* Signal to the consumer that we have added bytes to the buffer */ CPLCondSignal(hCondProducer); if (ENABLE_DEBUG) CPLDebug("VSICURL", "Waiting for reader to consume some bytes..."); while(oRingBuffer.GetSize() == oRingBuffer.GetCapacity() && !bAskDownloadEnd) { CPLCondWait(hCondConsumer, hRingBufferMutex); } if (bAskDownloadEnd) { if (ENABLE_DEBUG) CPLDebug("VSICURL", "Download interruption asked"); ReleaseMutex(); return 0; } } } ReleaseMutex(); return nmemb; }
int VSICurlStreamingHandle::Exists() { if (eExists == EXIST_UNKNOWN) { /* Consider that only the files whose extension ends up with one that is */ /* listed in CPL_VSIL_CURL_ALLOWED_EXTENSIONS exist on the server */ /* This can speeds up dramatically open experience, in case the server */ /* cannot return a file list */ /* For example : */ /* gdalinfo --config CPL_VSIL_CURL_ALLOWED_EXTENSIONS ".tif" /vsicurl_streaming/http://igskmncngs506.cr.usgs.gov/gmted/Global_tiles_GMTED/075darcsec/bln/W030/30N030W_20101117_gmted_bln075.tif */ const char* pszAllowedExtensions = CPLGetConfigOption("CPL_VSIL_CURL_ALLOWED_EXTENSIONS", NULL); if (pszAllowedExtensions) { char** papszExtensions = CSLTokenizeString2( pszAllowedExtensions, ", ", 0 ); int nURLLen = strlen(pszURL); int bFound = FALSE; for(int i=0;papszExtensions[i] != NULL;i++) { int nExtensionLen = strlen(papszExtensions[i]); if (nURLLen > nExtensionLen && EQUAL(pszURL + nURLLen - nExtensionLen, papszExtensions[i])) { bFound = TRUE; break; } } if (!bFound) { eExists = EXIST_NO; fileSize = 0; poFS->AcquireMutex(); CachedFileProp* cachedFileProp = poFS->GetCachedFileProp(pszURL); cachedFileProp->bHastComputedFileSize = TRUE; cachedFileProp->fileSize = fileSize; cachedFileProp->eExists = eExists; poFS->ReleaseMutex(); CSLDestroy(papszExtensions); return 0; } CSLDestroy(papszExtensions); } char chFirstByte; int bExists = (Read(&chFirstByte, 1, 1) == 1); AcquireMutex(); poFS->AcquireMutex(); CachedFileProp* cachedFileProp = poFS->GetCachedFileProp(pszURL); cachedFileProp->eExists = eExists = bExists ? EXIST_YES : EXIST_NO; poFS->ReleaseMutex(); ReleaseMutex(); Seek(0, SEEK_SET); } return eExists == EXIST_YES; }
vsi_l_offset VSICurlStreamingHandle::GetFileSize() { WriteFuncStruct sWriteFuncData; WriteFuncStruct sWriteFuncHeaderData; AcquireMutex(); if (bHastComputedFileSize) { vsi_l_offset nRet = fileSize; ReleaseMutex(); return nRet; } ReleaseMutex(); #if LIBCURL_VERSION_NUM < 0x070B00 /* Curl 7.10.X doesn't manage to unset the CURLOPT_RANGE that would have been */ /* previously set, so we have to reinit the connection handle */ if (hCurlHandle) { curl_easy_cleanup(hCurlHandle); hCurlHandle = curl_easy_init(); } #endif CURL* hLocalHandle = curl_easy_init(); VSICurlSetOptions(hLocalHandle, pszURL); VSICURLStreamingInitWriteFuncStruct(&sWriteFuncHeaderData); /* HACK for mbtiles driver: proper fix would be to auto-detect servers that don't accept HEAD */ /* http://a.tiles.mapbox.com/v3/ doesn't accept HEAD, so let's start a GET */ /* and interrupt is as soon as the header is found */ if (strstr(pszURL, ".tiles.mapbox.com/") != NULL) { curl_easy_setopt(hLocalHandle, CURLOPT_HEADERDATA, &sWriteFuncHeaderData); curl_easy_setopt(hLocalHandle, CURLOPT_HEADERFUNCTION, VSICurlStreamingHandleWriteFuncForHeader); sWriteFuncHeaderData.bIsHTTP = strncmp(pszURL, "http", 4) == 0; sWriteFuncHeaderData.bDownloadHeaderOnly = TRUE; } else { curl_easy_setopt(hLocalHandle, CURLOPT_NOBODY, 1); curl_easy_setopt(hLocalHandle, CURLOPT_HTTPGET, 0); curl_easy_setopt(hLocalHandle, CURLOPT_HEADER, 1); } /* We need that otherwise OSGEO4W's libcurl issue a dummy range request */ /* when doing a HEAD when recycling connections */ curl_easy_setopt(hLocalHandle, CURLOPT_RANGE, NULL); /* Bug with older curl versions (<=7.16.4) and FTP. See http://curl.haxx.se/mail/lib-2007-08/0312.html */ VSICURLStreamingInitWriteFuncStruct(&sWriteFuncData); curl_easy_setopt(hLocalHandle, CURLOPT_WRITEDATA, &sWriteFuncData); curl_easy_setopt(hLocalHandle, CURLOPT_WRITEFUNCTION, VSICurlStreamingHandleWriteFuncForHeader); char szCurlErrBuf[CURL_ERROR_SIZE+1]; szCurlErrBuf[0] = '\0'; curl_easy_setopt(hLocalHandle, CURLOPT_ERRORBUFFER, szCurlErrBuf ); double dfSize = 0; curl_easy_perform(hLocalHandle); AcquireMutex(); eExists = EXIST_UNKNOWN; bHastComputedFileSize = TRUE; if (strncmp(pszURL, "ftp", 3) == 0) { if (sWriteFuncData.pBuffer != NULL && strncmp(sWriteFuncData.pBuffer, "Content-Length: ", strlen( "Content-Length: ")) == 0) { const char* pszBuffer = sWriteFuncData.pBuffer + strlen("Content-Length: "); eExists = EXIST_YES; fileSize = CPLScanUIntBig(pszBuffer, sWriteFuncData.nSize - strlen("Content-Length: ")); if (ENABLE_DEBUG) CPLDebug("VSICURL", "GetFileSize(%s)=" CPL_FRMT_GUIB, pszURL, fileSize); } } if (eExists != EXIST_YES) { CURLcode code = curl_easy_getinfo(hLocalHandle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &dfSize ); if (code == 0) { eExists = EXIST_YES; if (dfSize < 0) fileSize = 0; else fileSize = (GUIntBig)dfSize; } else { eExists = EXIST_NO; fileSize = 0; CPLError(CE_Failure, CPLE_AppDefined, "VSICurlStreamingHandle::GetFileSize failed"); } long response_code = 0; curl_easy_getinfo(hLocalHandle, CURLINFO_HTTP_CODE, &response_code); if (response_code != 200) { eExists = EXIST_NO; fileSize = 0; } /* Try to guess if this is a directory. Generally if this is a directory, */ /* curl will retry with an URL with slash added */ char *pszEffectiveURL = NULL; curl_easy_getinfo(hLocalHandle, CURLINFO_EFFECTIVE_URL, &pszEffectiveURL); if (pszEffectiveURL != NULL && strncmp(pszURL, pszEffectiveURL, strlen(pszURL)) == 0 && pszEffectiveURL[strlen(pszURL)] == '/') { eExists = EXIST_YES; fileSize = 0; bIsDirectory = TRUE; } if (ENABLE_DEBUG) CPLDebug("VSICURL", "GetFileSize(%s)=" CPL_FRMT_GUIB " response_code=%d", pszURL, fileSize, (int)response_code); } CPLFree(sWriteFuncData.pBuffer); CPLFree(sWriteFuncHeaderData.pBuffer); poFS->AcquireMutex(); CachedFileProp* cachedFileProp = poFS->GetCachedFileProp(pszURL); cachedFileProp->bHastComputedFileSize = TRUE; #ifdef notdef cachedFileProp->nChecksumOfFirst1024Bytes = nRecomputedChecksumOfFirst1024Bytes; #endif cachedFileProp->fileSize = fileSize; cachedFileProp->eExists = eExists; cachedFileProp->bIsDirectory = bIsDirectory; poFS->ReleaseMutex(); vsi_l_offset nRet = fileSize; ReleaseMutex(); if (hCurlHandle == NULL) hCurlHandle = hLocalHandle; else curl_easy_cleanup(hLocalHandle); return nRet; }
size_t VSICurlStreamingHandle::Read( void *pBuffer, size_t nSize, size_t nMemb ) { GByte* pabyBuffer = (GByte*)pBuffer; size_t nBufferRequestSize = nSize * nMemb; if (nBufferRequestSize == 0) return 0; size_t nRemaining = nBufferRequestSize; AcquireMutex(); int bHastComputedFileSizeLocal = bHastComputedFileSize; vsi_l_offset fileSizeLocal = fileSize; ReleaseMutex(); if (bHastComputedFileSizeLocal && curOffset >= fileSizeLocal) { CPLDebug("VSICURL", "Read attempt beyond end of file"); bEOF = TRUE; } if (bEOF) return 0; if (curOffset < nRingBufferFileOffset) PutRingBufferInCache(); if (ENABLE_DEBUG) CPLDebug("VSICURL", "Read [" CPL_FRMT_GUIB ", " CPL_FRMT_GUIB "[ in %s", curOffset, curOffset + nBufferRequestSize, pszURL); #ifdef notdef if( pCachedData != NULL && nCachedSize >= 1024 && nRecomputedChecksumOfFirst1024Bytes == 0 ) { for(size_t i = 0; i < 1024 / sizeof(int); i ++) { int nVal; memcpy(&nVal, pCachedData + i * sizeof(int), sizeof(int)); nRecomputedChecksumOfFirst1024Bytes += nVal; } if( bHastComputedFileSizeLocal ) { poFS->AcquireMutex(); CachedFileProp* cachedFileProp = poFS->GetCachedFileProp(pszURL); if( cachedFileProp->nChecksumOfFirst1024Bytes == 0 ) { cachedFileProp->nChecksumOfFirst1024Bytes = nRecomputedChecksumOfFirst1024Bytes; } else if( nRecomputedChecksumOfFirst1024Bytes != cachedFileProp->nChecksumOfFirst1024Bytes ) { CPLDebug("VSICURL", "Invalidating previously cached file size. First bytes of file have changed!"); AcquireMutex(); bHastComputedFileSize = FALSE; cachedFileProp->bHastComputedFileSize = FALSE; cachedFileProp->nChecksumOfFirst1024Bytes = 0; ReleaseMutex(); } poFS->ReleaseMutex(); } } #endif /* Can we use the cache ? */ if( pCachedData != NULL && curOffset < nCachedSize ) { size_t nSz = MIN(nRemaining, (size_t)(nCachedSize - curOffset)); if (ENABLE_DEBUG) CPLDebug("VSICURL", "Using cache for [%d, %d[ in %s", (int)curOffset, (int)(curOffset + nSz), pszURL); memcpy(pabyBuffer, pCachedData + curOffset, nSz); pabyBuffer += nSz; curOffset += nSz; nRemaining -= nSz; } /* Is the request partially covered by the cache and going beyond file size ? */ if ( pCachedData != NULL && bHastComputedFileSizeLocal && curOffset <= nCachedSize && curOffset + nRemaining > fileSizeLocal && fileSize == nCachedSize ) { size_t nSz = (size_t) (nCachedSize - curOffset); if (ENABLE_DEBUG && nSz != 0) CPLDebug("VSICURL", "Using cache for [%d, %d[ in %s", (int)curOffset, (int)(curOffset + nSz), pszURL); memcpy(pabyBuffer, pCachedData + curOffset, nSz); pabyBuffer += nSz; curOffset += nSz; nRemaining -= nSz; bEOF = TRUE; } /* Has a Seek() being done since the last Read() ? */ if (!bEOF && nRemaining > 0 && curOffset != nRingBufferFileOffset) { /* Backward seek : we need to restart the download from the start */ if (curOffset < nRingBufferFileOffset) StopDownload(); StartDownload(); #define SKIP_BUFFER_SIZE 32768 GByte* pabyTmp = (GByte*)CPLMalloc(SKIP_BUFFER_SIZE); CPLAssert(curOffset >= nRingBufferFileOffset); vsi_l_offset nBytesToSkip = curOffset - nRingBufferFileOffset; while(nBytesToSkip > 0) { vsi_l_offset nBytesToRead = nBytesToSkip; AcquireMutex(); if (nBytesToRead > oRingBuffer.GetSize()) nBytesToRead = oRingBuffer.GetSize(); if (nBytesToRead > SKIP_BUFFER_SIZE) nBytesToRead = SKIP_BUFFER_SIZE; oRingBuffer.Read(pabyTmp, (size_t)nBytesToRead); /* Signal to the producer that we have ingested some bytes */ CPLCondSignal(hCondConsumer); ReleaseMutex(); if (nBytesToRead) AddRegion(nRingBufferFileOffset, (size_t)nBytesToRead, pabyTmp); nBytesToSkip -= nBytesToRead; nRingBufferFileOffset += nBytesToRead; if (nBytesToRead == 0 && nBytesToSkip != 0) { if (ENABLE_DEBUG) CPLDebug("VSICURL", "Waiting for writer to produce some bytes..."); AcquireMutex(); while(oRingBuffer.GetSize() == 0 && bDownloadInProgress) CPLCondWait(hCondProducer, hRingBufferMutex); int bBufferEmpty = (oRingBuffer.GetSize() == 0); ReleaseMutex(); if (bBufferEmpty && !bDownloadInProgress) break; } } CPLFree(pabyTmp); if (nBytesToSkip != 0) { bEOF = TRUE; return 0; } } if (!bEOF && nRemaining > 0) { StartDownload(); CPLAssert(curOffset == nRingBufferFileOffset); } /* Fill the destination buffer from the ring buffer */ while(!bEOF && nRemaining > 0) { AcquireMutex(); size_t nToRead = oRingBuffer.GetSize(); if (nToRead > nRemaining) nToRead = nRemaining; oRingBuffer.Read(pabyBuffer, nToRead); /* Signal to the producer that we have ingested some bytes */ CPLCondSignal(hCondConsumer); ReleaseMutex(); if (nToRead) AddRegion(curOffset, nToRead, pabyBuffer); nRemaining -= nToRead; pabyBuffer += nToRead; curOffset += nToRead; nRingBufferFileOffset += nToRead; if (nToRead == 0 && nRemaining != 0) { if (ENABLE_DEBUG) CPLDebug("VSICURL", "Waiting for writer to produce some bytes..."); AcquireMutex(); while(oRingBuffer.GetSize() == 0 && bDownloadInProgress) CPLCondWait(hCondProducer, hRingBufferMutex); int bBufferEmpty = (oRingBuffer.GetSize() == 0); ReleaseMutex(); if (bBufferEmpty && !bDownloadInProgress) break; } } if (ENABLE_DEBUG) CPLDebug("VSICURL", "Read(%d) = %d", (int)nBufferRequestSize, (int)(nBufferRequestSize - nRemaining)); size_t nRet = (nBufferRequestSize - nRemaining) / nSize; if (nRet < nMemb) bEOF = TRUE; return nRet; }