How to receive a message through TCPBasicClientApp in omnet++? - tcp

I have made two different TCP Applications in Omnet++, one is TCPBasicClientApp and other is TCPGenericServerApp. TCP client application is successfully sending a GenericAppMsg through TCP Protocol. Once the message is received on the Server Side (with a specific replyLength) it is sending it back to the client side through SendBack() method (also mentioned in the inet example application).
My question is, how to receive this message back on the client side?
Here is the omnet.ini file code, for this transfer,
The Client Side,
**.host[0].numTcpApps = 1
**.host[0].tcpApp[0].typename = "ReputationAlgorithmApplication"
**.host[0].tcpApp[0].localAddress = ""
**.host[0].tcpApp[0].localPort = -1
**.host[0].tcpApp[0].connectAddress = "host[3]"
**.host[0].tcpApp[0].connectPort = 2000
**.host[0].tcpApp[0].dataTransferMode = "object"
The Server Side,
**.host[3].numTcpApps = 1
**.host[3].tcpApp[*].typename = "ReputationServerApplication"
**.host[3].tcpApp[*].localAddress = "host[3]"
**.host[3].tcpApp[*].localPort = 2000
Here is the sendBack method on Server Side,
void ReputationServerApplication::sendBack(cMessage *msg) {
cPacket *packet = dynamic_cast<cPacket *>(msg);
if (packet) {
msgsSent++;
bytesSent += packet->getByteLength();
emit(sentPkSignal, packet);
EV_INFO << "sending \"" << packet->getName() << "\" to TCP, "
<< packet->getByteLength() << " bytes\n";
} else {
EV_INFO << "sending \"" << msg->getName() << "\" to TCP\n";
}
DummyMessageForReputation *msgDum =
dynamic_cast<DummyMessageForReputation *>(msg);
std::cout << "\n Tested: Message with the string "
<< msgDum->getMessageString() << " is sending back to "
<< msgDum->getNodeName();
send(msgDum, "tcpOut");
}
Any help would be appreciated.

You can use TCPBasicClientApp::socketDataArrived() to process the received message on the client side.

Related

Listing Directory Entries with Qt on Remote Windows Server

I am on a Windows Server which is in the same network as the Server with the computer name service.
I got this simple code which tries to list the content
QFileInfoList fiList = QDir("\\service\\Documents").entryInfoList(QDir::Files);
qDebug() << "sizeof filist: " << fiList.size();
for (const QFileInfo& fi : fiList)
{
qDebug() << fi.absoluteFilePath();
}
The output is the following:
sizeof filist: 0
I make sure that the folder is shared on the network by checking the properties and also using the windows explorer. I can access the folder via Windows Explorer.
Is the functionality I am trying to achieve not possible with QDir?
It turns out there are 2 backslashes more needed because \ needs to be escaped.
So the right code would be:
QFileInfoList fiList = QDir("\\\\service\\Documents").entryInfoList(QDir::Files);
qDebug() << "sizeof filist: " << fiList.size();
for (const QFileInfo& fi : fiList)
{
qDebug() << fi.absoluteFilePath();
}

Files getting corrupted when being downloaded using QNetworkAcessManager

