http-server.tcl
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:16k
源码类别:

通讯编程

开发平台:

Visual C++

  1. # Copyright (c) Xerox Corporation 1998. All rights reserved.
  2. #
  3. # This program is free software; you can redistribute it and/or modify it
  4. # under the terms of the GNU General Public License as published by the
  5. # Free Software Foundation; either version 2 of the License, or (at your
  6. # option) any later version.
  7. # This program is distributed in the hope that it will be useful, but
  8. # WITHOUT ANY WARRANTY; without even the implied warranty of
  9. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  10. # General Public License for more details.
  11. # You should have received a copy of the GNU General Public License along
  12. # with this program; if not, write to the Free Software Foundation, Inc.,
  13. # 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  14. # Linking this file statically or dynamically with other modules is making
  15. # a combined work based on this file.  Thus, the terms and conditions of
  16. # the GNU General Public License cover the whole combination.
  17. # In addition, as a special exception, the copyright holders of this file
  18. # give you permission to combine this file with free software programs or
  19. # libraries that are released under the GNU LGPL and with code included in
  20. # the standard release of ns-2 under the Apache 2.0 license or under
  21. # otherwise-compatible licenses with advertising requirements (or modified
  22. # versions of such code, with unchanged license).  You may copy and
  23. # distribute such a system following the terms of the GNU GPL for this
  24. # file and the licenses of the other code concerned, provided that you
  25. # include the source code of that other code when and as the GNU GPL
  26. # requires distribution of source code.
  27. # Note that people who make modified versions of this file are not
  28. # obligated to grant this special exception for their modified versions;
  29. # it is their choice whether to do so.  The GNU General Public License
  30. # gives permission to release a modified version without this exception;
  31. # this exception also makes it possible to release a modified version
  32. # which carries forward this exception.
  33. #
  34. # Implementation of an HTTP server
  35. #
  36. # $Header: /cvsroot/nsnam/ns-2/tcl/webcache/http-server.tcl,v 1.11 2005/08/26 05:05:30 tomh Exp $
  37. #
  38. # PagePool
  39. #
  40. # Generage a new page, including size, age, and flags. Do NOT generate 
  41. # modification time. That's the job of web servers.
  42. PagePool instproc gen-page { pageid thismod } {
  43. set size [$self gen-size $pageid]
  44. # If $thismod == -1, we set age to -1, which means this page
  45. # never changes
  46. if {$thismod >= 0} {
  47. set age [expr [$self gen-modtime $pageid $thismod] - $thismod]
  48. } else {
  49. set age -1
  50. }
  51. return "size $size age $age modtime $thismod"
  52. }
  53. #
  54. # Compound pagepool with a non-cacheable main page
  55. #
  56. Class PagePool/CompMath/noc -superclass PagePool/CompMath
  57. PagePool/CompMath/noc instproc gen-page { pageid thismod } {
  58. set res [eval $self next $pageid $thismod]
  59. if {$pageid == 0} {
  60. return "$res noc 1"
  61. } else {
  62. return $res
  63. }
  64. }
  65. #
  66. # web server codes
  67. #
  68. Http/Server instproc init args {
  69. eval $self next $args
  70. $self instvar node_ stat_
  71. $node_ color "HotPink"
  72. array set stat_ [list hit-num 0 mod-num 0 barrival 0]
  73. }
  74. Http/Server instproc set-page-generator { pagepool } {
  75. $self instvar pgtr_
  76. set pgtr_ $pagepool
  77. }
  78. Http/Server instproc gen-init-modtime { id } {
  79. $self instvar pgtr_ ns_
  80. if [info exists pgtr_] {
  81. return [$pgtr_ gen-init-modtime $id]
  82. } else {
  83. return [$ns_ now]
  84. }
  85. }
  86. # XXX 
  87. # This method to calculate staleness time isn't scalable!!! We have to have
  88. # a garbage collection method to release unused portion of modtimes_ and 
  89. # modseq_. That's not implemented yet because it requires the server to know
  90. # the oldest version held by all other clients.
  91. Http/Server instproc stale-time { pageid modtime } {
  92. $self instvar modseq_ modtimes_ ns_
  93. for {set i $modseq_($pageid)} {$i >= 0} {incr i -1} {
  94. if {$modtimes_($pageid:$i) <= $modtime} {
  95. break
  96. }
  97. }
  98. if {$i < 0} {
  99. error "Non-existent modtime $modtime for page $pageid"
  100. }
  101. set ii [expr $i + 1]
  102. set t1 [expr abs($modtimes_($pageid:$i) - $modtime)]
  103. set t2 [expr abs($modtimes_($pageid:$ii) - $modtime)]
  104. if {$t1 > $t2} {
  105. incr ii
  106. }
  107. return [expr [$ns_ now] - $modtimes_($pageid:$ii)]
  108. }
  109. Http/Server instproc modify-page { pageid } {
  110. # Set Last-Modified-Time to current time
  111. $self instvar ns_ id_ stat_ pgtr_
  112. incr stat_(mod-num)
  113. set id [lindex [split $pageid :] end]
  114. # Change modtime and lifetime only, do not change page size
  115. set modtime [$ns_ now]
  116. if [info exists pgtr_] {
  117. set pginfo [$pgtr_ gen-page $id $modtime]
  118. } else {
  119. set pginfo "size 2000 age 50 modtime $modtime"
  120. }
  121. array set data $pginfo
  122. set age $data(age)
  123. $self schedule-nextmod [expr [$ns_ now] + $age] $pageid
  124. eval $self enter-page $pageid $pginfo
  125. $ns_ trace-annotate "S $id_ INV $pageid"
  126. $self evTrace S MOD p $pageid m [$ns_ now] n [expr [$ns_ now] + $age]
  127. $self instvar modtimes_ modseq_
  128. incr modseq_($pageid)
  129. set modtimes_($pageid:$modseq_($pageid)) $modtime
  130. }
  131. Http/Server instproc schedule-nextmod { time pageid } {
  132. $self instvar ns_
  133. $ns_ at $time "$self modify-page $pageid"
  134. }
  135. Http/Server instproc gen-page { pageid } {
  136. set pginfo [$self gen-pageinfo $pageid]
  137. eval $self enter-page $pageid $pginfo
  138. return $pginfo
  139. }
  140. # XXX Assumes page doesn't exists before. 
  141. Http/Server instproc gen-pageinfo { pageid } {
  142. $self instvar ns_ pgtr_ 
  143. if [$self exist-page $pageid] {
  144. error "$self: shouldn't use gen-page for existing pages"
  145. }
  146. set id [lindex [split $pageid :] end]
  147. # XXX If a page never changes, set modtime to -1 here!!
  148. set modtime [$self gen-init-modtime $id]
  149. if [info exists pgtr_] {
  150. set pginfo [$pgtr_ gen-page $id $modtime]
  151. } else {
  152. set pginfo "size 2000 age 50 modtime $modtime"
  153. }
  154. array set data $pginfo
  155. set age $data(age)
  156. if {$modtime >= 0} {
  157. $self schedule-nextmod [expr [$ns_ now] + $age] $pageid
  158. }
  159. $self evTrace S MOD p $pageid m [$ns_ now] n [expr [$ns_ now] + $age]
  160. $self instvar modtimes_ modseq_
  161. set modseq_($pageid) 0
  162. set modtimes_($pageid:0) $modtime
  163. return [join $pginfo]
  164. }
  165. Http/Server instproc disconnect { client } {
  166. $self instvar ns_ clist_ node_
  167. set pos [lsearch $clist_ $client]
  168. if {$pos >= 0} {
  169. lreplace $clist_ $pos $pos
  170. } else { 
  171. error "Http/Server::disconnect: not connected to $server"
  172. }
  173. set tcp [[$self get-cnc $client] agent]
  174. $self cmd disconnect $client
  175. $tcp proc done {} "$ns_ detach-agent $node_ $tcp; delete $tcp"
  176. $tcp close
  177. #puts "server [$self id] disconnect"
  178. }
  179. Http/Server instproc alloc-connection { client fid } {
  180. Http instvar TRANSPORT_
  181. $self instvar ns_ clist_ node_ fid_
  182. lappend clist_ $client
  183. set snk [new Agent/TCP/$TRANSPORT_]
  184. $snk set fid_ $fid
  185. $ns_ attach-agent $node_ $snk
  186. $snk listen
  187. set wrapper [new Application/TcpApp $snk]
  188. $self cmd connect $client $wrapper
  189. return $wrapper
  190. }
  191. Http/Server instproc handle-request-GET { pageid args } {
  192. $self instvar ns_
  193. if [$self exist-page $pageid] {
  194. set pageinfo [$self get-page $pageid]
  195. } else {
  196. set pageinfo [$self gen-page $pageid]
  197. }
  198. lappend res [$self get-size $pageid]
  199. eval lappend res $pageinfo
  200. }
  201. Http/Server instproc handle-request-IMS { pageid args } {
  202. array set data $args
  203. set mt [$self get-modtime $pageid]
  204. if {$mt <= $data(modtime)} {
  205. # Send a not-modified since
  206. set size [$self get-invsize]
  207. # We don't need other information for a IMS of a 
  208. # valid page
  209. set pageinfo 
  210.   "size $size modtime $mt time [$self get-cachetime $pageid]"
  211. $self evTrace S SND p $pageid m $mt z $size t IMS-NM
  212. } else {
  213. # Page modified, send the new one
  214. set size [$self get-size $pageid]
  215. set pageinfo [$self get-page $pageid]
  216. $self evTrace S SND p $pageid m $mt z $size t IMS-M
  217. }
  218. lappend res $size
  219. eval lappend res $pageinfo
  220. return $res
  221. }
  222. Http/Server instproc get-request { client type pageid args } {
  223. $self instvar ns_ id_ stat_
  224. incr stat_(hit-num)
  225. array set data $args
  226. incr stat_(barrival) $data(size)
  227. unset data
  228. # XXX Here maybe we want to wait for a random time to model 
  229. # server response delay, it could be easily added in a derived class.
  230. set res [eval $self handle-request-$type $pageid $args]
  231. set size [lindex $res 0]
  232. set pageinfo [lrange $res 1 end]
  233. $self send $client $size 
  234. "$client get-response-$type $self $pageid $pageinfo"
  235. }
  236. Http/Server instproc set-parent-cache { cache } {
  237. # Dummy proc
  238. }
  239. #----------------------------------------------------------------------
  240. # Http server modifying pages in the way as described in Pei Cao et al's 
  241. # ICDCS'97 paper. Used to test the simulator
  242. #----------------------------------------------------------------------
  243. Class Http/Server/epa -superclass Http/Server
  244. Http/Server/epa instproc start-update { interval } {
  245. $self instvar pm_itv_ ns_
  246. set pm_itv_ $interval
  247. $ns_ at [expr [$ns_ now] + $pm_itv_] "$self modify-page"
  248. }
  249. # Schedule next page modification using another way
  250. Http/Server/epa instproc schedule-nextmod { time pageid } {
  251. $self instvar ns_ pm_itv_
  252. $ns_ at [expr [$ns_ now]+$pm_itv_] "$self modify-page $pageid"
  253. }
  254. # Change the page id to be modified. The pageid given in argument makes 
  255. # no sense at all.
  256. Http/Server/epa instproc modify-page args {
  257. $self instvar pgtr_
  258. set pageid $self:[$pgtr_ pick-pagemod]
  259. eval $self next $pageid
  260. }
  261. # Do not schedule modification during page generation.
  262. Http/Server/epa instproc gen-pageinfo { pageid } {
  263. $self instvar ns_ pgtr_ 
  264. if [$self exist-page $pageid] {
  265. error "$self: shouldn't use gen-page for existing pages"
  266. }
  267. set id [lindex [split $pageid :] end]
  268. set modtime [$self gen-init-modtime $id]
  269. if [info exists pgtr_] {
  270. set pginfo [$pgtr_ gen-page $id $modtime]
  271. } else {
  272. set pginfo "size 2000 age 50 modtime $modtime"
  273. }
  274. array set data $pginfo
  275. set age $data(age)
  276. $self instvar modtimes_ modseq_
  277. set modseq_($pageid) 0
  278. set modtimes_($pageid:0) $modtime
  279. return [join $pginfo]
  280. }
  281. #----------------------------------------------------------------------
  282. # Base Http invalidation server
  283. #----------------------------------------------------------------------
  284. Http/Server/Inval instproc modify-page { pageid } {
  285. $self next $pageid
  286. $self instvar ns_ id_
  287. $self invalidate $pageid [$ns_ now]
  288. }
  289. Http/Server/Inval instproc handle-request-REF { pageid args } {
  290. return [eval $self handle-request-GET $pageid $args]
  291. }
  292. #----------------------------------------------------------------------
  293. # Old unicast invalidation Http server. For compatibility
  294. # Server with single unicast invalidation
  295. #----------------------------------------------------------------------
  296. Class Http/Server/Inval/Ucast -superclass Http/Server/Inval
  297. # We need to maintain a list of all caches who have gotten a page from this
  298. # server.
  299. Http/Server/Inval/Ucast instproc get-request { client type pageid args } {
  300.         eval $self next $client $type $pageid $args
  301.         # XXX more efficient representation?
  302.         $self instvar cacheList_
  303.         if [info exists cacheList_($pageid)] {
  304.                 set pos [lsearch $cacheList_($pageid) $client]
  305.         } else {
  306.                 set pos -1
  307.         }
  308.         # If it's a new cache, put it there
  309.         # XXX we should eventually have a timer for each cache entry, so 
  310.         # we can get rid of old cache entries
  311.         if {$pos < 0 && [regexp "Cache" [$client info class]]} {
  312.                 lappend cacheList_($pageid) $client
  313.         }
  314. }
  315. Http/Server/Inval/Ucast instproc invalidate { pageid modtime } {
  316.         $self instvar cacheList_ 
  317.         if ![info exists cacheList_($pageid)] {
  318.                 return
  319.         }
  320.         foreach c $cacheList_($pageid) {
  321.                 # Send invalidation to every cache, assuming a connection 
  322.                 # exists between the server and the cache
  323.                 set size [$self get-invsize]
  324. # Mark invalidation packet as another fid
  325. set agent [[$self get-cnc $c] agent]
  326. set fid [$agent set fid_]
  327. $agent_ set fid_ [Http set PINV_FID_]
  328.                 $self send $c $size 
  329.                         "$c invalidate $pageid $modtime"
  330. $agent_ set fid_ $fid
  331.                 $self evTrace S INV p $pageid m $modtime z $size
  332.         }
  333. }
  334. #----------------------------------------------------------------------
  335. # (Y)et another (U)ni(C)ast invalidation server
  336. #
  337. # It has a single parent cache. Whenever a page is updated in this server
  338. # it informs the parent cache, which will in turn propagate the update
  339. # (or invalidation) to the whole cache hierarchy.
  340. #----------------------------------------------------------------------
  341. Http/Server/Inval/Yuc instproc set-tlc { tlc } {
  342. $self instvar tlc_
  343. set tlc_ $tlc
  344. }
  345. Http/Server/Inval/Yuc instproc get-tlc { tlc } {
  346. $self instvar tlc_
  347. return $tlc_
  348. }
  349. Http/Server/Inval/Yuc instproc next-hb {} {
  350. Http/Server/Inval/Yuc instvar hb_interval_ 
  351. return [expr $hb_interval_ * [uniform 0.9 1.1]]
  352. }
  353. # XXX Must do this when the caching hierachy is ready
  354. Http/Server/Inval/Yuc instproc set-parent-cache { cache } {
  355. $self instvar pcache_
  356. set pcache_ $cache
  357. # Send JOIN
  358. #puts "[$self id] joins cache [$pcache_ id]"
  359. $self send $pcache_ [$self get-joinsize] 
  360. "$pcache_ server-join $self $self"
  361. # Establish an invalidation connection using TCP
  362. Http instvar TRANSPORT_
  363. $self instvar ns_ node_
  364. set tcp [new Agent/TCP/$TRANSPORT_]
  365. $tcp set fid_ [Http set HB_FID_]
  366. $ns_ attach-agent $node_ $tcp
  367. set dst [$pcache_ setup-unicast-hb]
  368. set snk [$dst agent]
  369. $ns_ connect $tcp $snk
  370. #$tcp set dst_ [$snk set addr_] 
  371. $tcp set window_ 100
  372. set wrapper [new Application/TcpApp/HttpInval $tcp]
  373. $wrapper connect $dst
  374. $wrapper set-app $self
  375. $self add-inval-sender $wrapper
  376. # Start heartbeat after some time, otherwise TCP connection may 
  377. # not be well established...
  378. $self instvar ns_
  379. $ns_ at [expr [$ns_ now] + [$self next-hb]] "$self heartbeat"
  380. }
  381. Http/Server/Inval/Yuc instproc heartbeat {} {
  382. $self instvar pcache_ ns_
  383. $self cmd send-hb
  384. $ns_ at [expr [$ns_ now] + [$self next-hb]] 
  385. "$self heartbeat"
  386. }
  387. Http/Server/Inval/Yuc instproc get-request { cl type pageid args } {
  388. eval $self next $cl $type $pageid $args
  389. if {($type == "GET") || ($type == "REF")} {
  390. $self count-request $pageid
  391. }
  392. }
  393. Http/Server/Inval/Yuc instproc invalidate { pageid modtime } {
  394. $self instvar pcache_ id_ enable_upd_
  395. if ![info exists pcache_] {
  396. error "Server $id_ doesn't have a parent cache!"
  397. }
  398. # One more invalidation
  399. $self count-inval $pageid
  400. if [$self is-pushable $pageid] {
  401. $self push-page $pageid $modtime
  402. return
  403. }
  404. # Send invalidation to every cache, assuming a connection 
  405. # exists between the server and the cache
  406. # set size [$self get-invsize]
  407. # Mark invalidation packet as another fid
  408. # set agent [[$self get-cnc $pcache_] agent]
  409. # set fid [$agent set fid_]
  410. # $agent set fid_ [Http set PINV_FID_]
  411. # $self send $pcache_ $size "$pcache_ invalidate $pageid $modtime"
  412. # $agent set fid_ $fid
  413. $self cmd add-inv $pageid $modtime
  414. $self evTrace S INV p $pageid m $modtime 
  415. }
  416. Http/Server/Inval/Yuc instproc push-page { pageid modtime } {
  417. $self instvar pcache_ id_
  418. if ![info exists pcache_] {
  419. error "Server $id_ doesn't have a parent cache!"
  420. }
  421. # Do not send invalidation, instead send the new page to 
  422. # parent cache
  423. set size [$self get-size $pageid]
  424. set pageinfo [$self get-page $pageid]
  425. # Mark invalidation packet as another fid
  426. set agent [[$self get-cnc $pcache_] agent]
  427. set fid [$agent set fid_]
  428. $agent set fid_ [Http set PINV_FID_]
  429. $self send $pcache_ $size 
  430. "$pcache_ push-update $pageid $pageinfo"
  431. $agent set fid_ $fid
  432. $self evTrace S UPD p $pageid m $modtime z $size
  433. }
  434. Http/Server/Inval/Yuc instproc get-req-notify { pageid } {
  435. $self count-request $pageid
  436. }
  437. Http/Server/Inval/Yuc instproc handle-request-TLC { pageid args } {
  438. $self instvar tlc_
  439. array set data $args
  440. lappend res $data(size) ;# Same size of queries
  441. lappend res $tlc_
  442. return $res
  443. }
  444. #----------------------------------------------------------------------
  445. # server + support for compound pages. 
  446. # A compound page is considered to be a frequently changing main page
  447. # and several component pages which are usually big static images.
  448. #
  449. # XXX This is a naive implementation, which assumes single page and 
  450. # fixed page size for all pages
  451. #----------------------------------------------------------------------
  452. Class Http/Server/Compound -superclass Http/Server
  453. # Invalidation server for compound pages
  454. Class Http/Server/Inval/MYuc -superclass 
  455. { Http/Server/Inval/Yuc Http/Server/Compound}