📄 http.cc
字号:
// Copyright (c) Xerox Corporation 1998. All rights reserved.//// License is granted to copy, to use, and to make and to use derivative// works for research and evaluation purposes, provided that Xerox is// acknowledged in all documentation pertaining to any such copy or// derivative work. Xerox grants no other licenses expressed or// implied. The Xerox trade name should not be used in any advertising// without its written permission. //// XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE// MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE// FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without// express or implied warranty of any kind.//// These notices must be retained in any copies of any part of this// software. //// Implementation of the HTTP agent. We want a separate agent for HTTP because// we are interested in (detailed) HTTP headers, instead of just request and // response patterns.//// $Header: /nfs/jade/vint/CVSROOT/ns-2/webcache/http.cc,v 1.18 1999/08/24 04:16:23 haoboy Exp $#include <stdlib.h>#include <assert.h>#include <string.h>#include <stdarg.h>#include "tclcl.h"#include "agent.h"#include "app.h"#include "tcp-simple.h"#include "http.h"#include "http-aux.h"#include "trace.h"#include "tcpapp.h"#include "mcache.h"//----------------------------------------------------------------------// Http Application//// Allows multiple concurrent HTTP connections//----------------------------------------------------------------------static class HttpAppClass : public TclClass {public: HttpAppClass() : TclClass("Http") {} TclObject* create(int, const char*const*) { return (new HttpApp()); }} class_http_app;// What states should be in a http agent?HttpApp::HttpApp() : log_(0){ bind("id_", &id_); // Map a client address to a particular TCP agent tpa_ = new Tcl_HashTable; Tcl_InitHashTable(tpa_, TCL_ONE_WORD_KEYS);}HttpApp::~HttpApp(){ if (tpa_ != NULL) { Tcl_DeleteHashTable(tpa_); delete tpa_; }}int HttpApp::add_cnc(HttpApp* client, TcpApp *agt){ int newEntry = 1; Tcl_HashEntry *he = Tcl_CreateHashEntry(tpa_, (const char *)client->id(), &newEntry); if (he == NULL) return -1; if (newEntry) Tcl_SetHashValue(he, (ClientData)agt); return 0;}void HttpApp::delete_cnc(HttpApp* client){ Tcl_HashEntry *he = Tcl_FindHashEntry(tpa_,(const char *)client->id()); if (he != NULL) { TcpApp *cnc = (TcpApp *)Tcl_GetHashValue(he); Tcl_DeleteHashEntry(he); delete cnc; }}TcpApp* HttpApp::lookup_cnc(HttpApp* client){ Tcl_HashEntry *he = Tcl_FindHashEntry(tpa_, (const char *)client->id()); if (he == NULL) return NULL; return (TcpApp *)Tcl_GetHashValue(he);}// Basic functionalities: int HttpApp::command(int argc, const char*const* argv){ Tcl& tcl = Tcl::instance(); if (argc == 2) { if (strcmp(argv[1], "id") == 0) { if (argc == 3) { id_ = atoi(argv[2]); tcl.resultf("%d", id_); } else tcl.resultf("%d", id_); return TCL_OK; } else if (strcmp(argv[1], "log") == 0) { // Return the name of the log channel if (log_ != NULL) tcl.resultf("%s", Tcl_GetChannelName(log_)); else tcl.result(""); return TCL_OK; } } else if (argc == 3) { if (strcmp(argv[1], "get-modtime") == 0) { double mt; if (pool_->get_mtime(argv[2], mt) != -1) { tcl.resultf("%.17g", mt); return TCL_OK; } else return TCL_ERROR; } else if (strcmp(argv[1], "exist-page") == 0) { tcl.resultf("%d", pool_->exist_page(argv[2])); return TCL_OK; } else if (strcmp(argv[1], "get-size") == 0) { int size; if (pool_->get_size(argv[2], size) != -1) { tcl.resultf("%d", size); return TCL_OK; } else return TCL_ERROR; } else if (strcmp(argv[1], "get-age") == 0) { double age; if (pool_->get_age(argv[2], age) != -1) { tcl.resultf("%.17g", age); return TCL_OK; } else return TCL_ERROR; } else if (strcmp(argv[1], "get-cachetime") == 0) { double et; if (pool_->get_etime(argv[2], et) != -1) { tcl.resultf("%.17g", et); return TCL_OK; } else return TCL_ERROR; } else if (strcmp(argv[1], "get-page") == 0) { char buf[4096]; if (pool_->get_pageinfo(argv[2], buf) != -1) { tcl.resultf("%s", buf); return TCL_OK; } else return TCL_ERROR; } else if (strcmp(argv[1], "get-cnc") == 0) { /* * <http> get-cnc <client> * * Given the communication party, get the tcp agent * connected to it. */ HttpApp *client = (HttpApp *)TclObject::lookup(argv[2]); TcpApp *cnc = (TcpApp *)lookup_cnc(client); if (cnc == NULL) tcl.result(""); else tcl.resultf("%s", cnc->name()); return TCL_OK; } else if (strcmp(argv[1], "set-pagepool") == 0) { pool_ = (ClientPagePool*)TclObject::lookup(argv[2]); if (pool_ != NULL) return TCL_OK; else return TCL_ERROR; } else if (strcmp(argv[1], "is-connected") == 0) { /* * <http> is-connected <server> */ HttpApp *a = (HttpApp*)TclObject::lookup(argv[2]); TcpApp *cnc = (TcpApp*)lookup_cnc(a); if (cnc == NULL) tcl.result("0"); else tcl.result("1"); return TCL_OK; } else if (strcmp(argv[1], "is-valid") == 0) { ClientPage *pg = (ClientPage *)pool_->get_page(argv[2]); if (pg == NULL) { tcl.resultf("%d is-valid: No page %s", id_, argv[2]); return TCL_ERROR; } tcl.resultf("%d", pg->is_valid()); return TCL_OK; } else if (strcmp(argv[1], "log") == 0) { int mode; log_ = Tcl_GetChannel(tcl.interp(), (char*)argv[2], &mode); if (log_ == 0) { tcl.resultf("%d: invalid log file handle %s\n", id_, argv[2]); return TCL_ERROR; } return TCL_OK; } else if (strcmp(argv[1], "disconnect") == 0) { /* * <http> disconnect <client> * Delete the association of source and sink TCP. */ HttpApp *client = (HttpApp *)TclObject::lookup(argv[2]); delete_cnc(client); return TCL_OK; } else if (strcmp(argv[1], "get-pagetype") == 0) { /* * <http> get-pagetype <pageid> * return the page type */ ClientPage *pg = (ClientPage*)pool_->get_page(argv[2]); if (pg == NULL) { tcl.resultf("%d get-pagetype: No page %s", id_, argv[2]); return TCL_ERROR; } switch (pg->type()) { case HTML: tcl.result("HTML"); break; case MEDIA: tcl.result("MEDIA"); break; default: fprintf(stderr, "Unknown page type %d", pg->type()); return TCL_ERROR; } return TCL_OK; } else if (strcmp(argv[1], "get-layer") == 0) { // Assume the page is a MediaPage MediaPage *pg = (MediaPage *)pool_->get_page(argv[2]); if (pg == NULL) { tcl.resultf("%d get-layer: No page %s", id_, argv[2]); return TCL_ERROR; } if (pg->type() != MEDIA) { tcl.resultf("%d get-layer %s not a media page", id_, argv[2]); return TCL_ERROR; } tcl.resultf("%d", pg->num_layer()); return TCL_OK; } } else if (argc == 4) { if (strcmp(argv[1], "connect") == 0) { /* * <http> connect <client> <ts> * * Associate a TCP agent with the given client. * <ts> is the agent used to send packets out. * We assume two-way TCP connection, therefore we * only need one agent. */ HttpApp *client = (HttpApp *)TclObject::lookup(argv[2]); TcpApp *cnc = (TcpApp *)TclObject::lookup(argv[3]); if (add_cnc(client, cnc)) { tcl.resultf("%s: failed to connect to %s", name_, argv[2]); return TCL_ERROR; } // Set data delivery target cnc->target() = (Process*)this; return TCL_OK; } else if (strcmp(argv[1], "set-modtime") == 0) { double mt = strtod(argv[3], NULL); if (pool_->set_mtime(argv[2], mt) != -1) return TCL_OK; else return TCL_ERROR; } else if (strcmp(argv[1], "set-cachetime") == 0) { double et = Scheduler::instance().clock(); if (pool_->set_etime(argv[2], et) != -1) return TCL_OK; else return TCL_ERROR; } } else { if (strcmp(argv[1], "send") == 0) { /* * <http> send <client> <bytes> <callback> */ HttpApp *client = (HttpApp *)TclObject::lookup(argv[2]); if (client == NULL) { tcl.add_errorf("%s: bad client name %s", name_, argv[2]); return TCL_ERROR; } int bytes = atoi(argv[3]); TcpApp *cnc = (TcpApp *)lookup_cnc(client); if (cnc == NULL) { //tcl.resultf("%s: no connection to client %s", // name_, argv[2]); // Tolerate it return TCL_OK; } char *buf = strdup(argv[4]); HttpNormalData *d = new HttpNormalData(id_, bytes, buf); cnc->send(bytes, d); // delete d; free(buf); return TCL_OK; } else if (strcmp(argv[1], "enter-page") == 0) { ClientPage* pg = pool_->enter_page(argc, argv); if (pg == NULL) return TCL_ERROR; else return TCL_OK; } else if (strcmp(argv[1], "evTrace") == 0) { char buf[1024], *p; if (log_ != 0) { sprintf(buf, TIME_FORMAT" i %d ", Trace::round(Scheduler::instance().clock()), id_); p = &(buf[strlen(buf)]); for (int i = 2; i < argc; i++) { strcpy(p, argv[i]); p += strlen(argv[i]); *(p++) = ' '; } // Stick in a newline. *(p++) = '\n', *p = 0; Tcl_Write(log_, buf, p-buf); } return TCL_OK; } } return TclObject::command(argc, argv);}void HttpApp::log(const char* fmt, ...){ // Don't do anything if we don't have a log file. if (log_ == 0) return; char buf[10240], *p; sprintf(buf, TIME_FORMAT" i %d ", Trace::round(Scheduler::instance().clock()), id_); p = &(buf[strlen(buf)]); va_list ap; va_start(ap, fmt); vsprintf(p, fmt, ap); Tcl_Write(log_, buf, strlen(buf));}void HttpApp::process_data(int, AppData* data){ if (data == NULL) return; switch (data->type()) { case HTTP_NORMAL: { HttpNormalData *tmp = (HttpNormalData*)data; Tcl::instance().eval(tmp->str()); break; } default: fprintf(stderr, "Bad http invalidation data type %d\n", data->type()); abort(); break; }}//----------------------------------------------------------------------// Clients//----------------------------------------------------------------------static class HttpClientClass : public TclClass {public: HttpClientClass() : TclClass("Http/Client") {} TclObject* create(int, const char*const*) { return (new HttpClient()); }} class_httpclient_app;//----------------------------------------------------------------------// Servers//----------------------------------------------------------------------static class HttpServerClass : public TclClass {public: HttpServerClass() : TclClass("Http/Server") {} TclObject* create(int, const char*const*) { return (new HttpServer()); }} class_httpserver_app;static class HttpInvalServerClass : public TclClass {public: HttpInvalServerClass() : TclClass("Http/Server/Inval") {} TclObject* create(int, const char*const*) { return (new HttpInvalServer()); }} class_httpinvalserver_app;static class HttpYucInvalServerClass : public TclClass {public: HttpYucInvalServerClass() : TclClass("Http/Server/Inval/Yuc") {} TclObject* create(int, const char*const*) { return (new HttpYucInvalServer()); }} class_httpyucinvalserver_app;HttpYucInvalServer::HttpYucInvalServer() : inv_sender_(0), invlist_(0), num_inv_(0){ bind("hb_interval_", &hb_interval_); bind("enable_upd_", &enable_upd_); bind("Ca_", &Ca_); bind("Cb_", &Cb_); bind("push_thresh_", &push_thresh_); bind("push_high_bound_", &push_high_bound_); bind("push_low_bound_", &push_low_bound_);}int HttpYucInvalServer::command(int argc, const char*const* argv){ Tcl& tcl = Tcl::instance(); switch (argv[1][0]) { case 'a': if (strcmp(argv[1], "add-inval-sender") == 0) { HttpUInvalAgent *tmp = (HttpUInvalAgent *)TclObject::lookup(argv[2]); if (tmp == NULL) { tcl.resultf("Non-existent agent %s", argv[2]); return TCL_ERROR; } inv_sender_ = tmp; return TCL_OK; } if (strcmp(argv[1], "add-inv") == 0) { /* * <server> add-inv <pageid> <modtime> */ double mtime = strtod(argv[3], NULL); add_inv(argv[2], mtime); return TCL_OK; } break; case 'c': if (strcmp(argv[1], "count-request") == 0) { ClientPage *pg = (ClientPage *)pool_->get_page(argv[2]); if (pg == NULL) { tcl.resultf("%d count-request: No page %s", id_, argv[2]); return TCL_ERROR; } pg->count_request(Cb_, push_high_bound_); log("S NTF p %s v %d\n", argv[2], pg->counter()); return TCL_OK; } else if (strcmp(argv[1], "count-inval") == 0) { ClientPage *pg = (ClientPage *)pool_->get_page(argv[2]); if (pg == NULL) { tcl.resultf("%d count-inval: No page %s", id_, argv[2]); return TCL_ERROR; } pg->count_inval(Ca_, push_low_bound_); log("S NTF p %s v %d\n", argv[2], pg->counter()); return TCL_OK; } break; case 'i': if (strcmp(argv[1], "is-pushable") == 0) { ClientPage *pg = (ClientPage *)pool_->get_page(argv[2]); if (pg == NULL) { tcl.resultf("%d is-pushable: No page %s", id_, argv[2]); return TCL_ERROR; } if (pg->is_mpush() && (Scheduler::instance().clock() - pg->mpush_time() > HTTP_HBEXPIRE_COUNT*hb_interval_)) { // If mandatory push timer expires, stop push pg->clear_mpush(); fprintf(stderr, "server %d timeout mpush\n", id_);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -