tcpapp.cc

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) Xerox Corporation 1998. All rights reserved.
00003  *
00004  * This program is free software; you can redistribute it and/or modify it
00005  * under the terms of the GNU General Public License as published by the
00006  * Free Software Foundation; either version 2 of the License, or (at your
00007  * option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License along
00015  * with this program; if not, write to the Free Software Foundation, Inc.,
00016  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00017  *
00018  * Linking this file statically or dynamically with other modules is making
00019  * a combined work based on this file.  Thus, the terms and conditions of
00020  * the GNU General Public License cover the whole combination.
00021  *
00022  * In addition, as a special exception, the copyright holders of this file
00023  * give you permission to combine this file with free software programs or
00024  * libraries that are released under the GNU LGPL and with code included in
00025  * the standard release of ns-2 under the Apache 2.0 license or under
00026  * otherwise-compatible licenses with advertising requirements (or modified
00027  * versions of such code, with unchanged license).  You may copy and
00028  * distribute such a system following the terms of the GNU GPL for this
00029  * file and the licenses of the other code concerned, provided that you
00030  * include the source code of that other code when and as the GNU GPL
00031  * requires distribution of source code.
00032  *
00033  * Note that people who make modified versions of this file are not
00034  * obligated to grant this special exception for their modified versions;
00035  * it is their choice whether to do so.  The GNU General Public License
00036  * gives permission to release a modified version without this exception;
00037  * this exception also makes it possible to release a modified version
00038  * which carries forward this exception.
00039  *
00040  *  $Header: /nfs/jade/vint/CVSROOT/ns-2/webcache/tcpapp.cc,v 1.16 2005/08/26 05:05:32 tomh Exp $
00041  *
00042  */
00043 
00044 //
00045 // Tcp application: transmitting real application data
00046 // 
00047 // Allows only one connection. Model underlying TCP connection as a 
00048 // FIFO byte stream, use this to deliver user data
00049 
00050 #include "agent.h"
00051 #include "app.h"
00052 #include "tcpapp.h"
00053 
00054 
00055 // Buffer management stuff.
00056 
00057 CBuf::CBuf(AppData *c, int nbytes)
00058 {
00059     nbytes_ = nbytes;
00060     size_ = c->size();
00061     if (size_ > 0) 
00062         data_ = c;
00063     else 
00064         data_ = NULL;
00065     next_ = NULL;
00066 }
00067 
00068 CBufList::~CBufList() 
00069 {
00070     while (head_ != NULL) {
00071         tail_ = head_;
00072         head_ = head_->next_;
00073         delete tail_;
00074     }
00075 }
00076 
00077 void CBufList::insert(CBuf *cbuf) 
00078 {
00079     if (tail_ == NULL) 
00080         head_ = tail_ = cbuf;
00081     else {
00082         tail_->next_ = cbuf;
00083         tail_ = cbuf;
00084     }
00085 #ifdef TCPAPP_DEBUG
00086     num_++;
00087 #endif
00088 }
00089 
00090 CBuf* CBufList::detach()
00091 {
00092     if (head_ == NULL)
00093         return NULL;
00094     CBuf *p = head_;
00095     if ((head_ = head_->next_) == NULL)
00096         tail_ = NULL;
00097 #ifdef TCPAPP_DEBUG
00098     num_--;
00099 #endif
00100     return p;
00101 }
00102 
00103 
00104 // ADU for plain TcpApp, which is by default a string of otcl script
00105 // XXX Local to this file
00106 class TcpAppString : public AppData {
00107 private:
00108     int size_;
00109     char* str_; 
00110 public:
00111     TcpAppString() : AppData(TCPAPP_STRING), size_(0), str_(NULL) {}
00112     TcpAppString(TcpAppString& d) : AppData(d) {
00113         size_ = d.size_;
00114         if (size_ > 0) {
00115             str_ = new char[size_];
00116             strcpy(str_, d.str_);
00117         } else
00118             str_ = NULL;
00119     }
00120     virtual ~TcpAppString() { 
00121         if (str_ != NULL) 
00122             delete []str_; 
00123     }
00124 
00125     char* str() { return str_; }
00126     virtual int size() const { return AppData::size() + size_; }
00127 
00128     // Insert string-contents into the ADU
00129     void set_string(const char* s) {
00130         if ((s == NULL) || (*s == 0)) 
00131             str_ = NULL, size_ = 0;
00132         else {
00133             size_ = strlen(s) + 1;
00134             str_ = new char[size_];
00135             assert(str_ != NULL);
00136             strcpy(str_, s);
00137         }
00138     }
00139     virtual AppData* copy() {
00140         return new TcpAppString(*this);
00141     }
00142 };
00143 
00144 // TcpApp
00145 static class TcpCncClass : public TclClass {
00146 public:
00147     TcpCncClass() : TclClass("Application/TcpApp") {}
00148     TclObject* create(int argc, const char*const* argv) {
00149         if (argc != 5)
00150             return NULL;
00151         Agent *tcp = (Agent *)TclObject::lookup(argv[4]);
00152         if (tcp == NULL) 
00153             return NULL;
00154         return (new TcpApp(tcp));
00155     }
00156 } class_tcpcnc_app;
00157 
00158 TcpApp::TcpApp(Agent *tcp) : 
00159     Application(), curdata_(0), curbytes_(0)
00160 {
00161     agent_ = tcp;
00162     agent_->attachApp(this);
00163 }
00164 
00165 TcpApp::~TcpApp()
00166 {
00167     // XXX Before we quit, let our agent know what we no longer exist
00168     // so that it won't give us a call later...
00169     agent_->attachApp(NULL);
00170 }
00171 
00172 // Send with callbacks to transfer application data
00173 void TcpApp::send(int nbytes, AppData *cbk)
00174 {
00175     CBuf *p = new CBuf(cbk, nbytes);
00176 #ifdef TCPAPP_DEBUG
00177     p->time() = Scheduler::instance().clock();
00178 #endif
00179     cbuf_.insert(p);
00180     Application::send(nbytes);
00181 }
00182 
00183 // All we need to know is that our sink has received one message
00184 void TcpApp::recv(int size)
00185 {
00186     // If it's the start of a new transmission, grab info from dest, 
00187     // and execute callback
00188     if (curdata_ == 0)
00189         curdata_ = dst_->rcvr_retrieve_data();
00190     if (curdata_ == 0) {
00191         fprintf(stderr, "[%g] %s receives a packet but no callback!\n",
00192             Scheduler::instance().clock(), name_);
00193         return;
00194     }
00195     curbytes_ += size;
00196 #ifdef TCPAPP_DEBUG
00197     fprintf(stderr, "[%g] %s gets data size %d, %s\n", 
00198         Scheduler::instance().clock(), name(), curbytes_, 
00199         curdata_->data());
00200 #endif
00201     if (curbytes_ == curdata_->bytes()) {
00202         // We've got exactly the data we want
00203         // If we've received all data, execute the callback
00204         process_data(curdata_->size(), curdata_->data());
00205         // Then cleanup this data transmission
00206         delete curdata_;
00207         curdata_ = NULL;
00208         curbytes_ = 0;
00209     } else if (curbytes_ > curdata_->bytes()) {
00210         // We've got more than we expected. Must contain other data.
00211         // Continue process callbacks until the unfinished callback
00212         while (curbytes_ >= curdata_->bytes()) {
00213             process_data(curdata_->size(), curdata_->data());
00214             curbytes_ -= curdata_->bytes();
00215 #ifdef TCPAPP_DEBUG
00216             fprintf(stderr, 
00217                 "[%g] %s gets data size %d(left %d)\n", 
00218                 Scheduler::instance().clock(), 
00219                 name(),
00220                 curdata_->bytes(), curbytes_);
00221                 //curdata_->data());
00222 #endif
00223             delete curdata_;
00224             curdata_ = dst_->rcvr_retrieve_data();
00225             if (curdata_ != 0)
00226                 continue;
00227             if ((curdata_ == 0) && (curbytes_ > 0)) {
00228                 fprintf(stderr, "[%g] %s gets extra data!\n",
00229                     Scheduler::instance().clock(), name_);
00230                 Tcl::instance().eval("[Simulator instance] flush-trace");
00231                 abort();
00232             } else
00233                 // Get out of the look without doing a check
00234                 break;
00235         }
00236     }
00237 }
00238 
00239 void TcpApp::resume()
00240 {
00241     // Do nothing
00242 }
00243 
00244 int TcpApp::command(int argc, const char*const* argv)
00245 {
00246     Tcl& tcl = Tcl::instance();
00247 
00248     if (strcmp(argv[1], "connect") == 0) {
00249         dst_ = (TcpApp *)TclObject::lookup(argv[2]);
00250         if (dst_ == NULL) {
00251             tcl.resultf("%s: connected to null object.", name_);
00252             return (TCL_ERROR);
00253         }
00254         dst_->connect(this);
00255         return (TCL_OK);
00256     } else if (strcmp(argv[1], "send") == 0) {
00257         /*
00258          * <app> send <size> <tcl_script>
00259          */
00260         int size = atoi(argv[2]);
00261         if (argc == 3)
00262             send(size, NULL);
00263         else {
00264             TcpAppString *tmp = new TcpAppString();
00265             tmp->set_string(argv[3]);
00266             send(size, tmp);
00267         }
00268         return (TCL_OK);
00269     } else if (strcmp(argv[1], "dst") == 0) {
00270         tcl.resultf("%s", dst_->name());
00271         return TCL_OK;
00272     }
00273     return Application::command(argc, argv);
00274 }
00275 
00276 void TcpApp::process_data(int size, AppData* data) 
00277 {
00278     if (data == NULL)
00279         return;
00280     // XXX Default behavior:
00281     // If there isn't a target, use tcl to evaluate the data
00282     if (target())
00283         send_data(size, data);
00284     else if (data->type() == TCPAPP_STRING) {
00285         TcpAppString *tmp = (TcpAppString*)data;
00286         Tcl::instance().eval(tmp->str());
00287     }
00288 }

Generated on Tue Mar 6 16:47:52 2007 for ns2 Network Simulator 2.29 by  doxygen 1.4.6