TcpTestClient.cc 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. //
  2. // This library is free software, you can redistribute it
  3. // and/or modify
  4. // it under the terms of the GNU Lesser General Public License
  5. // as published by the Free Software Foundation;
  6. // either version 2 of the License, or any later version.
  7. // The library is distributed in the hope that it will be useful,
  8. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. // See the GNU Lesser General Public License for more details.
  11. //
  12. // Copyright 2004 Andras Varga
  13. //
  14. #include <vector>
  15. #include <string>
  16. #include "inet/common/INETDefs.h"
  17. #include "inet/transportlayer/contract/tcp/TCPSocket.h"
  18. namespace inet {
  19. /**
  20. * TCP client application for testing the TCP model.
  21. */
  22. class INET_API TcpTestClient : public cSimpleModule
  23. {
  24. protected:
  25. struct Command
  26. {
  27. simtime_t tSend;
  28. int numBytes;
  29. };
  30. typedef std::list<Command> Commands;
  31. Commands commands;
  32. enum { TEST_OPEN, TEST_SEND, TEST_CLOSE };
  33. int ctr;
  34. TCPSocket socket;
  35. // statistics
  36. int64_t rcvdBytes;
  37. int rcvdPackets;
  38. protected:
  39. void parseScript(const char *script);
  40. std::string makeMsgName();
  41. void handleSelfMessage(cMessage *msg);
  42. void scheduleNextSend();
  43. protected:
  44. virtual void initialize();
  45. virtual void handleMessage(cMessage *msg);
  46. virtual void finish();
  47. };
  48. Define_Module(TcpTestClient);
  49. void TcpTestClient::parseScript(const char *script)
  50. {
  51. const char *s = script;
  52. while (*s)
  53. {
  54. Command cmd;
  55. // parse time
  56. while (isspace(*s)) s++;
  57. if (!*s || *s==';') break;
  58. const char *s0 = s;
  59. cmd.tSend = strtod(s,&const_cast<char *&>(s));
  60. if (s==s0)
  61. throw cRuntimeError("syntax error in script: simulation time expected");
  62. // parse number of bytes
  63. while (isspace(*s)) s++;
  64. if (!isdigit(*s))
  65. throw cRuntimeError("syntax error in script: number of bytes expected");
  66. cmd.numBytes = atoi(s);
  67. while (isdigit(*s)) s++;
  68. // add command
  69. commands.push_back(cmd);
  70. // skip delimiter
  71. while (isspace(*s)) s++;
  72. if (!*s) break;
  73. if (*s!=';')
  74. throw cRuntimeError("syntax error in script: separator ';' missing");
  75. s++;
  76. while (isspace(*s)) s++;
  77. }
  78. }
  79. std::string TcpTestClient::makeMsgName()
  80. {
  81. char buf[40];
  82. sprintf(buf,"data-%d", ++ctr);
  83. return std::string(buf);
  84. }
  85. void TcpTestClient::initialize()
  86. {
  87. rcvdBytes = 0;
  88. rcvdPackets = 0;
  89. // parameters
  90. simtime_t tOpen = par("tOpen");
  91. Command cmd;
  92. cmd.tSend = par("tSend");
  93. cmd.numBytes = par("sendBytes");
  94. simtime_t tClose = par("tClose");
  95. const char *script = par("sendScript");
  96. if (cmd.numBytes > 0)
  97. commands.push_back(cmd);
  98. parseScript(script);
  99. if (cmd.numBytes > 0 && commands.size() > 1)
  100. throw cRuntimeError("cannot use both sendScript and tSend+sendBytes");
  101. socket.readDataTransferModePar(*this);
  102. socket.setOutputGate(gate("tcpOut"));
  103. ctr = 0;
  104. scheduleAt(tOpen, new cMessage("Open", TEST_OPEN));
  105. if (tClose > 0)
  106. scheduleAt(tClose, new cMessage("Close", TEST_CLOSE));
  107. }
  108. void TcpTestClient::handleMessage(cMessage *msg)
  109. {
  110. if (msg->isSelfMessage())
  111. {
  112. handleSelfMessage(msg);
  113. return;
  114. }
  115. //EV << fullPath() << ": received " << msg->name() << ", " << msg->byteLength() << " bytes\n";
  116. if (msg->getKind()==TCP_I_DATA || msg->getKind()==TCP_I_URGENT_DATA)
  117. {
  118. rcvdPackets++;
  119. rcvdBytes += PK(msg)->getByteLength();
  120. }
  121. socket.processMessage(msg);
  122. }
  123. void TcpTestClient::handleSelfMessage(cMessage *msg)
  124. {
  125. switch (msg->getKind())
  126. {
  127. case TEST_OPEN:
  128. {
  129. const char *localAddress = par("localAddress");
  130. int localPort = par("localPort");
  131. const char *connectAddress = par("connectAddress");
  132. int connectPort = par("connectPort");
  133. socket.bind(*localAddress ? L3Address(localAddress) : L3Address(), localPort);
  134. if (par("active").boolValue())
  135. socket.connect(L3Address(connectAddress), connectPort);
  136. else
  137. socket.listenOnce();
  138. scheduleNextSend();
  139. delete msg;
  140. break;
  141. }
  142. case TEST_SEND:
  143. socket.send(msg);
  144. scheduleNextSend();
  145. break;
  146. case TEST_CLOSE:
  147. socket.close();
  148. delete msg;
  149. break;
  150. default:
  151. throw cRuntimeError("Unknown self message!");
  152. break;
  153. }
  154. }
  155. void TcpTestClient::scheduleNextSend()
  156. {
  157. if (commands.empty())
  158. return;
  159. Command cmd = commands.front();
  160. commands.pop_front();
  161. cPacket *msg = new cPacket(makeMsgName().c_str(),TEST_SEND);
  162. msg->setByteLength(cmd.numBytes);
  163. scheduleAt(cmd.tSend, msg);
  164. }
  165. void TcpTestClient::finish()
  166. {
  167. EV << getFullPath() << ": received " << rcvdBytes << " bytes in " << rcvdPackets << " packets\n";
  168. }
  169. } // namespace inet