I'm developing a client app whose purpose is to download some files from a web server, temporarily store them in the Temp folder, check for file integrity, then send them to a FTP server in a Embedded Linux device.
Recently I got problems when doing the process in a preliminary development stage when I was trying to do the download from my local machine (see related question here). Now I'm able to download and upload without errors and with verification (I'm using QCryptographicHash + file size to check for any nonconformities) from my machine, but the same doesn't happen when I try downloading from the HTTP server.
There is a total of 8 files being downloaded: three .tar.gz, one simple text, two programs and two binaries. I'm able to successfully download all compressed files, the text file and one of the binaries, but the others, namely the two programs and one of the binaries (a Linux Kernel image) are always being incorrectly downloaded.
I check this by noticing not only that the hash returns error for them, but also for their sizes: their sizes are always wrong (and always the same erroneous value for any download attempt). And the files in the server are all correct.
My first suspicion was that I need to configure the HTTP download in a way that differs from the common FTP download from the local machine, but I'm unaware on how would that be. Moreover if this extra configuration was needed, then why some of the files always return correctly?
Here is the relevant code as for now:
void MainWindow::processNextDownload()
{
QUrl ulrTemp(updateData.at(transferStep).downloadUrl.arg(ui->leID->text())); //"//" +
if (updateData.at(transferStep).downloadUrl.contains("http"))
ulrTemp.setScheme("http");
else
ulrTemp.setScheme("file");
// ulrTemp.setUserName();
// ulrTemp.setPassword();
// ulrTemp.setPort();
qDebug() << "Downloading" << transferStep << "from" << ulrTemp;
#if 1
poReply = downloadNetworkManager->get(QNetworkRequest(ulrTemp));
#else
QNetworkRequest request;
request.setUrl(ulrTemp);
request.setRawHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.60 Safari/537.17");
poReply = downloadNetworkManager->get(request);
#endif
connect(poReply,SIGNAL(downloadProgress(qint64,qint64)),this,SLOT(slotDownloadProgress(qint64,qint64)));
ui->statusBar->showMessage(tr("Downloading: %1").arg(updateData.at(transferStep).itemName));
}
void MainWindow::slotFileDownloaded(QNetworkReply* reply)
{
if (reply && (reply->error() != QNetworkReply::NoError))
{
ui->statusBar->clearMessage();
if (!isSingleFile)
{
const QString strTemp = tr("An error occurred while downloading \"%1\": %2 (error message: %3)")
.arg(updateData.at(transferStep).downloadName).arg(reply->error()).arg(reply->errorString());
QMessageBox::critical(this,tr("Error in download"),strTemp);
}
else
{
//irrelevant...
}
finished(false);
return;
}
qDebug() << "To write: " << reply->bytesAvailable();
QByteArray downloadedData = reply->readAll();
reply->deleteLater();
poReply->deleteLater();
//![]
static const QString tempFilePath = QDir::tempPath();
if (!isSingleFile)
{
QFile file(tempFilePath + "/" + updateData.at(transferStep).downloadName);
if (!file.open(QFile::WriteOnly | QFile::Truncate))
{
qDebug() << "Failure opening temp file to write: " << file.fileName();
QMessageBox::critical(this,
tr("Error"),
tr("An error occured while trying to open a temporary file to write the downloaded data (file: %1).").arg(file.fileName()));
transferStep = downloadStepCount;
slotFileUploaded(NULL);
return;
}
qint32 bytesWritten = file.write(downloadedData);
file.flush();
if (downloadedData.size() != bytesWritten)
qDebug() << "Write failed, wrote" << bytesWritten << "out of" << downloadedData.size() << "bytes.";
else
qDebug() << "Wrote " << bytesWritten << "bytes.";
file.close();
//![]
if (++transferStep >= downloadStepCount)
{
qDebug() << "Start hash check";
slotStartHashCheck();
return;
}
processNextDownload();
}
else
{
//irrelevant...
}
}
And this is why I get (the last number value after the "=" in the hash code is the file size):
So what am I missing?

Qt endl looks great from linux telnet, wrong from windows telnet

I am building a telnet server app in Qt, and when I connect from a linux telnet client output looks great. For example, sending "A" << endl << "B" << endl << "C" to my console looks like:
A
B
C
Now when I connect from a Windows telnet client I see
A
B
C
obviously Qt's endl is sending only '\n'. Is there a SIMPLE solution to this? If I replace endl with "\r\n" do I mess up linux clients now? Do I have to force a flush too?
Here is actual code I am using to send to my telnet client:
QString block;
QTextStream out(&block, QIODevice::WriteOnly);
out << "Valid commands are: " << endl
<< " help Print this list" << endl
<< " version Print this version" << endl
<< " clientcount Show the number of active telnet clients" << endl
<< " logrotate Rotate the event log file" << endl
<< " shutdown Initiate shutdown secast" << endl
<< " quit Disconnect your telnet session" << endl
<< " stop Shutdown secast" << endl;
tcpSocketPtr->write(block.toUtf8());
You could simply drop the QTextStream and write the QString directly in here:
QString block = QString("Valid commands are: \n")
+ " help Print this list\n"
+ " version Print this version\n"
+ " clientcount Show the number of active telnet clients\n"
+ " logrotate Rotate the event log file\n"
+ " shutdown Initiate shutdown secast\n"
+ " quit Disconnect your telnet session\n"
+ " stop Shutdown secast\n";
tcpSocketPtr->write(block.toUtf8());
Based on your comment though, you seem to use some old DOS client (on Windows!) which expects "\r\n". In that case, I would send "\r\n" for that, but only the usual "\n" for Linux. It is a not so good practice to send carriage return as well on Linux, and not just line feed even though "\r\n" may seem to work on Linux.

How use Procedure.Exec with C++Builder XE

I have a piece of code as show belowe, wich run well with C++Builder-6.
Now I have moved tha program to C++Builder-XE and the call to "RiconfiguraNodo << nomeNodo ...." give me the ambguity error report belowe.
I tried several way to rewrite the call to the ole proceudre "RiconfiguraNodo", but I didn't find a working solution.
How can I rewrite this snippet of code in way suitable for C++BuilderXE
Error reported:
[BCC32 Error] UnitMain.cpp(262): E2015 Ambiguity between 'operator
System::AutoCmd::<<(const System::Currency) at c:\program files
(x86)\embarcadero\rad studio\8.0\include\windows\rtl\sysvari.h:3561'
and 'operator System::AutoCmd::<<(const System::TDateTime)
at c:\program files (x86)\embarcadero\rad
studio\8.0\include\windows\rtl\sysvari.h:3562'
Full parser context
UnitMain.cpp(245): parsing: void _fastcall TFormMain::RiconfiguraNodo(System::UnicodeString,System::UnicodeString,System::UnicodeString,System::UnicodeString)
Sample code:
Procedure RiconfiguraNodo( L"RiconfiguraNodo" );
if (VarServerPmvManager.IsEmpty() || VarServerPmvManager.IsNull())
{
VarServerPmvManager = VarServerPmvManager.CreateObject(ProgId_ServerPmvmanager);
}
try
{
VarServerPmvManager.Exec( RiconfiguraNodo << nomeNodo << ipAddress << tipoPmv << cmdType );
}
catch (Exception & ex)
{
Mylog(Fun + Sysutils::Format("ERROR=[%s] ", ARRAYOFCONST((ex.Message))));
}
I found the solution.
The procedure exec simply require Variant instead of plain string
Variant vNomeNodo, vIpAddress, vTipoPmv, vCmdType;
vNomeNodo = nomeNodo;
vIpAddress = ipAddress;
vTipoPmv = tipoPmv;
vCmdType = cmdType;
VarServerPmvManager.Exec( RiconfiguraNodo << vNomeNodo << vIpAddress << vTipoPmv << vCmdType );

what ip address does accept return

see the following code:
accept(sockfd, (struct sockaddr*)&cliaddr, &slen);
cout << inet_ntop(AF_INET, cliaddr.sin_addr, ipv4addr, 100);
my client connects from localhost.
i get an absurd address in the output. this is not my ip address. everytime i run the code i get a different ip address. when i ping that ip address i don't get any response.
what is the reason.
i am running suse linux on a virtual machine in windows vista.
Update:
bzero(&cliaddr, sizeof(cliaddr));
int connfd = accept(sockfd, (struct sockaddr*)&cliaddr, &slen);
if (sem_wait(&mutex) < 0)
err_sys("sem_init error");
char ipv4addr[100];
cout << inet_ntop(AF_INET, &cliaddr.sin_addr, ipv4addr, 100) << endl;
//const char* p = inet_ntop(AF_INET, &cliaddr.sin_addr, ipv4addr, 100);
//cout << p << endl;
//cout << (void*)p << " " << (void*)ipv4addr << endl;
this returns address as 0.0.0.0
if i uncomment the lines, i get the correct address in all the lines, 127.0.0.1
You are missing the 4th parameter in your call to inet_ntop(). Here's a working example:
int sockfd, fd;
struct sockaddr_in saddr;
socklen_t len = sizeof( saddr );
char addr_buf[INET_ADDRSTRLEN]; /* defined in <netinet/in.h> */
/* ... socket(), bind(), listen() */
bzero( &saddr, len );
if (( fd = accept( sockfd, ( struct sockaddr* )&saddr, &len )) == -1 )
{ perror( "accept" ); exit( 1 ); } /* watch out for EINTR */
if ( inet_ntop( AF_INET, &saddr.sin_addr, addr_buf,
INET_ADDRSTRLEN ) == NULL )
{ perror( "inet_ntop" ); exit( 1 ); }
printf( "accepted connection from [%s:%d]\n",
addr_buf, ntohs( saddr.sin_port ));
...
Always check for errors when talking to network.
My unsubstantiated guess is that you're getting IP v6 addresses back instead of v4, so your conversion is off.
You might want to try using netstat to find out the client's port (you usually get a sort-of-random port number between 1025 and 65535) and see if the hex value of that appears somewhere in the hex representation of cliaddr. If there's a correlation between client port and what you believe to be the client address, then your conversion is incorrect.
My next guess:
On success, inet_ntop() returns a non-null pointer to dst. NULL is
returned if there was an error, with errno set to indicate the error.
Is cout.<< clever enough to dereference the pointer that's being returned, or are you printing out the pointer?

Resources