⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 httpinput.cpp

📁 FreeAMP(MP3播放)程序源代码-用来研究MP3解码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*____________________________________________________________________________
        
        FreeAmp - The Free MP3 Player

        Portions Copyright (C) 1998-1999 EMusic.com

        This program is free software; you can redistribute it and/or modify
        it under the terms of the GNU General Public License as published by
        the Free Software Foundation; either version 2 of the License, or
        (at your option) any later version.

        This program is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.

        You should have received a copy of the GNU General Public License
        along with this program; if not, write to the Free Software
        Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
        
        $Id: httpinput.cpp,v 1.72 2000/11/14 11:07:09 robert Exp $
____________________________________________________________________________*/

/* system headers */
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <iostream>
#include <errno.h>
#include <assert.h>
#ifdef WIN32
#include <winsock.h>
#include <time.h>
#else
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#ifndef __BEOS__
#include <arpa/inet.h>
#endif
#include <netdb.h>
#include <fcntl.h>
#endif

#include "config.h"

#if HAVE_UNISTD_H
#include <unistd.h>
#elif HAVE_IO_H
#include <io.h>
#else
#error Must have unistd.h or io.h!
#endif // HAVE_UNISTD_H

/* project headers */
#include "httpinput.h"
#include "facontext.h"
#include "log.h"
#include "tstream.h"
#include "debug.h"

const int iBufferSize = 8192;
const int iOverflowSize = 1536;
const int iTriggerSize = 1024;
const char *szDefaultStreamTitle = "SHOUTcast Stream";

#if !defined(WIN32) && !defined(__BEOS__)
#define closesocket(s) close(s)
#endif

#ifndef F_OK
#define F_OK 0
#endif

const int iHttpPort = 80;
const int iMaxHostNameLen = 64;
const int iGetHostNameBuffer = 1024;
const int iBufferUpInterval = 3;
const int iInitialBufferSize = 1024;
const int iHeaderSize = 1024;
const int iICY_OK = 200;
const int iICY_REDIRECT = 302;
const int iTransmitTimeout = 60;

#ifdef WIN32
const char cDirSepChar = '\\';
#else
const char cDirSepChar = '/';
#endif

#define DB Debug_v("%s:%d\n", __FILE__, __LINE__);

#ifndef min
#define min(a,b) ((a) < (b) ? (a) : (b))
#endif

extern    "C"
{
   PhysicalMediaInput *Initialize(FAContext * context)
   {
      return new HttpInput(context);
   }
}

#ifdef WIN32
HINSTANCE g_hinst = NULL;
INT WINAPI
DllMain(HINSTANCE hInstance, ULONG ul_reason_being_called, LPVOID lpReserved)
{
   switch (ul_reason_being_called)
   {
   case DLL_PROCESS_ATTACH:
      g_hinst = hInstance;
      break;

   case DLL_THREAD_ATTACH:
      break;

   case DLL_THREAD_DETACH:
      break;

   case DLL_PROCESS_DETACH:
      break;
   }

   return 1;
}
#endif

HttpInput::HttpInput(FAContext * context):
PhysicalMediaInput(context)
{
   m_path = NULL;
   m_hHandle = -1;
   m_bLoop = false;
   m_bDiscarded = false;
   m_bIsStreaming = true;
   m_pBufferThread = NULL;
   m_fpSave = NULL;
   m_szError = new char[iMaxErrorLen];

   m_pTitleStream = NULL;
   m_bUseBufferReduction = true;
   m_iMetaDataInterval = 0;
   m_uBytesReceived = 0;
   m_bExit = false;
#ifdef WIN32
   m_hWnd = NULL;
#endif

   m_pContext->prefs->GetPrefBoolean(kUseProxyPref, &m_bUseProxy);
   if (m_bUseProxy)
   {
      uint32    len = iMaxUrlLen;

      m_pContext->prefs->GetPrefString(kProxyHostPref, m_szProxyHost, &len);
      if (len == 0)
         m_pContext->log->Error("useProxy is true but ProxyHost "
                                "has no value ?!");
   }
}

