httpinput.cpp
字号:
/*____________________________________________________________________________
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.33 2000/01/20 00:48:46 robert Exp $
____________________________________________________________________________*/
/* system headers */
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <iostream.h>
#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 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);
}
}
HttpInput::HttpInput(FAContext *context):
PhysicalMediaInput(context)
{
uint32 len;
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_pContext->prefs->GetPrefBoolean(kUseProxyPref, &m_bUseProxy);
if (m_bUseProxy)
{
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()
{
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->GetInputBufferSize(&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)
{
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;
}
Error 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 };
pTemp = gethostbyname(szHostName);
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((IP_Adr = inet_addr(szHostName)) < 0)
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;
}
Error HttpInput::Open(void)
{
char szHostName[iMaxHostNameLen+1], *szFile, *szQuery;
char szLocalName[iMaxHostNameLen+1], *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;
szStreamName = NULL;
szStreamUrl = NULL;
if (!m_bUseProxy)
{
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;
}
szFile = strchr(m_path + 7, '/');
}
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.");
return (Error)httpError_BadUrl;
}
szFile = m_path;
}
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 "
"has no value ?!");
sSourceAddr.sin_family= AF_INET;
sSourceAddr.sin_port = 0;
sSourceAddr.sin_addr.s_addr = inet_addr(szSourceAddr);
iRet = bind(m_hHandle, (struct sockaddr *)&sSourceAddr,
sizeof(struct sockaddr_in));
if (iRet < 0)
{
close(m_hHandle);
m_hHandle= -1;
ReportError("Cannot bind the socket. Please make sure that your TCP/IP networking is correctly configured.");
return kError_CannotBind;
}
}
#if defined(WIN32)
unsigned long lMicrosoftSucksBalls = 1;
ioctlsocket(m_hHandle, FIONBIO, &lMicrosoftSucksBalls);
#elif defined(__BEOS__)
// int on = 1;
// setsockopt( m_hHandle, SOL_SOCKET, SO_NONBLOCK, &on, sizeof( on ) );
#else
fcntl(m_hHandle, F_SETFL, fcntl(m_hHandle, F_GETFL) | O_NONBLOCK);
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -