I'm using boost::asio to create a TCP client. I'm testing it out by loading a web site. I can create a connection, read, have my callback fired, etc, no problem. However, at the of every packet, I'm finding this, or something like it:
ýýýý««««««««îþîþ
I'm wondering how I can determine the size of what was actually read. In the code below, assume my socket is set up properly. I've connected to a URL (a plain old web site), sent a request, and have started reading. When I read the data, I get the data back, plus some extra weirdness.
class TcpClient
{
...
boost::asio::streambuf mResponse;
std::shared_ptr<boost::asio::ip::tcp::socket> mSocket;
...
void read()
{
boost::asio::async_read( *mSocket, mResponse,
boost::asio::transfer_at_least( 1 ),
boost::bind( &TcpClient::onRead, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred ) );
}
void onRead( const boost::system::error_code& err, size_t bytesTransferred )
{
if ( err ) {
if ( err == boost::asio::error::eof ) {
cout << "Read complete" << endl;
} else {
cout << "Error" << endl;
}
} else {
char* data = new char[ bytesTransferred ];
istream stream( &mResponse );
stream.read( data, bytesTransferred );
cout << data << endl;
delete [] data;
read();
}
mResponse.consume( mResponse.size() );
}
...
};
Below is the result of the first packet I receive from http://libcinder.org.
HTTP/1.1 200 OK
Server: nginx/0.5.33
Date: Fri, 24 May 2013 01:05:55 GMT
Content-Type: text/html; charset=utf-8
Connection: close
Vary: Cookie
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>Cinder | The library for professional-quality creative coding in C++</title>
<meta name="Descýýýý««««««««îþîþ
Answer came via Igor R.
This...
char* data = new char[ bytesTransferred ];
...should be...
char* data = new char[ bytesTransferred + 1 ];
data[ bytesTransferred ] = 0;
Related
I used one of one of the example of boost::beast web server asynchronous to communicate with client javascript using websocket. I am attempting to do the simple receiving image and write it in server side.
The result I receive in the server side is a broken jpg image.
Thank you in advance.
client-side (javascript)
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
var img = document.getElementById("image");
var ws = null;
connect.onclick = function() {
ws = new WebSocket(uri.value);
ws.onopen = function(ev) {
messages.innerText += "[connection opened]\n";
};
ws.onclose = function(ev) {
messages.innerText += "[connection closed]\n";
};
ws.onmessage = function(ev) {
messages.innerText += ev.data + "\n";
};
ws.onerror = function(ev) {
messages.innerText += "[error]\n";
console.log(ev);
};
};
disconnect.onclick = function() {
ws.close();
};
send.onclick = function() {
var canvas1 = ctx.getImageData(0,0,img.width,img.height);
var binary = new Uint8Array(img.data.length);
for (var i=0; i<img.data.length; ++i) {
binary[i] = img.data[i];
}
ws.send(binary.buffer);
}
server-side
void on_write(boost::system::error_code ec,
std::size_t bytes_transferred)
{
boost::ignore_unused(bytes_transferred);
if(ec)
return fail(ec, "write");
buffer_.consume(buffer_.size());
std::cout << "on write before do read\n";
ws_.async_read(
buffer_,
boost::asio::bind_executor(
strand_,
std::bind(
&session::on_read,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2)));
uint8_t *buf = new uint8_t [bytes_transferred];
boost::asio::buffer_copy(boost::asio::buffer(buf,bytes_transferred),buffer_.data(),bytes_transferred);
::cv::Mat mImg(400,320,CV_8UC3,buf);
::cv::imwrite("file.jpg",mImg);
delete [] buf;
}
I first recommend refactoring your code into small testable functions.
Write a function like this:
template <class AsyncStream, class CompletionToken>
auto
async_write_opencv_image(AsyncStream&, CompletionToken&& token)
{
// write composed op here
}
Using this, you can feed in a boost::beast::test::stream to the function which will allow you to manually inspect the buffers to ensure the image's correctness.
This has the advantage that now your image writing code is stream-agnostic so you can swap it out for any other type.
If you need any assistance in this regard, there's ample documentation on boost.org as well as live-help on the cpplang slack team.
Edit:
Here's a wandbox example how to potentially also setup a unit test for websockets as well:
https://wandbox.org/permlink/EixDmotCphJwiDZ1
I am trying to download a file from internet in C++. Hold the downloaded contents into HInternet Instance.
Also I populated the header information of HInternet instance. That is looks like
Header contents:
HTTP/1.1 200 OK
Cache-Control: no-cache
Date: Fri, 24 Nov 2017 07:00:26 GMT
Pragma: no-cache
Content-Length: 71156
Content-Type: text/html
Expires: -1
Server: Microsoft-IIS/8.0
Content-Disposition: attachment; filename=642078_3855u.zip
X-AspNet-Version: 4.0.30319
Error 0 has occurred.
Now I am trying to copied the 642088_3855u.zip file into some location.
So, I tried as,
if (bResults)
{
do
{
// Check for available data.
dwSize = 0;
if (!WinHttpQueryDataAvailable(hRequest, &dwSize))
{
dwLastError = GetLastError();
break;
}
// No more available data.
if (!dwSize)
break;
// Allocate space for the buffer.
pszOutBuffer = new char[dwSize + 1];
if (!pszOutBuffer)
{
bError = true;
break;
}
FILE *pfDestination = NULL;
_wfopen_s(&pfDestination, strDestinationFolder + L"\\" + L"642078_3855u.zip", L"w+b");
if (pfDestination == NULL)
{
bError = true;
break;
}
// Read the Data.
ZeroMemory(pszOutBuffer, dwSize + 1);
if (WinHttpReadData(hRequest, (LPVOID)pszOutBuffer,
dwSize, &dwDownloaded))
{
fwrite(pszOutBuffer, 1, dwDownloaded, pfDestination);
}
// Free the memory allocated to the buffer.
delete[] pszOutBuffer;
fclose(pfDestination);
// reported that there are bits to read.
if (!dwDownloaded)
break;
} while (dwSize > 0);
}
I am not getting any error, actual size of zip if is 72kb but it is created zip file with 4kb and when I am trying to open zip file, I am getting error Invalid zip file.
Note that: zip file contains executable also.
any suggestion where I am doing mistake.
Thanks,
I am trying to stream audio data from disk using OpenAL's buffer queueing mechanism. I load and enqueue 4 buffers, start the source playing, and check in a regular intervals to refresh the queue. Everything looks like it's going splendidly, up until the first time I try to load data into a recycled buffer I got from alSourceUnqueueBuffers(). In this situation, alBufferData() always sets AL_INVALID_OPERATION, which according to the official v1.1 spec, it doesn't seem like it should be able to do.
I have searched extensively on Google and StackOverflow, and can't seem to find any reason why this would happen. The closest thing I found was someone with a possibly-related issue in an archived forum post, but details are few and responses are null. There was also this SO question with slightly different circumstances, but the only answer's suggestion does not help.
Possibly helpful: I know my context and device are configured correctly, because loading small wav files completely into a single buffer and playing them works fine. Through experimentation, I've also found that queueing 2 buffers, starting the source playing, and immediately loading and enqueueing the other two buffers throws no errors; it's only when I've unqueued a processed buffer that I run into trouble.
The relevant code:
static constexpr int MAX_BUFFER_COUNT = 4;
#define alCall(funcCall) {funcCall; SoundyOutport::CheckError(__FILE__, __LINE__, #funcCall) ? abort() : ((void)0); }
bool SoundyOutport::CheckError(const string &pFile, int pLine, const string &pfunc)
{
ALenum tErrCode = alGetError();
if(tErrCode != 0)
{
auto tMsg = alGetString(tErrCode);
Log::e(ro::TAG) << tMsg << " at " << pFile << "(" << pLine << "):\n"
<< "\tAL call " << pfunc << " failed." << end;
return true;
}
return false;
}
void SoundyOutport::EnqueueBuffer(const float* pData, int pFrames)
{
static int called = 0;
++called;
ALint tState;
alCall(alGetSourcei(mSourceId, AL_SOURCE_TYPE, &tState));
if(tState == AL_STATIC)
{
Stop();
// alCall(alSourcei(mSourceId, AL_BUFFER, NULL));
}
ALuint tBufId = AL_NONE;
int tQueuedBuffers = QueuedUpBuffers();
int tReady = ProcessedBuffers();
if(tQueuedBuffers < MAX_BUFFER_COUNT)
{
tBufId = mBufferIds[tQueuedBuffers];
}
else if(tReady > 0)
{
// the fifth time through, this code gets hit
alCall(alSourceUnqueueBuffers(mSourceId, 1, &tBufId));
// debug code: make sure these values go down by one
tQueuedBuffers = QueuedUpBuffers();
tReady = ProcessedBuffers();
}
else
{
return; // no update needed yet.
}
void* tConverted = convert(pData, pFrames);
// the fifth time through, we get AL_INVALID_OPERATION, and call abort()
alCall(alBufferData(tBufId, mFormat, tConverted, pFrames * mBitdepth/8, mSampleRate));
alCall(alSourceQueueBuffers(mSourceId, 1, &mBufferId));
if(mBitdepth == BITDEPTH_8)
{
delete (uint8_t*)tConverted;
}
else // if(mBitdepth == BITDEPTH_16)
{
delete (uint16_t*)tConverted;
}
}
void SoundyOutport::PlayBufferedStream()
{
if(!StreamingMode() || !QueuedUpBuffers())
{
Log::w(ro::TAG) << "Attempted to play an unbuffered stream" << end;
return;
}
alCall(alSourcei(mSourceId, AL_LOOPING, AL_FALSE)); // never loop streams
alCall(alSourcePlay(mSourceId));
}
int SoundyOutport::QueuedUpBuffers()
{
int tCount = 0;
alCall(alGetSourcei(mSourceId, AL_BUFFERS_QUEUED, &tCount));
return tCount;
}
int SoundyOutport::ProcessedBuffers()
{
int tCount = 0;
alCall(alGetSourcei(mSourceId, AL_BUFFERS_PROCESSED, &tCount));
return tCount;
}
void SoundyOutport::Stop()
{
if(Playing())
{
alCall(alSourceStop(mSourceId));
}
int tBuffers;
alCall(alGetSourcei(mSourceId, AL_BUFFERS_QUEUED, &tBuffers));
if(tBuffers)
{
ALuint tDummy[tBuffers];
alCall(alSourceUnqueueBuffers(mSourceId, tBuffers, tDummy));
}
alCall(alSourcei(mSourceId, AL_BUFFER, AL_NONE));
}
bool SoundyOutport::Playing()
{
ALint tPlaying;
alCall(alGetSourcei(mSourceId, AL_SOURCE_STATE, &tPlaying));
return tPlaying == AL_PLAYING;
}
bool SoundyOutport::StreamingMode()
{
ALint tState;
alCall(alGetSourcei(mSourceId, AL_SOURCE_TYPE, &tState));
return tState == AL_STREAMING;
}
bool SoundyOutport::StaticMode()
{
ALint tState;
alCall(alGetSourcei(mSourceId, AL_SOURCE_TYPE, &tState));
return tState == AL_STATIC;
}
And here's an annotated screen cap of what I see in my debugger when I hit the error:
I've tried a bunch of little tweaks and variations, and the result is always the same. I've wasted too many days trying to fix this. Please help :)
This error occurs when you trying to fill buffer with data, when the buffer is still queued to the source.
Also this code is wrong.
if(tQueuedBuffers < MAX_BUFFER_COUNT)
{
tBufId = mBufferIds[tQueuedBuffers];
}
else if(tReady > 0)
{
// the fifth time through, this code gets hit
alCall(alSourceUnqueueBuffers(mSourceId, 1, &tBufId));
// debug code: make sure these values go down by one
tQueuedBuffers = QueuedUpBuffers();
tReady = ProcessedBuffers();
}
else
{
return; // no update needed yet.
}
You can fill buffer with data only if it unqueued from source. But your first if block gets tBufId that queued to the source. Rewrite code like so
if(tReady > 0)
{
// the fifth time through, this code gets hit
alCall(alSourceUnqueueBuffers(mSourceId, 1, &tBufId));
// debug code: make sure these values go down by one
tQueuedBuffers = QueuedUpBuffers();
tReady = ProcessedBuffers();
}
else
{
return; // no update needed yet.
}
I got a project that required drag & drop xml files from windows explorer into a TableModel, whatever I tried, that widget rejects(with the annoying block icon) the process and not any functions below are called.
i've tried the following:
reimplement QAbstarctTableView::flags to support drag & drop
remiplement QAbstractTableView::supportedDropActions.
remiplement QAbstractTableView::mimeTypes. return "text/uri-list", "text/plain", "application/xml", "text/xml". (some said that "text/uri-list" shall be enough.)
according to most posts i found in the internet, I shall be able to drag files into the TableView Widget now. That's not true for me. T_T
here's my code.
// set the flags to accept drop & drag
Qt::ItemFlags XMLFileModel::flags(const QModelIndex& index) const {
Qt::ItemFlags defaultFlags = Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
if (index.isValid())
return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
else
return Qt::ItemIsDropEnabled | defaultFlags;
}
.
// drop mime data
bool XMLFileModel::dropMimeData(const QMimeData *data,
Qt::DropAction action, int row, int column, const QModelIndex &parent)
{
qDebug() << "Drop Mime data" << endl;
if (action == Qt::IgnoreAction)
return true;
if (! data->hasUrls())
return false;
QList<QUrl> urls = data->urls();
foreach(QUrl url , urls) {
std::shared_ptr<QFile> file(new QFile(url.path()));
if (! file->open(QIODevice::ReadOnly | QIODevice::Text))
{
QMessageBox::warning(NULL, QString("note"), QString("unable to open file!"));
return false;
}
XMLFilePtr xml(new XMLFile(file->fileName(), file));
addXMLFile(xml);
}
return true;
}
.
Qt::DropActions XMLFileModel::supportedDropActions() const
{
qDebug () << "supportedDropActions";
return Qt::CopyAction | Qt::MoveAction;
}
.
// define the acceptable mime type
QStringList XMLFileModel::mimeTypes() const
{
qDebug () << "mimeTypes";
QStringList types;
types << "text/uri-list" << "text/plain" << "application/xml" << "text/xml";
qDebug() << types;
return types;
}
.
I tried to add
QMimeData* mimeData(const QModelIndexList &indexes) const;
and now I could drag&drop inside the tableview or even between table views. debug messages print as well.
then I continued to do the test.
I wrote a test class:
class test : public QTableView
{
Q_OBJECT
public:
explicit test(QWidget *parent = 0);
virtual void dropEvent(QDropEvent *event);
virtual void dragEnterEvent ( QDragEnterEvent * event );
void startDrag ( Qt::DropActions supportedActions );
};
.
void test::dropEvent(QDropEvent *event) {
qDebug() << "test";
qDebug() << event->mimeData()->formats();
event->accept();
}
void test::dragEnterEvent(QDragEnterEvent *event) {
qDebug() << "drag enter";
qDebug() << event->mimeData();
event->accept();
}
void test::startDrag(Qt::DropActions supportedActions) {
qDebug() << "true";
}
.
and add a new test widget in the mainWindow that accepts the same model.
It amazed me that drag&drop internally or between table views is still working. but when I tried to drop the item from my desktop, none of these three functions are called.
now I am thinking that the problem might be the incompatible mime-type between my OS and Qt D&D framework. I may not return the right mime type
any one suffered and solved this problem or any suggestions? >_<
= = = = = = = =
hey, I got the same problem with the drop site example, too!
I don't think you need to reimplement any of those functions except for dragEnterEvent and dropEvent. Did you call QWidget::setAcceptDrops(true)? This is important.
In Firefox internet connection is made through a proxy auto configuration file something.pac.
How do I know for a certain URL which proxy server is being used?
.pac file is just an ECMAscript - aka JavaScript. Check out the wikipedia article on the file format.
If you copy the PAC code you can process it to see what proxy is being used based on the target url. If you are feeling fancy, you can wrap the script into a web page (locally) to create a tool to evaluate locally.
Edit:
As an alternative to the method I started recommending, you might check out PACTester, available on Google Code. This will allow you to quickly test a range of options.
If you have .Net available and are interested in playing with C# then you can check out this article on MSDN which has code you can use in a similar fashion to the above.
To expand on the original method outlined above, there are a number of functions which may (and typically are) provided by the host browser. The basic function which must be implemented in a pac file is FindProxyForUrl(). This accepts two parameters: the url and the host (the host derived from the name of url). The "provided" functions include: isInNet(), localHostOrDomainIs(), isPlainHostName(), isResolvable(), etc.
If you are working in a Microsoft environment then you can check out this page on Technet which describes the .pac format with some useful examples.
Per the Microsoft documentation for isInNet():
The isInNet(host, pattern, mask) function returns TRUE if the host IP address matches the specified pattern. The mask indicates which part of the IP address to match (255=match, 0=ignore).
If you want to get technical, here is the Mozilla source code for the implementation of proxy auto-config related services. It specifies the JS code for isInNet() as:
200 function isInNet(ipaddr, pattern, maskstr) {
201 var test = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/(ipaddr);
202 if (test == null) {
203 ipaddr = dnsResolve(ipaddr);
204 if (ipaddr == null)
205 return false;
206 } else if (test[1] > 255 || test[2] > 255 ||
207 test[3] > 255 || test[4] > 255) {
208 return false; // not an IP address
209 }
210 var host = convert_addr(ipaddr);
211 var pat = convert_addr(pattern);
212 var mask = convert_addr(maskstr);
213 return ((host & mask) == (pat & mask));
214
215 }
Hope that helps!
I've created simple HTML page resolving proxy:
<html>
<head>
<script type="text/javascript">
function myIpAddress() {
return "192.168.1.2"; // Your IP
}
function isInNet(ipaddr, pattern, maskstr) {
var test = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/(ipaddr);
if (test == null) {
ipaddr = dnsResolve(ipaddr);
if (ipaddr == null) return false;
} else if (test[1] > 255 || test[2] > 255 || test[3] > 255 || test[4] > 255) {
return false; // not an IP address
}
var host = convert_addr(ipaddr);
var pat = convert_addr(pattern);
var mask = convert_addr(maskstr);
return ((host & mask) == (pat & mask));
}
function dnsResolve(host) {
try {
return dns.resolve(host, 0).getNextAddrAsString();
} catch (e) {
return null;
}
}
function convert_addr(ipchars) {
var bytes = ipchars.split('.');
var result = ((bytes[0] & 0xff) << 24) |
((bytes[1] & 0xff) << 16) |
((bytes[2] & 0xff) << 8) |
(bytes[3] & 0xff);
return result;
}
function isPlainHostName(host) {
return host.search('\\\\.') == -1;
}
function shExpMatch(url, pattern) {
pattern = pattern.replace(/\\./g, '\\\\.');
pattern = pattern.replace(/\\*/g, '.*');
pattern = pattern.replace(/\\?/g, '.');
var newRe = new RegExp('^' + pattern + '$');
return newRe.test(url);
}
function dnsDomainIs(host, domain) {
return host.length >= domain.length && host.substring(host.length - domain.length) == domain;
}
</script>
<!-- Your proxy script -->
<script type="text/javascript" src="webproxy.js"></script>
</head>
<body>
Host: <input id="host"/><br/>
URL: <input id="url"/><br/>
Proxy: <input id="proxy" disabled="disabled"/><br/>
<input type="button" value="Resolve"
onclick="document.getElementById('proxy').value = FindProxyForURL(document.getElementById('host').value, document.getElementById('url').value)"/><br/>
</body>
</html>
Code for myIpAddress etc I've got from mozilla sources.