#include "pong.h"
int hdr_pong::offset_;
// PacketHeaderClass를 상속받아 PongHeaderClass를 선언
// 이미 많은 protocol header들이 PacketHeaderClass를 상속받아 정의되어 있다.
// 동일한 방법으로 PacketHeader 아래에 Pong header를 둔다.
// pong.h 에서 정의한 hdr_pong의 offset를 연결한다.
static class PongHeaderClass : public PacketHeaderClass {
public:
PongHeaderClass() : PacketHeaderClass("PacketHeader/Pong", sizeof(hdr_pong)) {
bind_offset(&hdr_pong::offset_);
}
} class_ponghdr;
// TclClass를 상속받아 PongClass를 선언
// Agent 하위에 Pong을 두기 위해 "Agent/Pong"을 지정
// 이 부분은 tcl 파일을 작성할 때 "set p0 [new Agent/Pong]"와 같이 사용됨
// PongAgent를 TclObject로 생성하여 반환
static class PongClass : public TclClass {
public:
PongClass() : TclClass("Agent/Pong") { }
TclObject* create(int, const char*const*) {
return (new PongAgent);
}
} class_pong;
// PongAgent의 생성자를 구체적으로 정의하는 부분
// 생성자에서는 C++과 Tcl을 바인드하도록 함.
PongAgent::PongAgent() : Agent(PT_PONG) {
bind("packetSize_", &size_);
}
// PongAgent의 command 메소드를 정의
// 궁극적으로 이 부분은 pong packet을 send하는 부분이다.
// Packet을 생성하고, pong header의 시작지점으로 이동하여,
// ret를 0으로 설정하고, 시간을 설정한 다음, Packet을 전송한다.
int PongAgent::command(int argc, const char*const* argv) {
if(argc == 2) {
if(strcmp(argv[1], "send") == 0) {
// 새로운 packet을 준비
// Creaqte a new packet
Packet* pkt = allocpkt();
// packet의 pong header 시작 지점으로 이동
// Access the Pong header for the new packet
hdr_pong* hdr = hdr_pong::access(pkt);
// pong header의 ret를 0으로 설정
// Set the 'ret' field to 0, so the receiving node
// knows that it to generate an echo packet
hdr->ret = 0;
// pong header의 send time을 현재의 시간으로 설정
// Store the current time in the 'send_time' field
hdr->send_time = Scheduler::instance().clock();
// 만들어진 packet을 전송
// Send the packet
send(pkt, 0);
// Return TCL_OK, so the calling function knows that
// the command has been procoessed
return (TCL_OK);
}
}
// If the command hasn't been proceesed by PongAgent()::command,
// call the command() function for the base class
return (Agent::command(argc, argv));
}
// PongAgent의 recv() 메소드를 정의
// Pong Packet을 수신하였을 때 수행하는 부분을 정의
void PongAgent::recv(Packet* pkt, Handler*) {
// ip header의 시작 지점으로 이동
// Access the IP header for the received packet
hdr_ip* hdrip = hdr_ip::access(pkt);
// pong header의 시작 지점으로 이동
// Access the pong header for the received packet
hdr_pong* hdr = hdr_pong::access(pkt);
// ret = 0 이면, 즉 처음 수신한 packet일 때 처리하는 부분
if(hdr->ret == 0) {
// packet에 있는 시간을 stime에 할당
double stime = hdr->send_time;
// packet을 폐기
Packet::free(pkt);
// 응답을 위한 packet을 생성
Packet* pktret = allocpkt();
// packet의 pong header 시작지점으로 이동
hdr_pong* hdrret = hdr_pong::access(pktret);
// packet의 ret를 1로 설정
hdrret->ret = 1;
// packet의 send_time에 packet을 수신한 시간을 설정
hdrret->send_time = stime;
// packet을 전송
send(pktret, 0);
} else { // ret = 1 이면, 즉 보낸 packet이 다시 되돌아왔을 때 처리하는 부분
// 출력을 위한 변수 out을 선언
char out[100];
// out 변수에 내용을 기록
// "이름(Agent/Pong) recv from(Source address) rtt(round-trip-time)"의 형태를 갖추어 기록
sprintf(out, "%s recv %d %3.1f",
// %s에 해당하는 부분(노드 이름)
name(),
// %d에 해당하는 부분(노드 주소)
hdrip->src_.addr_ >> Address::instance().NodeShift_[1],
// %3.1f에 해당하는 부분(응답시간)
// (현재시간 - send_time * 1000) --> round-trip-time
(Scheduler::instance().clock() - hdr->send_time) * 1000);
// tcl instance를 생성
Tcl& tcl =Tcl::instance();
// tcl instance로 out을 반환
tcl.eval(out);
// packet을 폐기
Packet::free(pkt);
}
}