tcpapp.cc
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:8k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /*
  2.  * Copyright (c) Xerox Corporation 1998. All rights reserved.
  3.  *
  4.  * This program is free software; you can redistribute it and/or modify it
  5.  * under the terms of the GNU General Public License as published by the
  6.  * Free Software Foundation; either version 2 of the License, or (at your
  7.  * option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful, but
  10.  * WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12.  * General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License along
  15.  * with this program; if not, write to the Free Software Foundation, Inc.,
  16.  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  17.  *
  18.  * Linking this file statically or dynamically with other modules is making
  19.  * a combined work based on this file.  Thus, the terms and conditions of
  20.  * the GNU General Public License cover the whole combination.
  21.  *
  22.  * In addition, as a special exception, the copyright holders of this file
  23.  * give you permission to combine this file with free software programs or
  24.  * libraries that are released under the GNU LGPL and with code included in
  25.  * the standard release of ns-2 under the Apache 2.0 license or under
  26.  * otherwise-compatible licenses with advertising requirements (or modified
  27.  * versions of such code, with unchanged license).  You may copy and
  28.  * distribute such a system following the terms of the GNU GPL for this
  29.  * file and the licenses of the other code concerned, provided that you
  30.  * include the source code of that other code when and as the GNU GPL
  31.  * requires distribution of source code.
  32.  *
  33.  * Note that people who make modified versions of this file are not
  34.  * obligated to grant this special exception for their modified versions;
  35.  * it is their choice whether to do so.  The GNU General Public License
  36.  * gives permission to release a modified version without this exception;
  37.  * this exception also makes it possible to release a modified version
  38.  * which carries forward this exception.
  39.  *
  40.  *  $Header: /cvsroot/nsnam/ns-2/webcache/tcpapp.cc,v 1.16 2005/08/26 05:05:32 tomh Exp $
  41.  *
  42.  */
  43. //
  44. // Tcp application: transmitting real application data
  45. // 
  46. // Allows only one connection. Model underlying TCP connection as a 
  47. // FIFO byte stream, use this to deliver user data
  48. #include "agent.h"
  49. #include "app.h"
  50. #include "tcpapp.h"
  51. // Buffer management stuff.
  52. CBuf::CBuf(AppData *c, int nbytes)
  53. {
  54. nbytes_ = nbytes;
  55. size_ = c->size();
  56.    if (size_ > 0) 
  57. data_ = c;
  58.    else 
  59.    data_ = NULL;
  60. next_ = NULL;
  61. }
  62. CBufList::~CBufList() 
  63. {
  64. while (head_ != NULL) {
  65. tail_ = head_;
  66. head_ = head_->next_;
  67. delete tail_;
  68. }
  69. }
  70. void CBufList::insert(CBuf *cbuf) 
  71. {
  72. if (tail_ == NULL) 
  73. head_ = tail_ = cbuf;
  74. else {
  75. tail_->next_ = cbuf;
  76. tail_ = cbuf;
  77. }
  78. #ifdef TCPAPP_DEBUG
  79. num_++;
  80. #endif
  81. }
  82. CBuf* CBufList::detach()
  83. {
  84. if (head_ == NULL)
  85. return NULL;
  86. CBuf *p = head_;
  87. if ((head_ = head_->next_) == NULL)
  88. tail_ = NULL;
  89. #ifdef TCPAPP_DEBUG
  90. num_--;
  91. #endif
  92. return p;
  93. }
  94. // ADU for plain TcpApp, which is by default a string of otcl script
  95. // XXX Local to this file
  96. class TcpAppString : public AppData {
  97. private:
  98. int size_;
  99. char* str_; 
  100. public:
  101. TcpAppString() : AppData(TCPAPP_STRING), size_(0), str_(NULL) {}
  102. TcpAppString(TcpAppString& d) : AppData(d) {
  103. size_ = d.size_;
  104. if (size_ > 0) {
  105. str_ = new char[size_];
  106. strcpy(str_, d.str_);
  107. } else
  108. str_ = NULL;
  109. }
  110. virtual ~TcpAppString() { 
  111. if (str_ != NULL) 
  112. delete []str_; 
  113. }
  114. char* str() { return str_; }
  115. virtual int size() const { return AppData::size() + size_; }
  116. // Insert string-contents into the ADU
  117. void set_string(const char* s) {
  118. if ((s == NULL) || (*s == 0)) 
  119. str_ = NULL, size_ = 0;
  120. else {
  121. size_ = strlen(s) + 1;
  122. str_ = new char[size_];
  123. assert(str_ != NULL);
  124. strcpy(str_, s);
  125. }
  126. }
  127. virtual AppData* copy() {
  128. return new TcpAppString(*this);
  129. }
  130. };
  131. // TcpApp
  132. static class TcpCncClass : public TclClass {
  133. public:
  134. TcpCncClass() : TclClass("Application/TcpApp") {}
  135. TclObject* create(int argc, const char*const* argv) {
  136. if (argc != 5)
  137. return NULL;
  138. Agent *tcp = (Agent *)TclObject::lookup(argv[4]);
  139. if (tcp == NULL) 
  140. return NULL;
  141. return (new TcpApp(tcp));
  142. }
  143. } class_tcpcnc_app;
  144. TcpApp::TcpApp(Agent *tcp) : 
  145. Application(), curdata_(0), curbytes_(0)
  146. {
  147. agent_ = tcp;
  148. agent_->attachApp(this);
  149. }
  150. TcpApp::~TcpApp()
  151. {
  152. // XXX Before we quit, let our agent know what we no longer exist
  153. // so that it won't give us a call later...
  154. agent_->attachApp(NULL);
  155. }
  156. // Send with callbacks to transfer application data
  157. void TcpApp::send(int nbytes, AppData *cbk)
  158. {
  159. CBuf *p = new CBuf(cbk, nbytes);
  160. #ifdef TCPAPP_DEBUG
  161. p->time() = Scheduler::instance().clock();
  162. #endif
  163. cbuf_.insert(p);
  164. Application::send(nbytes);
  165. }
  166. // All we need to know is that our sink has received one message
  167. void TcpApp::recv(int size)
  168. {
  169. // If it's the start of a new transmission, grab info from dest, 
  170. // and execute callback
  171. if (curdata_ == 0)
  172. curdata_ = dst_->rcvr_retrieve_data();
  173. if (curdata_ == 0) {
  174. fprintf(stderr, "[%g] %s receives a packet but no callback!n",
  175. Scheduler::instance().clock(), name_);
  176. return;
  177. }
  178. curbytes_ += size;
  179. #ifdef TCPAPP_DEBUG
  180. fprintf(stderr, "[%g] %s gets data size %d, %sn", 
  181. Scheduler::instance().clock(), name(), curbytes_, 
  182. curdata_->data());
  183. #endif
  184. if (curbytes_ == curdata_->bytes()) {
  185. // We've got exactly the data we want
  186. // If we've received all data, execute the callback
  187. process_data(curdata_->size(), curdata_->data());
  188. // Then cleanup this data transmission
  189. delete curdata_;
  190. curdata_ = NULL;
  191. curbytes_ = 0;
  192. } else if (curbytes_ > curdata_->bytes()) {
  193. // We've got more than we expected. Must contain other data.
  194. // Continue process callbacks until the unfinished callback
  195. while (curbytes_ >= curdata_->bytes()) {
  196. process_data(curdata_->size(), curdata_->data());
  197. curbytes_ -= curdata_->bytes();
  198. #ifdef TCPAPP_DEBUG
  199. fprintf(stderr, 
  200. "[%g] %s gets data size %d(left %d)n", 
  201. Scheduler::instance().clock(), 
  202. name(),
  203. curdata_->bytes(), curbytes_);
  204. //curdata_->data());
  205. #endif
  206. delete curdata_;
  207. curdata_ = dst_->rcvr_retrieve_data();
  208. if (curdata_ != 0)
  209. continue;
  210. if ((curdata_ == 0) && (curbytes_ > 0)) {
  211. fprintf(stderr, "[%g] %s gets extra data!n",
  212. Scheduler::instance().clock(), name_);
  213. Tcl::instance().eval("[Simulator instance] flush-trace");
  214. abort();
  215. } else
  216. // Get out of the look without doing a check
  217. break;
  218. }
  219. }
  220. }
  221. void TcpApp::resume()
  222. {
  223. // Do nothing
  224. }
  225. int TcpApp::command(int argc, const char*const* argv)
  226. {
  227. Tcl& tcl = Tcl::instance();
  228. if (strcmp(argv[1], "connect") == 0) {
  229. dst_ = (TcpApp *)TclObject::lookup(argv[2]);
  230. if (dst_ == NULL) {
  231. tcl.resultf("%s: connected to null object.", name_);
  232. return (TCL_ERROR);
  233. }
  234. dst_->connect(this);
  235. return (TCL_OK);
  236. } else if (strcmp(argv[1], "send") == 0) {
  237. /*
  238.  * <app> send <size> <tcl_script>
  239.  */
  240. int size = atoi(argv[2]);
  241. if (argc == 3)
  242. send(size, NULL);
  243. else {
  244. TcpAppString *tmp = new TcpAppString();
  245. tmp->set_string(argv[3]);
  246. send(size, tmp);
  247. }
  248. return (TCL_OK);
  249. } else if (strcmp(argv[1], "dst") == 0) {
  250. tcl.resultf("%s", dst_->name());
  251. return TCL_OK;
  252. }
  253. return Application::command(argc, argv);
  254. }
  255. void TcpApp::process_data(int size, AppData* data) 
  256. {
  257. if (data == NULL)
  258. return;
  259. // XXX Default behavior:
  260. // If there isn't a target, use tcl to evaluate the data
  261. if (target())
  262. send_data(size, data);
  263. else if (data->type() == TCPAPP_STRING) {
  264. TcpAppString *tmp = (TcpAppString*)data;
  265. Tcl::instance().eval(tmp->str());
  266. }
  267. }