HttpInput::~HttpInput()
{
#ifdef WIN32
   if (m_hWnd)
      PostMessage(m_hWnd, WM_QUIT, 0, 0);
#endif

   m_bExit = true;
   m_pSleepSem->Signal();
   m_pPauseSem->Signal();

   if (m_pTitleStream)
      delete    m_pTitleStream;

   if (m_pBufferThread)
   {
      m_pBufferThread->Join();
      delete    m_pBufferThread;
   }

   if (m_hHandle >= 0)
   {
      shutdown(m_hHandle, 2);
      closesocket(m_hHandle);
   }

   if (m_fpSave)
      fclose(m_fpSave);

   delete    m_szError;
}

bool
HttpInput::CanHandle(const char *szUrl, char *szTitle)
{
   bool      bRet;

   bRet = strncmp(szUrl, "http://", 7) == 0;

   if (szTitle && bRet)
      strcpy(szTitle, szDefaultStreamTitle);

   return bRet;
}

Error
HttpInput::Prepare(PullBuffer * &pBuffer)
{
   int32     iBufferSize = iDefaultBufferSize;
   Error     result;

   if (m_pOutputBuffer)
   {
      delete    m_pOutputBuffer;

      m_pOutputBuffer = NULL;
   }

   if (!IsError
       (m_pContext->prefs->GetPrefInt32(kInputBufferSizePref, &iBufferSize)))
      iBufferSize *= 1024;

   m_pOutputBuffer = new PullBuffer(iBufferSize, iDefaultOverflowSize,
                                    m_pContext);
   assert(m_pOutputBuffer);

   pBuffer = m_pOutputBuffer;

   result = Run();
   if (IsError(result))
   {
      ReportError("Could not initialize http streaming plugin.");
      return result;
   }

   return kError_NoErr;
}

Error
HttpInput::Close(void)
{
#ifdef WIN32
   if (m_hWnd)
      PostMessage(m_hWnd, WM_QUIT, 0, 0);
#endif

   delete    m_pOutputBuffer;

   m_pOutputBuffer = NULL;

   if (m_hHandle >= 0)
   {
      shutdown(m_hHandle, 2);
      closesocket(m_hHandle);
   }

   if (m_fpSave)
      fclose(m_fpSave);

   return kError_NoErr;
}

Error
HttpInput::Run(void)
{
   if (!m_pBufferThread)
   {
      m_pBufferThread = Thread::CreateThread();
      if (!m_pBufferThread)
      {
         return (Error) kError_CreateThreadFailed;
      }
      m_pBufferThread->Create(HttpInput::StartWorkerThread, this);
   }

   return kError_NoErr;
}

bool
HttpInput::PauseLoop(bool bLoop)
{
   bool      bRet;

   m_bLoop = bLoop;
   bRet = m_bDiscarded;
   m_bDiscarded = false;

   return bRet;
}

#ifdef WIN32
#define WM_WINDOWS_IS_DONE_PICKING_ITS_BUTT (WM_USER + 1)

static LRESULT WINAPI WndProc(HWND hwnd, UINT msg,

                              WPARAM wParam, LPARAM lParam);

Error
HttpInput::Win32GetHostByName(char *szHostName, struct hostent *pHostInfo)
{
   WNDCLASS  wc;
   MSG       msg;
   HWND      hWnd;
   HANDLE    hHandle;
   char      szBuffer[MAXGETHOSTSTRUCT];
   int       result = -1;

   memset(&wc, 0x00, sizeof(WNDCLASS));

   wc.style = CS_HREDRAW | CS_VREDRAW;
   wc.lpfnWndProc = WndProc;
   wc.hInstance = g_hinst;
   wc.hCursor = NULL;
   wc.hIcon = NULL;
   wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
   wc.lpszClassName = "WindowsSucks";

   result = RegisterClass(&wc);

   hWnd = CreateWindow(wc.lpszClassName, "Fuss",
                       WS_OVERLAPPEDWINDOW,
                       CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
                       CW_USEDEFAULT, NULL, NULL, g_hinst, NULL);
   if (hWnd == NULL)
      return kError_NoDataAvail;

   m_hWnd = hWnd;
   hHandle =
      WSAAsyncGetHostByName(hWnd, WM_WINDOWS_IS_DONE_PICKING_ITS_BUTT,
                            szHostName, szBuffer, MAXGETHOSTSTRUCT);
   if (hHandle == NULL)
   {
      DestroyWindow(hWnd);
      return kError_NoDataAvail;
   }

   while (GetMessage(&msg, NULL, 0, 0))
   {
      TranslateMessage(&msg);

      if (msg.message == WM_WINDOWS_IS_DONE_PICKING_ITS_BUTT)
         result = WSAGETASYNCERROR(msg.lParam);

      DispatchMessage(&msg);
   }

   if (m_bExit)
   {
      WSACancelAsyncRequest(hHandle);
   }

   m_hWnd = NULL;
   DestroyWindow(hWnd);

   if (m_bExit)
   {
      return kError_Interrupt;
   }

   if (result == 0)
   {
      memcpy(pHostInfo, szBuffer, sizeof(struct hostent));

      return kError_NoErr;
   }
   else
   {
      static unsigned long IP_Adr;
      static char *AdrPtrs[2] = { (char *) &IP_Adr, NULL };

      // That didn't work.  On some stacks a numeric IP address
      // will not parse with gethostbyname.  Try to convert it as a
      // numeric address before giving up.
      if ((IP_Adr = inet_addr(szHostName)) == INADDR_NONE)
         return kError_NoDataAvail;

      pHostInfo->h_length = sizeof(uint32);
      pHostInfo->h_addrtype = AF_INET;
      pHostInfo->h_addr_list = (char **) &AdrPtrs;
      return kError_NoErr;
   }

   return kError_NoDataAvail;
}

static LRESULT WINAPI
WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
   LRESULT   result = 0;

   switch (msg)
   {
   case WM_WINDOWS_IS_DONE_PICKING_ITS_BUTT:
      {
         PostMessage(hwnd, WM_QUIT, 0, 0);
      }
   default:
      return DefWindowProc(hwnd, msg, wParam, lParam);
   }
   return result;
}

#endif

Error
HttpInput::GetHostByName(char *szHostName, struct hostent * pResult)
{
   struct hostent *pTemp;
   struct hostent TempHostent;
   static unsigned long IP_Adr;
   static char *AdrPtrs[2] = { (char *) &IP_Adr, NULL };

#ifdef WIN32
   Error     eRet;

   eRet = Win32GetHostByName(szHostName, &TempHostent);
   if (eRet == kError_Interrupt)
      return eRet;

   if (IsError(eRet))
      pTemp = NULL;
   else
      pTemp = &TempHostent;

#else
   pTemp = gethostbyname(szHostName);
#endif

   if (pTemp == NULL)
   {
      // That didn't work.  On some stacks a numeric IP address
      // will not parse with gethostbyname.  Try to convert it as a
      // numeric address before giving up.
      if ((int) (IP_Adr = inet_addr(szHostName)) == INADDR_ANY)
         return kError_NoDataAvail;

      TempHostent.h_length = sizeof(uint32);
      TempHostent.h_addrtype = AF_INET;
      TempHostent.h_addr_list = (char **) &AdrPtrs;
      pTemp = &TempHostent;
   }

   memcpy(pResult, pTemp, sizeof(struct hostent));

   return kError_NoErr;
}

