📄 httpinput.cpp
字号:
"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
iConnect = connect(m_hHandle, (const sockaddr *) &sAddr, sizeof(sAddr));
if (iConnect == -1)
{
#ifndef WIN32
int error = errno;
if (error != EINPROGRESS)
#else
int error = WSAGetLastError();
if (error != WSAEINPROGRESS && error != WSAEWOULDBLOCK)
#endif
{
ReportError("Cannot connect to host: %s", szHostName);
closesocket(m_hHandle);
return (Error) httpError_CannotConnect;
}
int conattempt = 0;
for (; iConnect && !m_bExit;)
{
if (conattempt > 50)
{
cout << "timed out\n";
ReportError("Host not answering: %s", szHostName);
closesocket(m_hHandle);
return (Error) httpError_CannotConnect;
}
conattempt++;
sTv.tv_sec = 0;
sTv.tv_usec = 0;
FD_ZERO(&sSet);
FD_SET(m_hHandle, &sSet);
iRet = select(m_hHandle + 1, NULL, &sSet, NULL, &sTv);
if (!iRet)
{
usleep(100000);
continue;
}
if (iRet < 0)
{
ReportError("Cannot connect to host: %s", szHostName);
closesocket(m_hHandle);
return (Error) httpError_CannotConnect;
}
break;
}
}
if (m_bExit)
return (Error) kError_Interrupt;
szQuery = new char[iMaxUrlLen];
if (file.length() > 0)
{
sprintf(szQuery, "GET %s HTTP/1.0\r\n"
"Host: %s\r\n"
"Accept: */*\r\n"
"Icy-MetaData:1\r\n"
"User-Agent: FreeAmp/%s\r\n",
file.c_str(), szHostName, FREEAMP_VERSION);
}
else
{
sprintf(szQuery, "GET / HTTP/1.0\r\n"
"Host: %s\r\n"
"Accept: */*\r\n"
"Icy-MetaData:1\r\n"
"User-Agent: FreeAmp/%s\r\n", szHostName, FREEAMP_VERSION);
}
m_pContext->prefs->GetPrefBoolean(kUseTitleStreamingPref,
&bUseTitleStreaming);
if (bUseTitleStreaming)
{
int iPort;
Error eRet;
m_pTitleStream = new TitleStreamServer(m_pContext, m_pTarget);
eRet = m_pTitleStream->Init(iPort);
if (IsntError(eRet))
{
sprintf(szQuery + strlen(szQuery), "x-audiocast-udpport: %d\r\n",
iPort);
}
else
{
delete m_pTitleStream;
m_pTitleStream = NULL;
}
}
strcat(szQuery, "\r\n");
ReportStatus("Requesting stream...");
iRet = send(m_hHandle, szQuery, strlen(szQuery), 0);
if (iRet != (int) strlen(szQuery))
{
delete szQuery;
ReportError("Cannot send data to host: %s", szHostName);
closesocket(m_hHandle);
return (Error) httpError_SocketWrite;
}
delete szQuery;
pInitialBuffer = new char[iInitialBufferSize + 1];
for (; !m_bExit;)
{
sTv.tv_sec = 0;
sTv.tv_usec = 0;
FD_ZERO(&sSet);
FD_SET(m_hHandle, &sSet);
iRet = select(m_hHandle + 1, &sSet, NULL, NULL, &sTv);
if (!iRet)
{
usleep(10000);
continue;
}
iRead = recv(m_hHandle, pInitialBuffer, iInitialBufferSize, 0);
if (iRead < 0)
{
ReportError("Cannot receive data from host: %s", szHostName);
closesocket(m_hHandle);
return (Error) httpError_SocketRead;
}
break;
}
if (m_bExit)
return (Error) kError_Interrupt;
if (sscanf(pInitialBuffer, " %*s %d %255[^\n\r]", &iRet, m_szError))
{
void *pData;
if (iRet == iICY_REDIRECT)
{
char *redir;
redir = strstr(pInitialBuffer, "Location: ");
if (redir)
{
int port, ret;
char url[MAX_PATH];
ret = sscanf(redir, "Location: %255[0-9.]:%d", url, &port);
if (ret == 0)
ret = sscanf(redir, "Location: http://%255[0-9.]:%d", url, &port);
if (ret)
{
if (ret == 2)
sprintf(m_path, "http://%s:%d", url, port);
else
sprintf(m_path, "http://%s", url);
sprintf(url, "Redirected to: %s", m_path);
ReportStatus(url);
delete pInitialBuffer;
closesocket(m_hHandle);
return Open();
}
}
}
if (iRet != iICY_OK)
{
ReportStatus("");
ReportError("This stream is not available: %s\n", m_szError);
delete pInitialBuffer;
closesocket(m_hHandle);
return (Error) httpError_CustomError;
}
// for(int i = 0; i < 25; i++)
// Debug_v("%c - %d", pInitialBuffer[i], pInitialBuffer[i]);
pHeaderData = new char[iHeaderSize];
for (;;)
{
if (iHeaderBytes + iRead > iCurHeaderSize)
{
char *pNew;
iCurHeaderSize += iHeaderSize;
pNew = new char[iCurHeaderSize + 1];
memset(pNew, 0, iCurHeaderSize + 1);
memcpy(pNew, pHeaderData, iHeaderBytes);
delete pHeaderData;
pHeaderData = pNew;
}
memcpy(pHeaderData + iHeaderBytes, pInitialBuffer, iRead);
iHeaderBytes += iRead;
pEnd = strstr(pHeaderData, "\r\n\r\n");
if (pEnd)
{
*(pEnd + 3) = 0;
break;
}
pEnd = strstr(pHeaderData, "\n\n");
if (pEnd)
{
*(pEnd + 1) = 0;
break;
}
for (; !m_bExit;)
{
sTv.tv_sec = 0;
sTv.tv_usec = 0;
FD_ZERO(&sSet);
FD_SET(m_hHandle, &sSet);
iRet = select(m_hHandle + 1, &sSet, NULL, NULL, &sTv);
if (!iRet)
{
usleep(10000);
continue;
}
iRead = recv(m_hHandle, pInitialBuffer, iInitialBufferSize, 0);
if (iRead < 0)
{
ReportError("Cannot receive data from host: %s", szHostName);
closesocket(m_hHandle);
return (Error) httpError_SocketRead;
}
break;
}
if (m_bExit)
return (Error) kError_Interrupt;
}
pPtr = strstr(pHeaderData, "icy-name");
if (pPtr)
{
pPtr += strlen("icy-name:");
szStreamName = new char[strlen(pPtr) + 1];
sscanf(pPtr, " %[^\r\n]", szStreamName);
}
pPtr = strstr(pHeaderData, "icy-url");
if (pPtr)
{
pPtr += strlen("icy-url:");
szStreamUrl = new char[strlen(pPtr) + 1];
sscanf(pPtr, " %[^\r\n]", szStreamUrl);
}
pPtr = strstr(pHeaderData, "icy-metaint");
if (pPtr)
{
pPtr += strlen("icy-metaint:");
m_iMetaDataInterval = atoi(pPtr);
}
// If this is a stream from a web server and not a shout/ice
// server we don't want to use buffer reduction when the
// input buffers fill up
if (strstr(pHeaderData, "Server:") && strstr(pHeaderData, "Date:"))
m_bUseBufferReduction = false;
if (szStreamName && strlen(szStreamName))
{
PlaylistItemsUpdatedEvent *e;
PlaylistItem *pItem;
pItem = m_pContext->plm->GetCurrentItem();
if (pItem && szStreamName)
{
MetaData oData;
oData = pItem->GetMetaData();
oData.SetTitle(szStreamName);
pItem->SetMetaData(&oData);
vector < PlaylistItem * >pl_items;
pl_items.push_back(pItem);
e = new PlaylistItemsUpdatedEvent(&pl_items, m_pContext->plm);
m_pTarget->AcceptEvent(e);
}
delete szStreamUrl;
}
pPtr = strstr(pHeaderData, "x-audiocast-udpport:");
if (pPtr)
{
// Debug_v("x-audiocast-udpport: %s", atoi(pPtr));
if (m_pTitleStream)
m_pTitleStream->Run(sAddr.sin_addr, atoi(pPtr + 20));
}
// Let's save the bytes we've read into the pullbuffer.
iRead = iHeaderBytes - strlen(pHeaderData) - 1;
if (iRead > 0)
{
m_pOutputBuffer->BeginWrite(pData, iRead);
memcpy(pData, (char *) pHeaderData + strlen(pHeaderData) + 1, iRead);
m_pOutputBuffer->EndWrite(iRead);
m_uBytesReceived = iRead;
}
}
delete pInitialBuffer;
bool bSave;
uint32 size = 255;
m_pContext->prefs->GetPrefBoolean(kSaveStreamsPref, &bSave);
if (bSave || (m_pContext->argFlags & FAC_ARGFLAGS_SAVE_STREAMS))
{
char szPath[255], szFile[255];
unsigned i;
if (szStreamName == NULL)
{
szStreamName = new char[255];
sprintf(szStreamName, "%s:%d", szHostName, iPort);
}
for (i = 0; i < strlen(szStreamName); i++)
if (strchr("\\/?*{}[]()*|:<>\"'", szStreamName[i]))
szStreamName[i] = '-';
if (m_pContext->prefs->
GetPrefString(kSaveStreamsDirPref, szPath,
&size) == kError_NoPrefValue)
strcpy(szPath, ".");
if (szPath[strlen(szPath) - 1] == cDirSepChar)
szPath[strlen(szPath) - 1] = 0;
for (i = 0;; i++)
{
if (!i)
sprintf(szFile, "%s%c%s.mp3", szPath, cDirSepChar, szStreamName);
else
sprintf(szFile, "%s%c%s-%d.mp3", szPath, cDirSepChar, szStreamName,
i);
if (access(szFile, F_OK))
break;
}
m_fpSave = fopen(szFile, "wb");
if (m_fpSave == NULL)
ReportError("Cannot open file to save HTTP stream. Check "
"the save streams locally setting in the "
"options dialog.");
if (pHeaderData && m_fpSave && iRead > 0)
{
iRet = fwrite((char *) pHeaderData + strlen(pHeaderData) + 1,
sizeof(char), iRead, m_fpSave);
if (iRet != iRead)
{
delete pHeaderData;
ReportError("Cannot save http stream to disk. Disk full? (1)");
return kError_WriteFile;
}
}
}
delete pHeaderData;
delete szStreamName;
return kError_NoErr;
}
void
HttpInput::StartWorkerThread(void *pVoidBuffer)
{
((HttpInput *) pVoidBuffer)->WorkerThread();
}
void
HttpInput::WorkerThread(void)
{
int iRead, iRet, iReadSize = 1024, iMaxReadBytes;
void *pBuffer;
Error eError;
fd_set sSet;
struct timeval sTv;
char cNumBlocks;
static int iSize = 0;
eError = Open();
if (IsError(eError) || m_bExit)
{
return;
}
m_pSleepSem->Wait();
for (; !m_bExit;)
{
if (m_pOutputBuffer->IsEndOfStream())
{
m_pSleepSem->Wait();
continue;
}
sTv.tv_sec = 0;
sTv.tv_usec = 0;
FD_ZERO(&sSet);
FD_SET(m_hHandle, &sSet);
iRet = select(m_hHandle + 1, &sSet, NULL, NULL, &sTv);
if (!iRet)
{
usleep(10000);
continue;
}
eError = m_pOutputBuffer->BeginWrite(pBuffer, iReadSize);
if (eError == kError_NoErr)
{
if (m_iMetaDataInterval > 0)
{
iMaxReadBytes =
min(iReadSize, m_iMetaDataInterval - m_uBytesReceived);
if (iMaxReadBytes == 0)
{
iRead = recv(m_hHandle, &cNumBlocks, 1, 0);
if (cNumBlocks > 0)
{
char *pMeta, *pPtr, *pNull;
pMeta = new char[cNumBlocks * 16 + 1];
recv(m_hHandle, pMeta, cNumBlocks * 16, 0);
pMeta[cNumBlocks * 16] = 0;
pPtr = strstr(pMeta, "StreamTitle=");
if (pPtr)
{
pPtr += strlen("StreamTitle='");
pNull = strchr(pPtr, '\'');
if (pNull)
{
*pNull = 0;
m_pTarget->AcceptEvent(new StreamInfoEvent(pPtr, NULL));
}
}
delete pMeta;
}
iMaxReadBytes = iReadSize;
m_uBytesReceived = 0;
}
}
else
iMaxReadBytes = iReadSize;
iRead = recv(m_hHandle, (char *) pBuffer, iMaxReadBytes, 0);
if (iRead == 0)
{
m_pOutputBuffer->SetEndOfStream(true);
m_pOutputBuffer->EndWrite(0);
}
if (iRead < 0)
{
#ifdef WIN32
if (WSAGetLastError() == WSAEWOULDBLOCK)
#else
if (errno == EAGAIN)
#endif
{
iRead = 0;
}
}
if (iRead < 0)
{
m_pOutputBuffer->SetEndOfStream(true);
m_pOutputBuffer->EndWrite(0);
break;
}
iSize += iRead;
m_uBytesReceived += iRead;
if (m_fpSave)
{
iRet = fwrite(pBuffer, sizeof(char), iRead, m_fpSave);
if (iRet != iRead)
{
ReportError("Cannot save http stream to disk. Disk full? (2)");
break;
}
}
eError = m_pOutputBuffer->EndWrite(iRead);
if (IsError(eError))
{
m_pContext->log->Error("http: EndWrite returned: %d\n", eError);
break;
}
}
if (eError == kError_BufferTooSmall)
{
if (m_bLoop)
{
m_pOutputBuffer->DiscardBytes();
m_bDiscarded = true;
}
else
{
iSize = 0;
m_pSleepSem->Wait();
}
continue;
}
}
shutdown(m_hHandle, 2);
closesocket(m_hHandle);
m_hHandle = -1;
}
vector < string > *HttpInput::GetProtocols(void)
{
vector < string > *protoList = new vector < string >;
protoList->push_back("http");
return protoList;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -