HTTPFileSource.cpp

Go to the documentation of this file.
00001 //===========================================================================
00002 //Copyright (C) 2003, 2004 Zentaro Kavanagh
00003 //
00004 //Redistribution and use in source and binary forms, with or without
00005 //modification, are permitted provided that the following conditions
00006 //are met:
00007 //
00008 //- Redistributions of source code must retain the above copyright
00009 //  notice, this list of conditions and the following disclaimer.
00010 //
00011 //- Redistributions in binary form must reproduce the above copyright
00012 //  notice, this list of conditions and the following disclaimer in the
00013 //  documentation and/or other materials provided with the distribution.
00014 //
00015 //- Neither the name of Zentaro Kavanagh nor the names of contributors 
00016 //  may be used to endorse or promote products derived from this software 
00017 //  without specific prior written permission.
00018 //
00019 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00020 //``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00021 //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00022 //PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE ORGANISATION OR
00023 //CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00024 //EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00025 //PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00026 //PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00027 //LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00028 //NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00029 //SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00030 //===========================================================================
00031 #include "stdafx.h"
00032 #include "httpfilesource.h"
00033 
00034 HTTPFileSource::HTTPFileSource(void)
00035         :       mBufferLock(NULL)
00036         ,       mIsChunked(false)
00037         ,       mIsFirstChunk(true)
00038         ,       mChunkRemains(0)
00039         ,       mNumLeftovers(0)
00040 {
00041         mBufferLock = new CCritSec;
00042 #ifdef OGGCODECS_LOGGING
00043         debugLog.open("d:\\zen\\logs\\htttp.log", ios_base::out);
00044         fileDump.open("d:\\zen\\logs\\filedump.ogg", ios_base::out|ios_base::binary);
00045         rawDump.open("D:\\zen\\logs\\rawdump.out", ios_base::out|ios_base::binary);
00046 #endif
00047         mInterBuff = new unsigned char[RECV_BUFF_SIZE* 2];
00048 
00049 }
00050 
00051 HTTPFileSource::~HTTPFileSource(void)
00052 {
00053         //debugLog<<"About to close socket"<<endl;
00054         close();
00055         //debugLog<<"Winsock ended"<<endl;
00056 #ifdef OGGCODECS_LOGGING
00057         debugLog.close();
00058         fileDump.close();
00059         rawDump.close();
00060 #endif
00061         delete mBufferLock;
00062         delete mInterBuff;
00063 }
00064 
00065 void HTTPFileSource::unChunk(unsigned char* inBuff, unsigned long inNumBytes) 
00066 {
00067 
00068         //This method is a bit rough and ready !!
00069         ASSERT(inNumBytes > 2);
00070         rawDump.write((char*)inBuff, inNumBytes);
00071         //debugLog<<"UnChunk"<<endl;
00072         unsigned long locNumBytesLeft = inNumBytes;
00073 
00074         memcpy((void*)(mInterBuff + mNumLeftovers), (const void*)inBuff, inNumBytes);
00075         locNumBytesLeft +=  mNumLeftovers;
00076         mNumLeftovers = 0;
00077         unsigned char* locWorkingBuffPtr = mInterBuff;
00078 
00079         //debugLog<<"inNumBytes = "<<inNumBytes<<endl;
00080 
00081         while (locNumBytesLeft > 8) {
00082                 //debugLog<<"---"<<endl;
00083                 //debugLog<<"Bytes left = "<<locNumBytesLeft<<endl;
00084                 //debugLog<<"ChunkRemaining = "<<mChunkRemains<<endl;
00085 
00086                 if (mChunkRemains == 0) {
00087                         //debugLog<<"Zero bytes of chunk remains"<<endl;
00088 
00089                         //Assign to a string for easy manipulation of the hex size
00090                         string locTemp;
00091                 
00092                         if (mIsFirstChunk) {
00093                                 //debugLog<<"It's the first chunk"<<endl;
00094                                 mIsFirstChunk = false;
00095                                 locTemp = (char*)locWorkingBuffPtr;
00096                         } else {
00097                                 //debugLog<<"Not the first chunk"<<endl;
00098                                 //debugLog<<"Skip bytes = "<<(int)locWorkingBuffPtr[0]<<(int)locWorkingBuffPtr[1]<<endl;
00099                                 locTemp = (char*)(locWorkingBuffPtr + 2);
00100                                 locWorkingBuffPtr+=2;
00101                                 locNumBytesLeft -= 2;
00102                         }
00103 
00104         /*              if (mLeftOver != "") {
00105                                 debugLog<<"Sticking the leftovers back together..."<<endl;
00106                                 locTemp = mLeftOver + locTemp;
00107                                 mLeftOver = "";
00108                         }*/
00109 
00110                         size_t locChunkSizePos = locTemp.find("\r\n");
00111                         
00112                         
00113                         if (locChunkSizePos != string::npos) {
00114                                 //debugLog<<"Found the size bytes "<<endl;
00115                                 //Get a string representation of the hex string that tells us the size of the chunk
00116                                 string locChunkSizeStr = locTemp.substr(0, locChunkSizePos);
00117                                 //debugLog<<"Sizingbuytes " << locChunkSizeStr<<endl;
00118                                 char* locDummyPtr = NULL;
00119 
00120                                 //Convert it to a number
00121                                 mChunkRemains = strtol(locChunkSizeStr.c_str(), &locDummyPtr, 16);
00122 
00123                                 //debugLog<<"Chunk reamining "<<mChunkRemains<<endl;
00124                                 //The size of the crlf 's and the chunk size value
00125                                 unsigned long locGuffSize = (unsigned long)(locChunkSizeStr.size() + 2);
00126                                 locWorkingBuffPtr +=  locGuffSize;
00127                                 locNumBytesLeft -= locGuffSize;
00128                         } else {
00129                                 //debugLog<<"************************************** "<<endl;
00130                         
00131 
00132                         }
00133                 }
00134 
00135                 //This is the end of file
00136                 if (mChunkRemains == 0) {
00137                         //debugLog<<"EOF"<<endl;
00138                         return;
00139                 }
00140 
00141                 //If theres less bytes than the remainder of the chunk
00142                 if (locNumBytesLeft < mChunkRemains) {
00143                         //debugLog<<"less bytes remain than the chunk needs"<<endl;
00144                         
00145                         mFileCache.write((const unsigned char*)locWorkingBuffPtr, locNumBytesLeft );
00146                         fileDump.write((char*)locWorkingBuffPtr, locNumBytesLeft);
00147                         locWorkingBuffPtr += locNumBytesLeft;
00148                         mChunkRemains -= locNumBytesLeft;
00149                         locNumBytesLeft = 0;
00150                 } else {
00151                         //debugLog<<"more bytes remain than the chunk needs"<<endl;
00152                         mFileCache.write((const unsigned char*)locWorkingBuffPtr, mChunkRemains );
00153                         fileDump.write((char*)locWorkingBuffPtr, mChunkRemains);
00154                         locWorkingBuffPtr += mChunkRemains;
00155                         locNumBytesLeft -= mChunkRemains;
00156                         mChunkRemains = 0;
00157                 }
00158 
00159         }
00160 
00161         if (locNumBytesLeft != 0) {
00162                 //debugLog<<"There is a non- zero amount of bytes leftover... buffer them up for next time..."<<endl;
00163                 memcpy((void*)mInterBuff, (const void*)locWorkingBuffPtr, locNumBytesLeft);
00164                 mNumLeftovers = locNumBytesLeft;
00165         }
00166 }
00167 void HTTPFileSource::DataProcessLoop() {
00168         //debugLog<<"DataProcessLoop: "<<endl;
00169         int locNumRead = 0;
00170         char* locBuff = NULL;
00171         DWORD locCommand = 0;
00172         bool locSeenAny = false;
00173 
00174         locBuff = new char[RECV_BUFF_SIZE];
00175 
00176         while(true) {
00177                 if(CheckRequest(&locCommand) == TRUE) {
00178                         //debugLog<<"Thread Data Process loop received breakout signal..."<<endl;
00179                         delete[] locBuff;
00180                         return;
00181                 }
00182                 //debugLog<<"About to call recv"<<endl;
00183                 locNumRead = recv(mSocket, locBuff, RECV_BUFF_SIZE, 0);
00184                 //debugLog<<"recv complete"<<endl;
00185                 if (locNumRead == SOCKET_ERROR) {
00186                         int locErr = WSAGetLastError();
00187                         //debugLog<<"Socket error receiving - Err No = "<<locErr<<endl;
00188                         mWasError = true;
00189                         break;
00190                 }
00191 
00192                 if (locNumRead == 0) {
00193                         //debugLog<<"Read last bytes..."<<endl;
00194                         mIsEOF = true;
00195                         delete[] locBuff;
00196                         return;
00197                 }
00198 
00199                 {//CRITICAL SECTION - PROTECTING BUFFER STATE
00200                         CAutoLock locLock(mBufferLock);
00201                         //debugLog <<"Num Read = "<<locNumRead<<endl;
00202                         if (mSeenResponse) {
00203                                 //Add to buffer
00204 
00205                                 if (mIsChunked) {
00206                                         unChunk((unsigned char*)locBuff, locNumRead);
00207                                 } else {
00208                                         mFileCache.write((const unsigned char*)locBuff, locNumRead);
00209                                 }
00210                         
00211                                 //Dump to file
00212                                 //fileDump.write(locBuff, locNumRead);
00213                         } else {
00214                                 //if (!locSeenAny) {
00215                                 //      locSeenAny = true;
00216                                 //      //Start of response
00217                                 //      if (locBuff[0] != '2') {
00218                                 //              mWasError = true;
00219                                 //              delete[] locBuff;
00220                                 //              return;
00221                                 //      }
00222                                 //}
00223                                 string locTemp = locBuff;
00224                                 //debugLog<<"Binary follows... "<<endl<<locTemp<<endl;
00225                                 size_t locPos = locTemp.find("\r\n\r\n");
00226                                 if (locPos != string::npos) {
00227                                         //Found the break
00228                                         //debugLog<<"locPos = "<<locPos<<endl;
00229                                         mSeenResponse = true;
00230                                         mLastResponse = locTemp.substr(0, locPos);
00231 
00232                                         if (locTemp.find("Transfer-Encoding: chunked") != string::npos) {
00233                                                 mIsChunked = true;
00234                                         }
00235 
00236                                         char* locBuff2 = locBuff + locPos + 4;  //View only - don't delete.
00237                                         locTemp = locBuff2;
00238 
00239                                         if (mIsChunked) {
00240                                                 unChunk((unsigned char*)locBuff2, locNumRead - locPos - 4);
00241                                         } else {
00242                         //debugLog<<"Start of data follows"<<endl<<locTemp<<endl;
00243                                                 mFileCache.write((const unsigned char*)locBuff2, (locNumRead - (locPos + 4)));
00244                                         }
00245                                 }
00246                         }
00247                 } //END CRITICAL SECTION
00248         }
00249 
00250         delete[] locBuff;
00251 }
00252 
00253 
00254 DWORD HTTPFileSource::ThreadProc(void) {
00255         //debugLog<<"ThreadProc:"<<endl;
00256         while(true) {
00257                 DWORD locThreadCommand = GetRequest();
00258                 
00259                 switch(locThreadCommand) {
00260                         case THREAD_EXIT:
00261                                 
00262                                 Reply(S_OK);
00263                                 return S_OK;
00264 
00265                         case THREAD_RUN:
00266                                 
00267                                 Reply(S_OK);
00268                                 DataProcessLoop();
00269                                 break;
00270                 }
00271         }
00272         return S_OK;
00273 }
00274 unsigned long HTTPFileSource::seek(unsigned long inPos) {
00275         //Close the socket down
00276         //Open up a new one to the same place.
00277         //Make the partial content request.
00278         //debugLog<<"Seeking to "<<inPos<<endl;
00279         if (mFileCache.readSeek(inPos)) {
00280                 return inPos;
00281         } else {
00282                 return (unsigned long) -1;
00283         }
00284         
00285 }
00286 
00287 
00288 void HTTPFileSource::close() {
00289         //Killing thread
00290         //debugLog<<"HTTPFileSource::close()"<<endl;
00291         if (ThreadExists() == TRUE) {
00292                 //debugLog<<"Calling Thread to EXIT"<<endl;
00293                 CallWorker(THREAD_EXIT);
00294                 //debugLog<<"Killing thread..."<<endl;
00295                 Close();
00296                 //debugLog<<"After Close called on CAMThread"<<endl;
00297         }
00298         
00299         //debugLog<<"Closing socket..."<<endl;
00300         //Close the socket down.
00301         closeSocket();
00302 }
00303 
00304 bool HTTPFileSource::startThread() {
00305         if (ThreadExists() == FALSE) {
00306                 Create();
00307         }
00308         CallWorker(THREAD_RUN);
00309         return true;
00310 }
00311 bool HTTPFileSource::open(string inSourceLocation) {
00312         //Open network connection and start feeding data into a buffer
00313         //
00314         mSeenResponse = false;
00315         mLastResponse = "";
00316         //debugLog<<"Open: "<<inSourceLocation<<endl;
00317 
00318         { //CRITICAL SECTION - PROTECTING STREAM BUFFER
00319                 CAutoLock locLock(mBufferLock);
00320                 
00321                 //Init rand number generator
00322                 LARGE_INTEGER locTicks;
00323                 QueryPerformanceCounter(&locTicks);
00324                 srand((unsigned int)locTicks.LowPart);
00325 
00326                 int locRand = rand();
00327 
00328                 string locCacheFileName = getenv("TEMP");
00329                 //debugLog<<"Temp = "<<locCacheFileName<<endl;
00330                 locCacheFileName += "\\filecache";
00331                 
00332                 locCacheFileName += StringHelper::numToString(locRand);
00333                 locCacheFileName += ".ogg";
00334                 //debugLog<<"Cache file  = "<<locCacheFileName<<endl;
00335                 if(mFileCache.open(locCacheFileName)) {
00336                         //debugLog<<"OPEN : Cach file opened"<<endl;
00337                 }
00338         } //END CRITICAL SECTION
00339 
00340         bool locIsOK = setupSocket(inSourceLocation);
00341 
00342         if (!locIsOK) {
00343                 //debugLog<<"Setup socket FAILED"<<endl;
00344                 closeSocket();
00345                 return false;
00346         }
00347 
00348         //debugLog<<"Sending request..."<<endl;
00349 
00350         //How is filename already set ??
00351         httpRequest(assembleRequest(mFileName));
00352         //debugLog<<"Socket ok... starting thread"<<endl;
00353         locIsOK = startThread();
00354 
00355 
00356         return locIsOK;
00357 }
00358 void HTTPFileSource::clear() {
00359         //Reset flags.
00360         mIsEOF = false;
00361         mWasError = false;
00362 }
00363 bool HTTPFileSource::isEOF() {
00364         { //CRITICAL SECTION - PROTECTING STREAM BUFFER
00365                 CAutoLock locLock(mBufferLock);
00366                 unsigned long locSizeBuffed = mFileCache.bytesAvail();;
00367         
00368                 //debugLog<<"isEOF : Amount Buffered avail = "<<locSizeBuffed<<endl;
00369                 if ((locSizeBuffed == 0) && mIsEOF) {
00370                         //debugLog<<"isEOF : It is EOF"<<endl;
00371                         return true;
00372                 } else {
00373                         //debugLog<<"isEOF : It's not EOF"<<endl;
00374                         return false;
00375                 }
00376         } //END CRITICAL SECTION
00377 
00378 }
00379 unsigned long HTTPFileSource::read(char* outBuffer, unsigned long inNumBytes) {
00380         //Reads from the buffer, will return 0 if nothing in buffer.
00381         // If it returns 0 check the isEOF flag to see if it was the end of file or the network is just slow.
00382 
00383         { //CRITICAL SECTION - PROTECTING STREAM BUFFER
00384                 CAutoLock locLock(mBufferLock);
00385                 
00386                 //debugLog<<"Read:"<<endl;
00387                 if((mFileCache.bytesAvail() == 0) || mWasError) {
00388                         //debugLog<<"read : Can't read is error or eof"<<endl;
00389                         return 0;
00390                 } else {
00391                         //debugLog<<"Reading from buffer"<<endl;
00392                         
00393                         unsigned long locNumRead = mFileCache.read((unsigned char*)outBuffer, inNumBytes);
00394 
00395                         //debugLog<<locNumRead<<" bytes read from buffer"<<endl;
00396                         return locNumRead;
00397                 }
00398         } //END CRITICAL SECTION
00399 }

Generated on Tue Feb 15 14:54:19 2005 for oggdsf by  doxygen 1.3.9