static void
EncodeURI(string & URI)
{
   string::size_type convert = 0;
   const char *legalCharacters =

      "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/?.";

   if (strncmp(URI.c_str(), "http://", 7) == 0)
       convert = URI.find(string("/"), 7);

   while ((convert = URI.find_first_not_of(legalCharacters, convert)) !=
          string::npos)
   {
      string    hex = "%";
      char      num[8];

      // Do not replace %## sequences -- they are already encoded and
      // ready to roll
      if (URI[convert] == '%' && URI.length() - convert > 2 &&
          isdigit(URI[convert + 1]) && 
          isdigit(URI[convert + 2])) 
      {
          convert++;
          continue;
      }

      sprintf(num, "%02x", URI[convert] & 0xFF);
      hex += num;

      URI.replace(convert, 1, hex);

      convert += hex.length();
   }
}

Error
HttpInput::Open(void)
{
   char      szHostName[iMaxHostNameLen + 1], *szQuery;
   char     *pEnd;
   char     *pInitialBuffer, szSourceAddr[100];
   char     *szStreamName, *szStreamUrl;
   unsigned  iPort;
   int       iRet, iRead = 0, iConnect;
   struct sockaddr_in sAddr, sSourceAddr;
   struct hostent sHost;
   Error     eRet;
   char     *pHeaderData = NULL, *pPtr;
   fd_set    sSet;
   struct timeval sTv;
   bool      bUseTitleStreaming = true, bUseAltNIC = false;
   int       iHeaderBytes = 0, iCurHeaderSize = 1024;
   string    file;

   szStreamName = NULL;
   szStreamUrl = NULL;
   if (!m_bUseProxy)
   {
      const char* ptr;

      iRet = sscanf(m_path, " http://%[^:/]:%d", szHostName, &iPort);
      if (iRet < 1)
      {
         ReportError("Bad URL format. URL format: http://<host name>"
                     ":[port][/path]. Please check the URL and try again.");
         return (Error) httpError_BadUrl;
      }
      ptr = strchr(m_path + 7, '/');
      file = (ptr ? ptr : "");
   }
   else
   {
      iRet = sscanf(m_szProxyHost, " http://%[^:/]:%d", szHostName, &iPort);
      if (iRet < 1)
      {
         ReportError("Bad Proxy URL format. URL format: http:"
                     "//<host name>:[port]. Please check your proxy settings "
                     "in the Options.");

         m_pContext->log->Error("Debug: m_szProxyHost: '%s'\n", m_szProxyHost);
         return (Error) httpError_BadUrl;
      }
      file = string(m_path);
   }
   EncodeURI(file);

   if (iRet < 2)
      iPort = iHttpPort;

   memset(&sAddr, 0, sizeof(struct sockaddr_in));

   ReportStatus("Looking up host %s...", szHostName);

   eRet = GetHostByName(szHostName, &sHost);
   if (eRet != kError_NoErr)
   {
      sprintf(m_szError, "Cannot find host %s\n", szHostName);
      ReportError(m_szError);
      return (Error) httpError_CustomError;
   }

   memcpy((char *) &sAddr.sin_addr, sHost.h_addr, sHost.h_length);
   sAddr.sin_family = sHost.h_addrtype;
   sAddr.sin_port = htons((unsigned short) iPort);

   ReportStatus("Contacting host %s...", szHostName);
   m_hHandle = socket(sHost.h_addrtype, SOCK_STREAM, 0);
   if (m_hHandle < 0)
   {
      ReportError
         ("Cannot create socket. Is TCP/IP networking properly installed?");
      return (Error) httpError_CannotOpenSocket;
   }

   m_pContext->prefs->GetPrefBoolean(kUseAlternateNICPref, &bUseAltNIC);
   if (bUseAltNIC)
   {
      uint32    len = 100;

      m_pContext->prefs->GetPrefString(kAlternateNICAddressPref, szSourceAddr,
                                       &len);
      if (len == 0)
         m_pContext->log->Error("UseAlternateNIC is true but AlternateNIC "

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -