Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Compound Members | File Members

tcpapp.cc

Go to the documentation of this file.
00001 // Copyright (c) Xerox Corporation 1998. All rights reserved.
00002 //
00003 // License is granted to copy, to use, and to make and to use derivative
00004 // works for research and evaluation purposes, provided that Xerox is
00005 // acknowledged in all documentation pertaining to any such copy or
00006 // derivative work. Xerox grants no other licenses expressed or
00007 // implied. The Xerox trade name should not be used in any advertising
00008 // without its written permission. 
00009 //
00010 // XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE
00011 // MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE
00012 // FOR ANY PARTICULAR PURPOSE.  The software is provided "as is" without
00013 // express or implied warranty of any kind.
00014 //
00015 // These notices must be retained in any copies of any part of this
00016 // software. 
00017 //
00018 // $Header: /nfs/jade/vint/CVSROOT/ns-2/webcache/tcpapp.cc,v 1.15 2000/11/06 21:41:01 haoboy Exp $
00019 //
00020 // Tcp application: transmitting real application data
00021 // 
00022 // Allows only one connection. Model underlying TCP connection as a 
00023 // FIFO byte stream, use this to deliver user data
00024 
00025 #include "agent.h"
00026 #include "app.h"
00027 #include "tcpapp.h"
00028 
00029 
00030 // Buffer management stuff.
00031 
00032 CBuf::CBuf(AppData *c, int nbytes)
00033 {
00034         nbytes_ = nbytes;
00035         size_ = c->size();
00036         if (size_ > 0) 
00037                 data_ = c;
00038         else 
00039                 data_ = NULL;
00040         next_ = NULL;
00041 }
00042 
00043 CBufList::~CBufList() 
00044 {
00045         while (head_ != NULL) {
00046                 tail_ = head_;
00047                 head_ = head_->next_;
00048                 delete tail_;
00049         }
00050 }
00051 
00052 void CBufList::insert(CBuf *cbuf) 
00053 {
00054         if (tail_ == NULL) 
00055                 head_ = tail_ = cbuf;
00056         else {
00057                 tail_->next_ = cbuf;
00058                 tail_ = cbuf;
00059         }
00060 #ifdef TCPAPP_DEBUG
00061         num_++;
00062 #endif
00063 }
00064 
00065 CBuf* CBufList::detach()
00066 {
00067         if (head_ == NULL)
00068                 return NULL;
00069         CBuf *p = head_;
00070         if ((head_ = head_->next_) == NULL)
00071                 tail_ = NULL;
00072 #ifdef TCPAPP_DEBUG
00073         num_--;
00074 #endif
00075         return p;
00076 }
00077 
00078 
00079 // ADU for plain TcpApp, which is by default a string of otcl script
00080 // XXX Local to this file
00081 class TcpAppString : public AppData {
00082 private:
00083         int size_;
00084         char* str_; 
00085 public:
00086         TcpAppString() : AppData(TCPAPP_STRING), size_(0), str_(NULL) {}
00087         TcpAppString(TcpAppString& d) : AppData(d) {
00088                 size_ = d.size_;
00089                 if (size_ > 0) {
00090                         str_ = new char[size_];
00091                         strcpy(str_, d.str_);
00092                 } else
00093                         str_ = NULL;
00094         }
00095         virtual ~TcpAppString() { 
00096                 if (str_ != NULL) 
00097                         delete []str_; 
00098         }
00099 
00100         char* str() { return str_; }
00101         virtual int size() const { return AppData::size() + size_; }
00102 
00103         // Insert string-contents into the ADU
00104         void set_string(const char* s) {
00105                 if ((s == NULL) || (*s == 0)) 
00106                         str_ = NULL, size_ = 0;
00107                 else {
00108                         size_ = strlen(s) + 1;
00109                         str_ = new char[size_];
00110                         assert(str_ != NULL);
00111                         strcpy(str_, s);
00112                 }
00113         }
00114         virtual AppData* copy() {
00115                 return new TcpAppString(*this);
00116         }
00117 };
00118 
00119 // TcpApp
00120 static class TcpCncClass : public TclClass {
00121 public:
00122         TcpCncClass() : TclClass("Application/TcpApp") {}
00123         TclObject* create(int argc, const char*const* argv) {
00124                 if (argc != 5)
00125                         return NULL;
00126                 Agent *tcp = (Agent *)TclObject::lookup(argv[4]);
00127                 if (tcp == NULL) 
00128                         return NULL;
00129                 return (new TcpApp(tcp));
00130         }
00131 } class_tcpcnc_app;
00132 
00133 TcpApp::TcpApp(Agent *tcp) : 
00134         Application(), curdata_(0), curbytes_(0)
00135 {
00136         agent_ = tcp;
00137         agent_->attachApp(this);
00138 }
00139 
00140 TcpApp::~TcpApp()
00141 {
00142         // XXX Before we quit, let our agent know what we no longer exist
00143         // so that it won't give us a call later...
00144         agent_->attachApp(NULL);
00145 }
00146 
00147 // Send with callbacks to transfer application data
00148 void TcpApp::send(int nbytes, AppData *cbk)
00149 {
00150         CBuf *p = new CBuf(cbk, nbytes);
00151 #ifdef TCPAPP_DEBUG
00152         p->time() = Scheduler::instance().clock();
00153 #endif
00154         cbuf_.insert(p);
00155         Application::send(nbytes);
00156 }
00157 
00158 // All we need to know is that our sink has received one message
00159 void TcpApp::recv(int size)
00160 {
00161         // If it's the start of a new transmission, grab info from dest, 
00162         // and execute callback
00163         if (curdata_ == 0)
00164                 curdata_ = dst_->rcvr_retrieve_data();
00165         if (curdata_ == 0) {
00166                 fprintf(stderr, "[%g] %s receives a packet but no callback!\n",
00167                         Scheduler::instance().clock(), name_);
00168                 return;
00169         }
00170         curbytes_ += size;
00171 #ifdef TCPAPP_DEBUG
00172         fprintf(stderr, "[%g] %s gets data size %d, %s\n", 
00173                 Scheduler::instance().clock(), name(), curbytes_, 
00174                 curdata_->data());
00175 #endif
00176         if (curbytes_ == curdata_->bytes()) {
00177                 // We've got exactly the data we want
00178                 // If we've received all data, execute the callback
00179                 process_data(curdata_->size(), curdata_->data());
00180                 // Then cleanup this data transmission
00181                 delete curdata_;
00182                 curdata_ = NULL;
00183                 curbytes_ = 0;
00184         } else if (curbytes_ > curdata_->bytes()) {
00185                 // We've got more than we expected. Must contain other data.
00186                 // Continue process callbacks until the unfinished callback
00187                 while (curbytes_ >= curdata_->bytes()) {
00188                         process_data(curdata_->size(), curdata_->data());
00189                         curbytes_ -= curdata_->bytes();
00190 #ifdef TCPAPP_DEBUG
00191                         fprintf(stderr, 
00192                                 "[%g] %s gets data size %d(left %d)\n", 
00193                                 Scheduler::instance().clock(), 
00194                                 name(),
00195                                 curdata_->bytes(), curbytes_);
00196                                 //curdata_->data());
00197 #endif
00198                         delete curdata_;
00199                         curdata_ = dst_->rcvr_retrieve_data();
00200                         if (curdata_ != 0)
00201                                 continue;
00202                         if ((curdata_ == 0) && (curbytes_ > 0)) {
00203                                 fprintf(stderr, "[%g] %s gets extra data!\n",
00204                                         Scheduler::instance().clock(), name_);
00205                                 Tcl::instance().eval("[Simulator instance] flush-trace");
00206                                 abort();
00207                         } else
00208                                 // Get out of the look without doing a check
00209                                 break;
00210                 }
00211         }
00212 }
00213 
00214 void TcpApp::resume()
00215 {
00216         // Do nothing
00217 }
00218 
00219 int TcpApp::command(int argc, const char*const* argv)
00220 {
00221         Tcl& tcl = Tcl::instance();
00222 
00223         if (strcmp(argv[1], "connect") == 0) {
00224                 dst_ = (TcpApp *)TclObject::lookup(argv[2]);
00225                 if (dst_ == NULL) {
00226                         tcl.resultf("%s: connected to null object.", name_);
00227                         return (TCL_ERROR);
00228                 }
00229                 dst_->connect(this);
00230                 return (TCL_OK);
00231         } else if (strcmp(argv[1], "send") == 0) {
00232                 /*
00233                  * <app> send <size> <tcl_script>
00234                  */
00235                 int size = atoi(argv[2]);
00236                 if (argc == 3)
00237                         send(size, NULL);
00238                 else {
00239                         TcpAppString *tmp = new TcpAppString();
00240                         tmp->set_string(argv[3]);
00241                         send(size, tmp);
00242                 }
00243                 return (TCL_OK);
00244         } else if (strcmp(argv[1], "dst") == 0) {
00245                 tcl.resultf("%s", dst_->name());
00246                 return TCL_OK;
00247         }
00248         return Application::command(argc, argv);
00249 }
00250 
00251 void TcpApp::process_data(int size, AppData* data) 
00252 {
00253         if (data == NULL)
00254                 return;
00255         // XXX Default behavior:
00256         // If there isn't a target, use tcl to evaluate the data
00257         if (target())
00258                 send_data(size, data);
00259         else if (data->type() == TCPAPP_STRING) {
00260                 TcpAppString *tmp = (TcpAppString*)data;
00261                 Tcl::instance().eval(tmp->str());
00262         }
00263 }

Generated on Tue Apr 20 12:14:36 2004 for NS2.26SourcesOriginal by doxygen 1.3.3