I need help diagnosing this segfault. Because I have failed.
It is clockwork reproducible.
Does anyone else (in unix / linux) have the same segfault after
opening the streams tree in the music browser?
I think something is compiling / linking / loading wrong. I notice
that when I touch Http.cpp, that the Http.o and freeamp executable and
plugins/musicbrowser.ui and plugins/freeamp.ui are re-compiled.
When I add output to this function:
int Http::WriteToBuffer(unsigned char *buffer, unsigned int size)
{
cerr << "WriteToBuffer " << size << endl << flush;
if (m_buffer == NULL)
{
_you_are_here;
m_bufferSize = kBufferSize;
m_buffer = new unsigned char[m_bufferSize];
}
_show_args1(m_buffer);
...
...
return size;
}
That it does NOT output any message. This function is called from
this sequence in Download (line numbers for me in left column):
483: _show_args1(wcount);
484: _show_args3(m_bufferSize,m_bytesInBuffer,m_buffer);
485: wcount = this->Http::WriteToBuffer((unsigned char *)cp,
486: total - (cp-buffer));
487: _show_args1(wcount);
488: _show_args3(m_bufferSize,m_bytesInBuffer,m_buffer);
This does produce output:
@ lib/http/src/Http.cpp : 483 : enum Error Http::Download(const class string &, bool)
args: wcount=0
@ lib/http/src/Http.cpp : 484 : enum Error Http::Download(const class string &, bool)
args: m_bufferSize=0, m_bytesInBuffer=0, m_buffer=(null)
@ lib/http/src/Http.cpp : 487 : enum Error Http::Download(const class string &, bool)
args: wcount=1804
@ lib/http/src/Http.cpp : 488 : enum Error Http::Download(const class string &, bool)
args: m_bufferSize=1804, m_bytesInBuffer=0, m_buffer=
[2]+ Segmentation fault /opt/freeamp-mine/bin/freeamp
So even though the WriteToBuffer does not seems to execute the output
to cerr, it does change m_buffer and return size to wcount. I cannot
trace this in gdb, I set a breakpoint on Http::Download but it passed
right over it.
I am guessing my dificulty may lie in the way plugins are loaded and
symbols are resolved? Is gdb setting a breakpoint in freeamp's version
of Http.o and not seeing the one in musicbrowser.ui?
I still do not understand how musicbrowser.ui writes to cerr in
Download but not in WriteToBuffer.
I am out of ideas.
I am attaching the header file that defines the macros I am using,
for completeness, and my copy of Http.cpp.
I am running RH 6.2/HelixGnome with gcc 2.91.66
The make output from touching Http.cpp is
[1525|ckuklewicz /usr/local/src/freeamp/freeamp-mine]$ make
for p in base base/beos base/beos/src base/src base/unix base/unix/src dlm dlm/rmp io
io/alsa io/alsa/unix io/alsa/unix/linux io/alsa/unix/linux/src io/esound io/esound/src
io/http io/local io/obs io/src io/soundcard io/soundcard/beos io/soundcard/unix
io/soundcard/beos io/soundcard/unix/linux io/soundcard/unix/linux/src
io/soundcard/beos/src io/soundcard/unix/linux/src io/wavout io/wavout/src
io/wavout/include io/signature lib lib/xml lib/xml/src lib/http lib/http/src lib/zlib
lmc lmc/xingmp3 lmc/xingmp3/src lib/gdbm lib/zlib/src lmc/vorbis plm plm/metadata
plm/playlist plm/portable plm/portable/pmp300 lmc/xingmp3/src plm/metadata/id3v1
plm/metadata/id3v2 plm/metadata/misc plm/playlist/m3u plm/portable/pmp300/sba ui
ui/download ui/download/unix ui/freeamp ui/freeamp/beos ui/cmdline
ui/download/unix/src ui/freeamp/beos/src ui/freeamp/tools ui/freeamp/unix ui/irman
ui/lcd ui/musicbrowser ui/freeamp/src ui/freeamp/tools/src ui/freeamp/unix/src
ui/musicbrowser/src ui/musicbrowser/unix ui/mpg123 plm/playlist/pls ui/irman/src
ui/lcd/src ui/musicbrowser/unix/src ui/ncurses update update/unix lmc/cd lmc/cd/src
io/cd io/cd/unix io/cd/unix/src lib/unzip lib/unzip/src ftc ftc/kjofol ftc/winamp
plm/metadata/cddb base/aps lmc/vorbis/src io/signature/src lib/musicbrainz
lib/musicbrainz/expat lib/musicbrainz/expat/xmlparse lib/musicbrainz/expat/xmltok
lib/musicbrainz/osdep lib/musicbrainz/lib; do \
test -d $p || mkdir $p; \
done
c++ -I. -I. -I./config -DUNIX_LIBDIR=\"/opt/freeamp-mine//lib\" -Dlinux -I.
-I./lib/gdbm -I./base/include -I./config -I./io/include -I./ui/include -I./lmc/include
-I./base/unix/include -I./base/unix/linux/include -I./io/esound/include
-I./ui/musicbrowser/unix/include -I./ui/freeamp/include -I./ui/freeamp/unix/include
-I./ui/download/unix/include -I./ui/musicbrowser/include -I./ftc/kjofol
-I./io/soundcard/unix/linux/include -I./lmc/xingmp3/include -I./lmc/cd/include
-I./plm/portable/pmp300/sba -I./lib/xml/include -I./lib/zlib/include
-I./lib/unzip/include -I./io/cd/unix/include -I./base/aps -I./io/wavout/include
-I./ui/lcd/include -I./ui/irman/include -I./lib/http/include -I./io/signature/include
-I./lib/musicbrainz/lib -I./lib/musicbrainz/expat/xmltok
-I./lib/musicbrainz/expat/xmlparse -I./lmc/vorbis/include -Wall -g -O0
-I/usr/lib/glib/include -I/usr/X11R6/include -I/usr/lib/glib/include
-I/usr/X11R6/include -D_REENTRANT -c lib/http/src/Http.cpp -o lib/http/src/Http.o
test -d lib/http/lib || mkdir lib/http/lib
ar -r lib/http/lib/libfahttp.a lib/http/src/Http.o
c++ -Wl,-export-dynamic -o freeamp base/src/log.o base/src/player.o
base/src/musiccatalog.o base/src/playlist.o base/src/propimpl.o base/src/registrar.o
base/src/registry.o base/src/thread.o io/src/eventbuffer.o base/src/prefixprefs.o
base/src/preferences.o base/src/debug.o base/src/utility.o base/src/database.o
base/src/downloadmanager.o base/src/errors.o io/src/pullbuffer.o io/src/tstream.o
base/src/undomanager.o base/src/timer.o base/src/missingfile.o io/src/pipeline.o
base/unix/src/bootstrap.o base/unix/src/unixprefs.o base/unix/src/win32impl.o
base/unix/src/pthreadthread.o base/unix/src/debug.o base/unix/src/mutex.o
base/unix/src/semaphore.o base/unix/src/utility.o base/aps/FAMetaUnit.o
base/aps/apsinterface.o base/aps/apsplaylist.o base/aps/gencrc.o base/aps/hosttonet.o
base/aps/nettohost.o base/aps/comsocket.o base/aps/apsconvert.o base/aps/YPClient.o
base/aps/uuid.o base/aps/slclient.o lib/gdbm/lib/libfagdbm.a lib/xml/lib/libfaxml.a
lib/zlib/lib/libzlib.a lib/http/lib/libfahttp.a -Wl,-export-dynamic -ldl -lpthread
-lmusicbrainz -lnsl
test -d plugins || mkdir plugins
make -f Makefile-plugins - plugins-cc
make[1]: Entering directory `/usr/local/src/freeamp/freeamp-mine'
test -d lib/http/lib || mkdir lib/http/lib
ar -r lib/http/lib/libfahttp.la lib/http/src/Http.o
c++ -shared -Wl,-export-dynamic -o plugins/musicbrowser.ui
ui/musicbrowser/unix/src/gtkmusicbrowser.o ui/musicbrowser/unix/src/browsermenu.o
ui/musicbrowser/unix/src/browsertree.o ui/musicbrowser/unix/src/browserlist.o
ui/musicbrowser/unix/src/musicbrowser.o ui/musicbrowser/unix/src/infoeditor.o
ui/musicbrowser/unix/src/fileselector.o ui/musicbrowser/unix/src/musicsearch.o
ui/musicbrowser/unix/src/gtkmessagedialog.o ui/musicbrowser/unix/src/introwizard.o
ui/musicbrowser/unix/src/missingfileui.o ui/musicbrowser/src/FreeAmpStreams.o
lib/xml/src/Parse.lo lib/http/lib/libfahttp.la -L/usr/lib -L/usr/X11R6/lib -lgtk -lgdk
-rdynamic -lgmodule -lgthread -lglib -lpthread -ldl -lXi -lXext -lX11 -lm
c++ -shared -Wl,-export-dynamic -o plugins/freeamp.ui ui/freeamp/src/Theme.doh
ui/freeamp/src/Bitmap.o ui/freeamp/src/Canvas.o ui/freeamp/src/SliderControl.o
ui/freeamp/src/VSliderControl.o ui/freeamp/src/Panel.o ui/freeamp/src/Window.o
ui/freeamp/src/ButtonControl.o ui/freeamp/src/Control.o ui/freeamp/src/TextControl.o
ui/freeamp/src/DialControl.o ui/freeamp/src/Font.o ui/freeamp/src/FreeAmpTheme.o
ui/freeamp/src/ThemeZip.o ui/freeamp/src/MultiStateControl.o
ui/freeamp/src/Headlines.o ui/freeamp/src/ForeignTheme.o base/src/utility.lo
ui/freeamp/src/PixFontControl.o ui/freeamp/src/PixTimeControl.o
ui/freeamp/src/Equalizer.o ui/freeamp/src/PixSliderControl.o lib/zlib/lib/libzlib.la
lib/xml/src/Parse.lo lib/unzip/lib/libunzip.la lib/http/lib/libfahttp.la
ui/freeamp/unix/src/GTKFont.o ui/freeamp/unix/src/GTKUtility.o
ui/freeamp/unix/src/GTKMessageDialog.o ui/freeamp/unix/src/GTKWindow.o
ui/freeamp/unix/src/GTKBitmap.o ui/freeamp/unix/src/GTKCanvas.o
ui/freeamp/unix/src/ttfont.o ui/freeamp/unix/src/ThemeManager.o
ui/freeamp/unix/src/GTKPreferenceWindow.o ui/freeamp/unix/src/GTKFileSelector.o
-L/usr/lib -L/usr/X11R6/lib -lgtk -lgdk -rdynamic -lgmodule -lgthread -lglib -lpthread
-ldl -lXi -lXext -lX11 -lm -lttf -L/usr/lib -lgdk_pixbuf -L/usr/lib -L/usr/X11R6/lib
-lgtk -lgdk -rdynamic -lgmodule -lglib -ldl -lXi -lXext -lX11 -lm
make[1]: Leaving directory `/usr/local/src/freeamp/freeamp-mine'
#ifndef __TRACER_H_
#define __TRACER_H_
#include <iostream>
#include <glib.h>
inline void _real_assert(bool b,const char *file,int line,
const char *func, const char *msg)
{
if (!b) {
cerr << endl << "! " << msg << " failed : " << file
<< " : " << line << " : " << func << endl << flush;
exit(1);
}
}
inline void _real_message(const char *file,int line,
const char *func, const char *msg)
{
cerr << "$ Message : " << file << " : "
<< line << " : " << func << " : " << msg << endl << flush;
}
// Macros to help debug that call the above functions
#define _assert(__f__) _real_assert((__f__),__FILE__,__LINE__, \
G_GNUC_PRETTY_FUNCTION,"_assert " #__f__)
#define _nullChk(__p__) _real_assert(NULL!=(__p__),__FILE__,__LINE__, \
G_GNUC_PRETTY_FUNCTION,"_nullChk " #__p__)
#define _message(__m__) _real_message(__FILE__,__LINE__, \
G_GNUC_PRETTY_FUNCTION,__m__)
#define _never_get_here _real_assert(false,__FILE__,__LINE__, \
G_GNUC_PRETTY_FUNCTION,"_never_get_here")
// Execution tracing macros for debugging
#define _you_are_here do { cerr << "@ " << __FILE__ << " : " << __LINE__ \
<< " : " << G_GNUC_PRETTY_FUNCTION << endl; } while(0)
#define _show_args0() _you_are_here;
#define _show_args1(Arg1) do { _you_are_here; cerr << "args: " \
<< #Arg1 << "=" << (Arg1) \
<< endl << flush; } while (0)
#define _show_args2(Arg1,Arg2) do { _you_are_here; cerr << "args: " \
<< #Arg1 << "=" << (Arg1) \
<< ", " << #Arg2 << "=" << (Arg2) \
<< endl << flush; } while (0)
#define _show_args3(Arg1,Arg2,Arg3) do { _you_are_here; \
cerr << "args: " \
<< #Arg1 << "=" << (Arg1) \
<< ", " << #Arg2 << "=" << (Arg2) \
<< ", " << #Arg3 << "=" << (Arg3) \
<< endl << flush; } while (0)
#define _show_args4(Arg1,Arg2,Arg3,Arg4) do { _you_are_here; \
cerr << "args: " \
<< #Arg1 << "=" << (Arg1) \
<< ", " << #Arg2 << "=" << (Arg2) \
<< ", " << #Arg3 << "=" << (Arg3) \
<< ", " << #Arg4 << "=" << (Arg4) \
<< endl << flush; } while (0)
#define _show_args5(Arg1,Arg2,Arg3,Arg4,Arg5) do { _you_are_here; \
cerr << "args: " \
<< #Arg1 << "=" << (Arg1) \
<< ", " << #Arg2 << "=" << (Arg2) \
<< ", " << #Arg3 << "=" << (Arg3) \
<< ", " << #Arg4 << "=" << (Arg4) \
<< ", " << #Arg5 << "=" << (Arg5) \
<< endl << flush; } while (0)
#endif
/*____________________________________________________________________________
FreeAmp - The Free MP3 Player
Copyright (C) 2000 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: Http.cpp,v 1.12 2000/09/01 10:57:59 ijr Exp $
____________________________________________________________________________*/
#include "config.h"
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifndef WIN32
#include <sys/time.h>
#endif
#include <fcntl.h>
#include <errno.h>
#ifdef WIN32
#include <io.h>
#else
#undef socklen_t
#include <netinet/in.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#endif
#if defined(unix) || defined(__BEOS__) || defined(_BSD_SOURCE)
#define SOCKET int
#endif
#if defined(unix) || defined(_BSD_SOURCE)
#include <arpa/inet.h>
#define closesocket(x) close(x)
#define O_BINARY 0
#endif
#include "Http.h"
#include "tracer.h"
#ifndef min
#define min(a, b) (((a) < (b)) ? (a) : (b))
#endif
const unsigned short kHttpPort = 80;
const unsigned int kMaxHostNameLen = 64;
const unsigned int kMaxURLLen = 1024;
const unsigned int kBufferSize=8192;
#define DB printf("%s:%d\n", __FILE__, __LINE__);
Http::Http(FAContext *context)
{
m_exit = false;
m_context = context;
m_file = NULL;
m_buffer = NULL;
_show_args1(m_buffer);
m_bytesInBuffer = 0;
m_bufferSize = 0;
}
Http::~Http(void)
{
if (m_buffer)
{
_show_args1(m_buffer);
delete m_buffer;
m_buffer = NULL;
_show_args1(m_buffer);
}
if (m_file)
fclose(m_file);
}
Error Http::DownloadToString(const string &url, string &page)
{
_show_args5(url,page,m_bytesInBuffer,m_bufferSize,m_buffer);
Error eRet;
eRet = Download(url, false);
if (IsntError(eRet))
{
/*
// This was segfaulting
if (m_buffer)
{
_show_args2(m_bytesInBuffer,m_bufferSize);
unsigned int i;
cerr << "==" << endl;
for(i=0; i < m_bytesInBuffer; i++)
{
if (0!=((char *)m_buffer)[i])
cerr << ((char *)m_buffer)[i];
else
cerr << "NULL";
}
cerr << endl << "==" << endl;
for(; i < m_bufferSize; i++)
{
if (0!=((char *)m_buffer)[i])
cerr << ((char *)m_buffer)[i];
else
cerr << "NULL";
}
cerr << endl << "==" << endl;
}
*/
page = string((char *)m_buffer);
}
if (m_buffer)
{
_show_args1(m_buffer);
delete m_buffer;
m_buffer = NULL;
_show_args1(m_buffer);
}
return eRet;
}
Error Http::DownloadToFile(const string &url, const string &destPath)
{
Error eRet;
m_destPath = destPath;
eRet = Download(url, true);
if (m_file)
{
fclose(m_file);
m_file = NULL;
}
return eRet;
}
int Http::WriteToBuffer(unsigned char *buffer, unsigned int size)
{
cerr << "WriteToBuffer " << size << endl << flush;
if (m_buffer == NULL)
{
_you_are_here;
m_bufferSize = kBufferSize;
m_buffer = new unsigned char[m_bufferSize];
}
_show_args1(m_buffer);
if (m_bytesInBuffer + size > m_bufferSize)
{
_you_are_here;
unsigned char *pTemp;
m_bufferSize += (kBufferSize > size) ? (kBufferSize) : (kBufferSize + size);
pTemp = new unsigned char[m_bufferSize];
if (m_bufferSize<m_bytesInBuffer)
{
exit(13);
}
memcpy(pTemp, m_buffer, m_bytesInBuffer);
delete m_buffer;
m_buffer = pTemp;
_show_args1(m_buffer);
}
if (m_bufferSize < m_bytesInBuffer+size)
{
exit(13);
}
memcpy(m_buffer + m_bytesInBuffer, buffer, size);
m_bytesInBuffer += size;
return size;
}
int Http::WriteToFile(unsigned char *buffer, unsigned int size)
{
_show_args4(buffer,size,m_bytesInBuffer,m_bufferSize);
if (m_file == NULL)
{
m_file = fopen(m_destPath.c_str(), "wb");
if (m_file == NULL)
return -1;
}
return fwrite(buffer, sizeof(unsigned char), size, m_file);
}
Error Http::Download(const string &url, bool fileDownload)
{
_show_args2(url,fileDownload);
_show_args2(m_bufferSize,m_buffer);
Error result = kError_InvalidParam;
char hostname[kMaxHostNameLen + 1];
char localname[kMaxHostNameLen + 1];
char proxyname[kMaxURLLen + 1];
unsigned short port;
struct sockaddr_in addr;
struct hostent host;
SOCKET s = -1;
char* file = NULL;
bool useProxy;
unsigned int bytesReceived = 0;
result = kError_ProtocolNotSupported;
// where should we connect to?
if(!strncasecmp(url.c_str(), "http://", 7))
{
_show_args2(m_bufferSize,m_buffer);
_nullChk(m_context);
_nullChk(m_context->prefs);
int32 numFields;
uint32 length;
result = kError_NoErr;
m_context->prefs->GetPrefBoolean(kUseProxyPref, &useProxy);
length = sizeof(proxyname);
m_context->prefs->GetPrefString(kProxyHostPref, proxyname, &length);
_show_args2(m_bufferSize,m_buffer);
if(useProxy)
{
numFields = sscanf(proxyname,
"http://%[^:/]:%hu", hostname, &port);
strncpy(proxyname, url.c_str(),length);
file = proxyname;
}
else
{
numFields = sscanf(url.c_str(),
"http://%[^:/]:%hu", hostname, &port);
file = strchr(url.c_str() + 7, '/');
}
_show_args2(m_bufferSize,m_buffer);
if(numFields < 1)
{
result = kError_InvalidURL;
}
if(numFields < 2)
{
port = kHttpPort;
}
}
_show_args2(m_bufferSize,m_buffer);
// get hostname
if(IsntError(result))
{
struct hostent* hostByName=NULL;
struct hostent hostByIP;
//*m_debug << "gethostbyname: " << hostname << endl;
hostByName = gethostbyname(hostname);
_nullChk(hostByName);
_show_args2(m_bufferSize,m_buffer);
// On some stacks a numeric IP address
// will not parse with gethostbyname.
// If that didn't work try to convert it as a
// numeric address before giving up.
if(!hostByName)
{
_show_args2(m_bufferSize,m_buffer);
static unsigned long ip;
static char *addr_ptr[2] = {(char*)&ip, NULL};
if((int)(ip = inet_addr(hostname)) < 0)
result = kError_CantFindHost;
else
{
hostByIP.h_length = sizeof(uint32);
hostByIP.h_addrtype = AF_INET;
hostByIP.h_addr_list = (char**)&addr_ptr;
hostByName = &hostByIP;
}
}
_show_args2(m_bufferSize,m_buffer);
if(IsntError(result))
{
memcpy(&host, hostByName, sizeof(struct hostent));
}
}
_show_args2(m_bufferSize,m_buffer);
// open socket
if(IsntError(result))
{
memset(&addr, 0x00, sizeof(struct sockaddr_in));
_show_args2(m_bufferSize,m_buffer);
int temp=sizeof(struct sockaddr_in);
if (temp < host.h_length)
{
exit(13);
}
memcpy(&addr.sin_addr, host.h_addr, host.h_length);
_show_args2(m_bufferSize,m_buffer);
addr.sin_family= host.h_addrtype;
addr.sin_port= htons(port);
//*m_debug << "socket" << endl;
s = socket(host.h_addrtype, SOCK_STREAM, 0);
_show_args2(m_bufferSize,m_buffer);
if(s < 0)
result = kError_CantCreateSocket;
}
_show_args2(m_bufferSize,m_buffer);
// connect and send request
if(IsntError(result))
{
Error err;
int ret;
err = Connect(s, (struct sockaddr*)&addr, ret);
_show_args1((long int)result);
if (IsError(err))
result = kError_UserCancel;
if (ret < 0)
result = kError_ConnectFailed;
_show_args2(m_bufferSize,m_buffer);
if(IsntError(result))
{
gethostname(localname, kMaxHostNameLen);
_show_args2(m_bufferSize,m_buffer);
const char* kHTTPQuery = "GET %s HTTP/1.1\r\n"
"Host: %s\r\n"
"Accept: */*\r\n"
"User-Agent: FreeAmp/%s\r\n\r\n";
// the magic 256 is enough for a time field that
// we got from the server
size_t sizeof_query=strlen(kHTTPQuery)+strlen(file)+
strlen(localname)+strlen(FREEAMP_VERSION)+2;
int snprintf_return=0;
_show_args1(sizeof_query);
char* query = new char[sizeof_query];
_show_args2(m_bufferSize,m_buffer);
snprintf_return=snprintf(query, sizeof_query,kHTTPQuery, file, localname,
FREEAMP_VERSION);
_show_args2(m_bufferSize,m_buffer);
if (0>=snprintf_return)
{
exit(13);
}
if (strlen(query)>=sizeof_query)
{
exit(13);
}
int count;
err = Send(s, query, strlen(query), 0, count);
if (IsError(err))
result = kError_UserCancel;
if(count != (int)strlen(query))
{
result = kError_IOError;
}
delete [] query;
query=NULL;
}
}
_show_args2(m_bufferSize,m_buffer);
// receive response
if(IsntError(result))
{
uint32 bufferSize = 2048;
char* buffer = NULL;
int count;
uint32 total = 0;
buffer = (char*)malloc(bufferSize);
_show_args2(m_bufferSize,m_buffer);
result = kError_OutOfMemory;
if(buffer)
{
Error err;
result = kError_NoErr;
do
{
_show_args2(m_bufferSize,m_buffer);
if(total >= bufferSize - 1)
{
bufferSize *= 2;
buffer = (char*) realloc(buffer, bufferSize);
if(!buffer)
{
result = kError_OutOfMemory;
break;
}
}
_show_args2(m_bufferSize,m_buffer);
err = Recv(s, buffer + total, bufferSize - total - 1, 0, count);
_show_args2(m_bufferSize,m_buffer);
if (IsError(err))
result = kError_UserCancel;
if(count > 0)
total += count;
else
{
result = kError_IOError;
}
}while(IsntError(result) && !IsHTTPHeaderComplete(buffer, total));
}
_show_args2(m_bufferSize,m_buffer);
// parse header
if(IsntError(result))
{
uint32 returnCode = atoi(buffer+9);
buffer[total] = 0x00;
cout << buffer << endl;
cout << returnCode << endl;
_show_args2(m_bufferSize,m_buffer);
switch(buffer[9])
{
// 1xx: Informational - Request received, continuing process
case '1':
{
_you_are_here;
// not sure what to do here... continue receiving???
}
// 2xx: Success - The action was successfully received,
// understood, and accepted
case '2':
{
_show_args2(m_bufferSize,m_buffer);
Error err;
result = kError_UnknownErr;
int32 fileSize = GetContentLengthFromHeader(buffer);
_show_args2(m_bufferSize,m_buffer);
result = kError_NoErr;
int wcount = 0;
char* cp;
cp = strstr(buffer, "\r\n\r\n");
_show_args2(m_bufferSize,m_buffer);
if(cp)
cp += 4;
if(cp)
{
if(cp - buffer < (int)total)
{
_show_args2(m_bufferSize,m_buffer);
_show_args3(fileDownload,(unsigned char
*)cp,total-(cp-buffer));
if (fileDownload)
{
_show_args1(wcount);
wcount = this->Http::WriteToFile((unsigned char *)cp,
total - (cp - buffer));
_show_args1(wcount);
}
else
{
_show_args1(wcount);
_show_args3(m_bufferSize,m_bytesInBuffer,m_buffer);
wcount = this->Http::WriteToBuffer((unsigned char *)cp,
total - (cp-buffer));
_show_args1(wcount);
_show_args3(m_bufferSize,m_bytesInBuffer,m_buffer);
}
bytesReceived = total - (cp - buffer);
_show_args1(bytesReceived);
}
}
do
{
if (min(bufferSize, fileSize - bytesReceived) != 0)
{
err = Recv(s, buffer,
min(bufferSize, fileSize - bytesReceived),
0, count);
}
else
count = 0;
if (IsError(err))
result = kError_UserCancel;
else
if(count > 0)
{
_you_are_here;
if (fileDownload)
{
_show_args2((unsigned char *)buffer,count);
wcount = WriteToFile((unsigned char *)buffer,
(unsigned int)count);
_show_args1(wcount);
}
else
{
_show_args2((unsigned char *)buffer,count);
wcount = WriteToBuffer((unsigned char *)buffer
,
(unsigned int)count);
_show_args1(wcount);
_show_args3(m_bufferSize,m_bytesInBuffer,m_buffer);
}
bytesReceived += count;
_show_args1(bytesReceived);
Progress(bytesReceived, fileSize);
}
if(count < 0)
result = kError_IOError;
if(wcount < 0)
result = kError_WriteFile;
}while(count > 0 && IsntError(result) &&
!m_exit && wcount >= 0 &&
(int)bytesReceived != fileSize);
break;
}
// 3xx: Redirection - Further action must be taken in order to
// complete the request
case '3':
{
_you_are_here;
char* cp = strstr(buffer, "Location:");
//int32 length;
if(cp)
{
cp += 9;
if(*cp == 0x20)
cp++;
char *end;
for(end = cp; end < buffer + total; end++)
if(*end=='\r' || *end == '\n') break;
*end = 0x00;
if (305 == returnCode) // proxy
{
size_t sizeof_proxy=strlen(cp) + strlen(url.c_str()) + 1;
char* proxy = new char[sizeof_proxy];
snprintf(proxy, sizeof_proxy, "%s%s", cp, url.c_str());
result = Download(string(proxy), fileDownload);
delete [] proxy;
proxy=NULL;
}
else // redirect of some type
{
result = Download(string(cp), fileDownload);
}
}
break;
}
// 4xx: Client Error - The request contains bad syntax or cannot
// be fulfilled
case '4':
{
_you_are_here;
switch(returnCode)
{
case 400:
result = kError_BadHTTPRequest;
break;
case 401:
result = kError_AccessNotAuthorized;
break;
case 403:
result = kError_DownloadDenied;
break;
case 404:
result = kError_HTTPFileNotFound;
break;
default:
result = kError_UnknownErr;
break;
}
break;
}
// 5xx: Server Error - The server failed to fulfill an apparently
// valid request
case '5':
{
_you_are_here;
result = kError_UnknownServerError;
break;
}
default:
{
_you_are_here;
}
}
}
_show_args1((long int)result);
// cleanup
if(buffer) {
free(buffer);
buffer=NULL;
}
}
_show_args1(s);
// cleanup
if(s > 0)
closesocket(s);
_show_args2((long int)result,"end func\n");
return result;
}
Error Http::Connect(int hHandle, const sockaddr *pAddr, int &iRet)
{
fd_set sSet;
struct timeval sTv;
#if defined(WIN32)
unsigned long lMicrosoftSucksBalls = 1;
ioctlsocket(hHandle, FIONBIO, &lMicrosoftSucksBalls);
#elif defined(__BEOS__)
// int on = 1;
// setsockopt( hHandle, SOL_SOCKET, SO_NONBLOCK, &on, sizeof( on ) );
#else
fcntl(hHandle, F_SETFL, fcntl(hHandle, F_GETFL) | O_NONBLOCK);
#endif
iRet = connect(hHandle, (const sockaddr *)pAddr,sizeof(*pAddr));
#ifndef WIN32
if (iRet == -1 && errno != EINPROGRESS)
return kError_NoErr;
#endif
for(; iRet && !m_exit;)
{
sTv.tv_sec = 0; sTv.tv_usec = 0;
FD_ZERO(&sSet); FD_SET(hHandle, &sSet);
iRet = select(hHandle + 1, NULL, &sSet, NULL, &sTv);
if (!iRet)
{
usleep(100000);
continue;
}
if (iRet < 0)
return kError_NoErr;
break;
}
if (m_exit)
return kError_Interrupt;
return kError_NoErr;
}
Error Http::Recv(int hHandle, char *pBuffer, int iSize,
int iFlags, int &iRead)
{
_show_args2(m_bufferSize,m_buffer);
fd_set sSet;
struct timeval sTv;
int iRet;
iRead = 0;
for(; !m_exit;)
{
sTv.tv_sec = 0; sTv.tv_usec = 0;
FD_ZERO(&sSet); FD_SET(hHandle, &sSet);
iRet = select(hHandle + 1, &sSet, NULL, NULL, &sTv);
if (!iRet)
{
usleep(10000);
continue;
}
_show_args2(m_bufferSize,m_buffer);
iRead = recv(hHandle, pBuffer, iSize, iFlags);
_show_args2(m_bufferSize,m_buffer);
if (iRead < 0)
{
return kError_NoErr;
}
break;
}
_show_args2(m_bufferSize,m_buffer);
if (m_exit)
return kError_Interrupt;
return kError_NoErr;
}
Error Http::Send(int hHandle, char *pBuffer, int iSize,
int iFlags, int &iRead)
{
fd_set sSet;
struct timeval sTv;
int iRet;
iRead = 0;
for(; !m_exit;)
{
sTv.tv_sec = 0; sTv.tv_usec = 0;
FD_ZERO(&sSet); FD_SET(hHandle, &sSet);
iRet = select(hHandle + 1, NULL, &sSet, NULL, &sTv);
if (!iRet)
{
usleep(10000);
continue;
}
iRead = send(hHandle, pBuffer, iSize, iFlags);
if (iRead < 0)
{
return kError_NoErr;
}
break;
}
if (m_exit)
return kError_Interrupt;
return kError_NoErr;
}
void Http::Progress(unsigned int bytesReceived, unsigned int maxBytes)
{
}
bool Http::IsHTTPHeaderComplete(char* buffer, uint32 length)
{
bool result = false;
for(char* cp = buffer; cp < buffer + length; cp++)
{
if(!strncmp(cp, "\n\n", 2) || !strncmp(cp, "\r\n\r\n", 4))
{
result = true;
break;
}
}
return result;
}
int32 Http::GetContentLengthFromHeader(const char* buffer)
{
int32 result = -1;
char* cp = strstr(buffer, "Content-Length:");
if(cp)
{
cp += strlen("Content-Length:") + 1;
result = atoi(cp);
}
return result;
}