Can anyone tels me the order in which TcpBasicClientApp of inet works
I know that in any simple module-based application, the functions called in the following order:
1- constructor
2-initialize
3- (if initialize contains send() then the following function would be handlemessage)
4- finish
// Copyright (C) 2004 Andras Varga
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
//
#include "inet/applications/tcpapp/TcpBasicClientApp.h"
#include "inet/common/ModuleAccess.h"
#include "inet/common/lifecycle/NodeOperations.h"
#include "inet/common/packet/Packet.h"
#include "inet/applications/tcpapp/GenericAppMsg_m.h"
namespace inet {
#define MSGKIND_CONNECT 0
#define MSGKIND_SEND 1
Define_Module(TcpBasicClientApp);
TcpBasicClientApp::~TcpBasicClientApp()
{
cancelAndDelete(timeoutMsg);
}
void TcpBasicClientApp::initialize(int stage)
{
TcpAppBase::initialize(stage);
if (stage == INITSTAGE_LOCAL) {
numRequestsToSend = 0;
earlySend = false; // TBD make it parameter
WATCH(numRequestsToSend);
WATCH(earlySend);
startTime = par("startTime");
stopTime = par("stopTime");
if (stopTime >= SIMTIME_ZERO && stopTime < startTime)
throw cRuntimeError("Invalid startTime/stopTime parameters");
}
else if (stage == INITSTAGE_APPLICATION_LAYER) {
timeoutMsg = new cMessage("timer");
nodeStatus = dynamic_cast<NodeStatus *>(findContainingNode(this)->getSubmodule("status"));
if (isNodeUp()) {
timeoutMsg->setKind(MSGKIND_CONNECT);
scheduleAt(startTime, timeoutMsg);
}
}
}
bool TcpBasicClientApp::isNodeUp()
{
return !nodeStatus || nodeStatus->getState() == NodeStatus::UP;
}
bool TcpBasicClientApp::handleOperationStage(LifecycleOperation *operation, int stage, IDoneCallback *doneCallback)
{
Enter_Method_Silent();
if (dynamic_cast<NodeStartOperation *>(operation)) {
if (static_cast<NodeStartOperation::Stage>(stage) == NodeStartOperation::STAGE_APPLICATION_LAYER) {
simtime_t now = simTime();
simtime_t start = std::max(startTime, now);
if (timeoutMsg && ((stopTime < SIMTIME_ZERO) || (start < stopTime) || (start == stopTime && startTime == stopTime))) {
timeoutMsg->setKind(MSGKIND_CONNECT);
scheduleAt(start, timeoutMsg);
}
}
}
else if (dynamic_cast<NodeShutdownOperation *>(operation)) {
if (static_cast<NodeShutdownOperation::Stage>(stage) == NodeShutdownOperation::STAGE_APPLICATION_LAYER) {
cancelEvent(timeoutMsg);
if (socket.getState() == TcpSocket::CONNECTED || socket.getState() == TcpSocket::CONNECTING || socket.getState() == TcpSocket::PEER_CLOSED)
close();
// TODO: wait until socket is closed
}
}
else if (dynamic_cast<NodeCrashOperation *>(operation)) {
if (static_cast<NodeCrashOperation::Stage>(stage) == NodeCrashOperation::STAGE_CRASH)
cancelEvent(timeoutMsg);
}
else
throw cRuntimeError("Unsupported lifecycle operation '%s'", operation->getClassName());
return true;
}
void TcpBasicClientApp::sendRequest()
{
long requestLength = par("requestLength");
long replyLength = par("replyLength");
if (requestLength < 1)
requestLength = 1;
if (replyLength < 1)
replyLength = 1;
const auto& payload = makeShared<GenericAppMsg>();
Packet *packet = new Packet("data");
payload->setChunkLength(B(requestLength));
payload->setExpectedReplyLength(B(replyLength));
payload->setServerClose(false);
packet->insertAtBack(payload);
EV_INFO << "sending request with " << requestLength << " bytes, expected reply length " << replyLength << " bytes,"
<< "remaining " << numRequestsToSend - 1 << " request\n";
sendPacket(packet);
}
void TcpBasicClientApp::handleTimer(cMessage *msg)
{
switch (msg->getKind()) {
case MSGKIND_CONNECT:
connect(); // active OPEN
// significance of earlySend: if true, data will be sent already
// in the ACK of SYN, otherwise only in a separate packet (but still
// immediately)
if (earlySend)
sendRequest();
break;
case MSGKIND_SEND:
sendRequest();
numRequestsToSend--;
// no scheduleAt(): next request will be sent when reply to this one
// arrives (see socketDataArrived())
break;
default:
throw cRuntimeError("Invalid timer msg: kind=%d", msg->getKind());
}
}
void TcpBasicClientApp::socketEstablished(TcpSocket *socket)
{
TcpAppBase::socketEstablished(socket);
// determine number of requests in this session
numRequestsToSend = par("numRequestsPerSession");
if (numRequestsToSend < 1)
numRequestsToSend = 1;
// perform first request if not already done (next one will be sent when reply arrives)
if (!earlySend)
sendRequest();
numRequestsToSend--;
}
void TcpBasicClientApp::rescheduleOrDeleteTimer(simtime_t d, short int msgKind)
{
cancelEvent(timeoutMsg);
if (stopTime < SIMTIME_ZERO || d < stopTime) {
timeoutMsg->setKind(msgKind);
scheduleAt(d, timeoutMsg);
}
else {
delete timeoutMsg;
timeoutMsg = nullptr;
}
}
void TcpBasicClientApp::socketDataArrived(TcpSocket *socket, Packet *msg, bool urgent)
{
TcpAppBase::socketDataArrived(socket, msg, urgent);
if (numRequestsToSend > 0) {
EV_INFO << "reply arrived\n";
if (timeoutMsg) {
simtime_t d = simTime() + par("thinkTime");
rescheduleOrDeleteTimer(d, MSGKIND_SEND);
}
}
else if (socket->getState() != TcpSocket::LOCALLY_CLOSED) {
EV_INFO << "reply to last request arrived, closing session\n";
close();
}
}
void TcpBasicClientApp::socketClosed(TcpSocket *socket)
{
TcpAppBase::socketClosed(socket);
// start another session after a delay
if (timeoutMsg) {
simtime_t d = simTime() + par("idleInterval");
rescheduleOrDeleteTimer(d, MSGKIND_CONNECT);
}
}
void TcpBasicClientApp::socketFailure(TcpSocket *socket, int code)
{
TcpAppBase::socketFailure(socket, code);
// reconnect after a delay
if (timeoutMsg) {
simtime_t d = simTime() + par("reconnectInterval");
rescheduleOrDeleteTimer(d, MSGKIND_CONNECT);
}
}
} // namespace inet