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

通讯编程

开发平台:

Visual C++

  1. #  Copyright (c) 1997 by the University of Southern California
  2. #  All rights reserved.
  3. #  This program is free software; you can redistribute it and/or
  4. #  modify it under the terms of the GNU General Public License,
  5. #  version 2, as published by the Free Software Foundation.
  6. #
  7. #  This program is distributed in the hope that it will be useful,
  8. #  but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  10. #  GNU General Public License for more details.
  11. #
  12. #  You should have received a copy of the GNU General Public License along
  13. #  with this program; if not, write to the Free Software Foundation, Inc.,
  14. #  59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
  15. #
  16. #  The copyright of this module includes the following
  17. #  linking-with-specific-other-licenses addition:
  18. #
  19. #  In addition, as a special exception, the copyright holders of
  20. #  this module give you permission to combine (via static or
  21. #  dynamic linking) this module with free software programs or
  22. #  libraries that are released under the GNU LGPL and with code
  23. #  included in the standard release of ns-2 under the Apache 2.0
  24. #  license or under otherwise-compatible licenses with advertising
  25. #  requirements (or modified versions of such code, with unchanged
  26. #  license).  You may copy and distribute such a system following the
  27. #  terms of the GNU GPL for this module and the licenses of the
  28. #  other code concerned, provided that you include the source code of
  29. #  that other code when and as the GNU GPL requires distribution of
  30. #  source code.
  31. #
  32. #  Note that people who make modified versions of this module
  33. #  are not obligated to grant this special exception for their
  34. #  modified versions; it is their choice whether to do so.  The GNU
  35. #  General Public License gives permission to release a modified
  36. #  version without this exception; this exception also makes it
  37. #  possible to release a modified version which carries forward this
  38. #  exception.
  39. # Implementation of web cache, client and server which support 
  40. # multimedia objects.
  41. #
  42. # $Header: /cvsroot/nsnam/ns-2/tcl/webcache/http-mcache.tcl,v 1.6 2005/09/16 03:05:47 tomh Exp $
  43. #
  44. # Multimedia web client
  45. #
  46. # Override this method to change the default max size of the page pool
  47. Http/Client/Media instproc create-pagepool {} {
  48. set pool [new PagePool/Client/Media]
  49. $self set-pagepool $pool
  50. return $pool
  51. }
  52. # Connection procedure:
  53. # (1) Client ---(HTTP_REQUEST)--> Server
  54. # (2) Client <--(HTTP_RESPONSE)-- Server
  55. # (3) Client <----(RAP_DATA)----  Server
  56. Http/Client/Media instproc get-response-GET { server pageid args } {
  57. eval $self next $server $pageid $args
  58. # XXX Enter the page into page pool, so that we can keep track of 
  59. # which segment has been received and know where to stop receiving. 
  60. if [$self exist-page $pageid] {
  61. error "Http/Client/Media: receives an "active" page!"
  62. }
  63. eval $self enter-page $pageid $args
  64. array set data $args
  65. if {[info exists data(pgtype)] && ($data(pgtype) == "MEDIA")} {
  66. # Create a multimedia connection to server
  67. $self media-connect $server $pageid
  68. }
  69. }
  70. # Don't accept an request if there is one stream still on transit
  71. Http/Client/Media instproc send-request { server type pageid args } {
  72. $self instvar mmapp_ 
  73. if [info exists mmapp_($pageid)] {
  74. return
  75. }
  76. eval $self next $server $type $pageid $args
  77. }
  78. # Create a RAP connection to a server
  79. Http/Client/Media instproc media-connect { server pageid } {
  80. # DEBUG ONLY
  81. #puts "Client [$self id] media-connect [$server id] $pageid"
  82. $self instvar mmapp_ ns_ node_ 
  83. Http instvar MEDIA_TRANSPORT_ MEDIA_APP_
  84. if [info exists mmapp_($pageid)] {
  85. puts "Media client [$self id] got a request for an existing stream"
  86. return
  87. }
  88. set agent [new Agent/$MEDIA_TRANSPORT_]
  89. $ns_ attach-agent $node_ $agent
  90. set app [new Application/$MEDIA_APP_ $pageid]
  91. $app attach-agent $agent
  92. $app target $self
  93. $server alloc-mcon $self $pageid $agent
  94. set mmapp_($pageid) $app
  95. $app set-layer [$self get-layer $pageid]
  96. }
  97. Http/Client/Media instproc media-disconnect { server pageid } {
  98. $self instvar mmapp_ ns_ node_
  99. if {![info exists mmapp_($pageid)]} {
  100. error "Media client [$self id] disconnect: not connected to 
  101. server [$server id] with page $pageid"
  102. }
  103. set app $mmapp_($pageid)
  104. set agent [$app agent]
  105. $ns_ detach-agent $node_ $agent
  106. # DEBUG ONLY
  107. # puts "Client [$self id] disconnect from server [$server id]"
  108. # Disconnect the agent and app at the server side
  109. $server media-disconnect $self $pageid
  110. delete $agent
  111. delete $app
  112. unset mmapp_($pageid)
  113. $self stream-received $pageid
  114. }
  115. #
  116. # Multimedia web server
  117. #
  118. # Create media pages instead of normal pages
  119. Http/Server/Media instproc gen-page { pageid } {
  120. $self instvar pgtr_ 
  121. set pginfo [$self next $pageid]
  122. if [$pgtr_ is-media-page $pageid] {
  123. return [lappend pginfo pgtype MEDIA]
  124. } else {
  125. return $pginfo
  126. }
  127. }
  128. Http/Server/Media instproc create-pagepool {} {
  129. set pool [new PagePool/Client/Media]
  130. $self set-pagepool $pool
  131. # Set the pool size to "infinity" (2^31-1)
  132. $pool set max_size_ 2147483647
  133. return $pool
  134. }
  135. Http/Server/Media instproc medialog-on {} {
  136. $self instvar MediaLog_
  137. set MediaLog_ 1
  138. }
  139. # Allocate a media connection
  140. Http/Server/Media instproc alloc-mcon { client pageid dst_agent } {
  141. $self instvar ns_ node_ mmapp_ 
  142. Http instvar MEDIA_TRANSPORT_ MEDIA_APP_
  143. set agent [new Agent/$MEDIA_TRANSPORT_]
  144. $ns_ attach-agent $node_ $agent
  145. set app [new Application/$MEDIA_APP_ $pageid]
  146. $app attach-agent $agent
  147. $app target $self 
  148. set mmapp_($client/$pageid) $app
  149. # Set layers
  150. $app set-layer [$self get-layer $pageid]
  151. # Associate $app with $client and $pageid
  152. $self register-client $app $client $pageid
  153. # DEBUG ONLY
  154. # Logging MediaApps, only do it for sender-side media apps
  155. $self instvar MediaLog_
  156. if [info exists MediaLog_] {
  157. set lf [$self log]
  158. if {$lf != ""} {
  159. $app log $lf
  160. }
  161. }
  162. # puts "Server [$self id] allocated a connection to client [$client id] using agent $agent"
  163. # Connect two RAP agents and start data transmission
  164. $ns_ connect $agent $dst_agent
  165. $agent start
  166. }
  167. Http/Server/Media instproc media-disconnect { client pageid } { 
  168. $self instvar mmapp_ ns_ node_
  169. # DEBUG ONLY
  170. # puts "At [$ns_ now] Server [$self id] disconnected from client [$client id]"
  171. if {![info exists mmapp_($client/$pageid)]} {
  172. error "Media server [$self id] disconnect: not connected to 
  173. client [$client id] with page $pageid"
  174. }
  175. set app $mmapp_($client/$pageid)
  176. set agent [$app agent]
  177. $ns_ detach-agent $node_ $agent
  178. $self unregister-client $app $client $pageid
  179. # DEBUG ONLY 
  180. # puts "Server [$self id] deleting agent $agent"
  181. delete $agent
  182. delete $app
  183. unset mmapp_($client/$pageid)
  184. }
  185. # Tell the client that a stream has been completed. Assume that there is 
  186. # an open connection between server and client
  187. Http/Server/Media instproc finish-stream { app } {
  188. $self instvar mmapp_ 
  189. foreach n [array names mmapp_] {
  190. if {$mmapp_($n) == $app} {
  191. set tmp [split $n /]
  192. set client [lindex $tmp 0]
  193. set pageid [lindex $tmp 1]
  194. $self send $client [$self get-reqsize] 
  195. "$client media-disconnect $self $pageid"
  196. return
  197. }
  198. }
  199. }
  200. # If the page is a media page, set the response size to that of the request
  201. Http/Server/Media instproc handle-request-GET { pageid args } {
  202. set pginfo [eval $self next $pageid $args]
  203. if {[$self get-pagetype $pageid] == "MEDIA"} {
  204. set pginfo [lreplace $pginfo 0 0 [$self get-reqsize]]
  205. }
  206. return $pginfo
  207. }
  208. Http/Server/Media instproc gen-pageinfo { pageid } {
  209. set pginfo [eval $self next $pageid]
  210. # Create contents for media page
  211. $self instvar pgtr_
  212. if [$pgtr_ is-media-page $pageid] {
  213. return [lappend pginfo pgtype MEDIA layer 
  214. [$pgtr_ get-layer $pageid]]
  215. } else {
  216. return $pginfo
  217. }
  218. }
  219. # Map a media application to the HTTP application at the other end
  220. #Http/Server/Media instproc map-media-app { app } {
  221. # $self instvar mmapp_
  222. # foreach n [array names mmapp_] {
  223. # if {$mmapp_($n) == $app} {
  224. # return [lindex [split $n /] 0]
  225. # }
  226. # }
  227. #}
  228. # Handle prefetching of designated segments
  229. Http/Server/Media instproc get-request { client type pageid args } {
  230. if {$type == "PREFSEG"} {
  231. # XXX allow only one prefetching stream from any single client
  232. # Records this client as doing prefetching. 
  233. # FAKE a connection to the client without prior negotiation
  234. set pagenum [lindex [split $pageid :] 1]
  235. set conid [lindex $args 0]
  236. set layer [lindex $args 1]
  237. set seglist [lrange $args 2 end]
  238. eval $self register-prefetch $client $pagenum $conid 
  239. $layer $seglist
  240. $client start-prefetch $self $pageid $conid
  241. $self evTrace S PREF p $pageid l $layer [join $seglist]
  242. # DEBUG only
  243. # $self instvar ns_
  244. # puts "At [$ns_ now] server [$self id] prefetches $args"
  245. } elseif {$type == "STOPPREF"} {
  246. set pagenum [lindex [split $pageid :] 1]
  247. set conid [lindex $args 0]
  248. # DEBUG only
  249. # $self instvar ns_
  250. # puts "At [$ns_ now] server [$self id] stops prefetching $pageid conid $conid"
  251. if [$self stop-prefetching $client $conid $pagenum] {
  252. # Tear down pref channel iff we don't have remaining 
  253. # clients sharing the channel
  254. $client media-disconnect $self $pageid $conid
  255. }
  256. } elseif {$type == "OFFLPREF"} {
  257. # Simply send the page back through TCP channel
  258. if ![$self exist-page $pageid] {
  259. error "Server [$self id] offline-prefetch non-existent page $pageid!"
  260. }
  261. set size [$self get-size $pageid]
  262. $self send $client $size "$client offline-complete $pageid"
  263. } else {
  264. eval $self next $client $type $pageid $args
  265. }
  266. }
  267. #
  268. # Multimedia web cache
  269. #
  270. Http/Cache/Media instproc create-pagepool {} {
  271. set pool [new PagePool/Client/Media]
  272. $self set-pagepool $pool
  273. return $pool
  274. }
  275. Http/Cache/Media instproc start-prefetch { server pageid conid } {
  276. $self instvar pref_ ns_
  277. if [info exists pref_($server/$pageid)] {
  278. # We are already connected to the server
  279. if {[lsearch -exact $pref_($server/$pageid) $conid] == -1} {
  280. # puts "At [$ns_ now] cache [$self id] RE-REQUESTs prefetching to server [$server id] for page $pageid"
  281. lappend pref_($server/$pageid) $conid
  282. }
  283. return
  284. } else {
  285. # Whenever there is a prefetching request to the server, 
  286. # increase the "ref counter" by one. Then we delete it 
  287. # when it's 0.
  288. lappend pref_($server/$pageid) $conid
  289. }
  290. # puts "At [$ns_ now] cache [$self id] starts prefetching to [$server id] for page $pageid conid $conid"
  291. # XXX Do not use QA for prefetching!!
  292. Http instvar MEDIA_APP_
  293. set oldapp $MEDIA_APP_
  294. # XXX Do not use the default initial RTT of RAP. We must start sending
  295. # as soon as possible, then drop our rate if necessary. Instead, set
  296. # initial ipg_ and srtt_ to 10ms.
  297. set oldipg [Agent/RAP set ipg_]
  298. set oldsrtt [Agent/RAP set srtt_]
  299. Agent/RAP set ipg_ 0.01
  300. Agent/RAP set srtt_ 0.01
  301. set MEDIA_APP_ MediaApp
  302. $self media-connect $server $pageid
  303. set MEDIA_APP_ $oldapp
  304. Agent/RAP set ipg_ $oldipg
  305. Agent/RAP set srtt_ $oldsrtt
  306. }
  307. Http/Cache/Media instproc media-connect { server pageid } {
  308. $self instvar s_mmapp_ ns_ node_ 
  309. # DEBUG ONLY
  310. # puts "At [$ns_ now], cache [$self id] connects to [$server id] for page $pageid"
  311. Http instvar MEDIA_TRANSPORT_ MEDIA_APP_
  312. if [info exists s_mmapp_($server/$pageid)] {
  313. error "Media client [$self id] got a request for an existing 
  314. stream"
  315. }
  316. set agent [new Agent/$MEDIA_TRANSPORT_]
  317. $ns_ attach-agent $node_ $agent
  318. set app [new Application/$MEDIA_APP_ $pageid]
  319. $app attach-agent $agent
  320. $app target $self
  321. $server alloc-mcon $self $pageid $agent
  322. set s_mmapp_($server/$pageid) $app
  323. $app set-layer [$self get-layer $pageid]
  324. }
  325. Http/Cache/Media instproc alloc-mcon { client pageid dst_agent } {
  326. $self instvar ns_ node_ c_mmapp_ 
  327. Http instvar MEDIA_TRANSPORT_ MEDIA_APP_
  328. if [info exists c_mmapp_($client/$pageid)] {
  329. error "Media cache [$self id] got a request for an existing 
  330. stream $pageid from client [$client id]"
  331. }
  332. set agent [new Agent/$MEDIA_TRANSPORT_]
  333. $ns_ attach-agent $node_ $agent
  334. set app [new Application/$MEDIA_APP_ $pageid]
  335. $app attach-agent $agent
  336. $app target $self 
  337. set c_mmapp_($client/$pageid) $app
  338. # Set layers
  339. $app set-layer [$self get-layer $pageid]
  340. # Associate $app with $client and $pageid
  341. $self register-client $app $client $pageid
  342. # Logging MediaApps, only do it for sender-side media apps
  343. $self instvar MediaLog_
  344. if [info exists MediaLog_] {
  345. set lf [$self log]
  346. if {$lf != ""} {
  347. $app log $lf
  348. }
  349. }
  350. # Connect two RAP agents and start data transmission
  351. $ns_ connect $agent $dst_agent
  352. $agent start
  353. }
  354. # Turn on logging of media application
  355. Http/Cache/Media instproc medialog-on {} {
  356. $self instvar MediaLog_
  357. set MediaLog_ 1
  358. }
  359. Http/Cache/Media instproc media-disconnect { host pageid args } {
  360. $self instvar c_mmapp_ s_mmapp_ ns_ node_ pref_ c_tbt_
  361. # Flags: is it client disconnection or server? 
  362. set cntdisco 0 
  363. set svrdisco 0
  364. set server [lindex [split $pageid :] 0]
  365. if {($host != $server) && [info exists c_mmapp_($host/$pageid)]} {
  366. # Disconnect from a client
  367. set app $c_mmapp_($host/$pageid)
  368. set agent [$app agent]
  369. $ns_ detach-agent $node_ $agent
  370. $self unregister-client $app $host $pageid
  371. # DEBUG ONLY
  372. # puts "At [$ns_ now] Cache [$self id] disconnect from 
  373. # client [$host id]"
  374. # Do NOT delete client-side agent and app until we've 
  375. # torn down prefetching connection to the server. 
  376. # XXX But first check that this client has indeed been 
  377. # involved in prefetching!
  378. if {[info exists pref_($server/$pageid)] && 
  379. [lsearch -exact $pref_($server/$pageid) $app] != -1} {
  380. # If we have concurrent requests and other clients
  381. # may still be using this prefetching channel. We
  382. # tell the server that this client has stopped so 
  383. # that server will remove all related state.
  384. # puts "At [$ns_ now] Cache [$self id] stops prefetching for conid $app, page $pageid, from server [$server id]"
  385. $self send $server [$self get-reqsize] "$server get-request $self STOPPREF $pageid $app"
  386. # Stop application-related timers
  387. set c_tbt_($host/$pageid) $app
  388. $app stop
  389. } else {
  390. delete $app
  391. }
  392. delete $agent
  393. unset c_mmapp_($host/$pageid)
  394. # Dump status of all pages after serving a client
  395. $self instvar pool_
  396. foreach p [lsort [$pool_ list-pages]] {
  397. $self dump-page $p
  398. }
  399. set cntdisco 1
  400. } elseif [info exists s_mmapp_($host/$pageid)] {
  401. # XXX This assumes that we are NOT connecting to another cache.
  402. # Stop prefetching when we requested that at the server. 
  403. #
  404. # Also, we assume that while the cache is downloading from 
  405. # the server during the first retrieval, no prefetching should
  406. # be used. This is guaranteed by the way MEDIAREQ_CHECKSEG is 
  407. # handled in mcache.cc:680.
  408. #
  409. # Note that (1) this always happens AFTER client disconnection,
  410. # (2) whenever there is a prefetching connection, there's 
  411. # always a corresponding entry in s_mmapp_().
  412. #
  413. # If we are disconnecting a prefetching channel, check if 
  414. # we still have other clients sharing the channel. If not,
  415. # then we tear down the channel. 
  416. set svrdisco 1
  417. if [info exists pref_($server/$pageid)] {
  418. # By default we don't tear down pref channel
  419. set teardown 0
  420. # Actually the MediaApp for the client
  421. set conid [lindex $args 0]
  422. set pos [lsearch -exact $pref_($server/$pageid) $conid]
  423. if {$pos == -1} {
  424. error "media-disconnect cannot find $conid!!"
  425. }
  426. set pref_($server/$pageid) [lreplace 
  427. $pref_($server/$pageid) $pos $pos]
  428. if {[llength $pref_($server/$pageid)] == 0} {
  429. $self evTrace E STP s [$server id] p $pageid
  430. unset pref_($server/$pageid)
  431. # Now we can tear down the pref channel
  432. set teardown 1
  433. }
  434. # Tear down client-side connection (i.e.,conid)
  435. # puts "At [$ns_ now] cache [$self id] stops prefetching
  436. # to [$server id] for client $conid"
  437. delete $conid
  438. } else {
  439. # If no pref, tear down by default
  440. set teardown 1
  441. }
  442. if {$teardown} {
  443. # Disconnect from a server
  444. set app $s_mmapp_($host/$pageid)
  445. set agent [$app agent]
  446. $ns_ detach-agent $node_ $agent
  447. $host media-disconnect $self $pageid
  448. # DEBUG ONLY
  449. # puts "At [$ns_ now] Cache [$self id] disconnect from 
  450. # server [$host id]"
  451. delete $agent
  452. delete $app
  453. unset s_mmapp_($host/$pageid)
  454. }
  455. # Use the TCP channel between the cache and the server to 
  456. # transmit the entire file. Note since we no longer do 
  457. # online prefetching, this channel is pretty much empty
  458. # and we can occupy it as long as we want. 
  459. $self instvar firstreq_
  460. if {([$self get-pref-style] == "OFFLINE_PREF") && 
  461. [info exists firstreq_($pageid)]} { 
  462. $self send $server [$self get-reqsize] 
  463. "$server get-request $self OFFLPREF $pageid"
  464. }
  465. if [info exists firstreq_($pageid)] {
  466. unset firstreq_($pageid)
  467. }
  468. } else {
  469. error "At [$ns_ now] Media cache [$self id] tries to 
  470. disconnect from a non-connected host [$host id]"
  471. }
  472. # XXX Only do this when we disconnect from a server. 
  473. if {$svrdisco == 1} {
  474. $self stream-received $pageid
  475. }
  476. }
  477. # Tell the client that a stream has been completed. Assume that there is 
  478. # an open connection between server and client
  479. Http/Cache/Media instproc finish-stream { app } {
  480. $self instvar c_mmapp_ s_mmapp_
  481. foreach n [array names c_mmapp_] {
  482. if {$c_mmapp_($n) == $app} {
  483. set tmp [split $n /]
  484. set client [lindex $tmp 0]
  485. set pageid [lindex $tmp 1]
  486. $self send $client [$self get-reqsize] 
  487. "$client media-disconnect $self $pageid"
  488. return
  489. }
  490. }
  491. }
  492. Http/Cache/Media instproc get-response-GET { server pageid args } {
  493. # Whether this is the first request. If offline prefetching is used, 
  494. # media-disconnect{} uses this information to decide whether to 
  495. # prefetch the entire stream. 
  496. $self instvar firstreq_
  497. if ![$self exist-page $pageid] {
  498. set firstreq_($pageid) 1
  499. }
  500. eval $self next $server $pageid $args
  501. # DEBUG ONLY
  502. # puts "Cache [$self id] gets response"
  503. array set data $args
  504. if {[info exists data(pgtype)] && ($data(pgtype) == "MEDIA")} {
  505. # Create a multimedia connection to server
  506. $self media-connect $server $pageid
  507. }
  508. }
  509. # XXX If it's a media page, change page size and send back a small response. 
  510. # This response is intended to establish a RAP connection from client to 
  511. # cache. 
  512. Http/Cache/Media instproc answer-request-GET { cl pageid args } {
  513. array set data $args
  514. if {[info exists data(pgtype)] && ($data(pgtype) == "MEDIA")} {
  515. set size [$self get-reqsize]
  516. } else {
  517. set size $data(size)
  518. }
  519. $self send $cl $size 
  520. "$cl get-response-GET $self $pageid $args"
  521. $self evTrace E SND c [$cl id] p $pageid z $data(size)
  522. }
  523. # $args is a list of segments, each of which is a list of 
  524. # two elements: {start end}
  525. Http/Cache/Media instproc pref-segment {conid pageid layer args} {
  526. # XXX directly send a request to the SERVER. Assuming that 
  527. # we are not going through another cache. 
  528. set server [lindex [split $pageid :] 0]
  529. set size [$self get-reqsize]
  530. $self send $server $size "$server get-request $self PREFSEG 
  531. $pageid $conid $layer [join $args]"
  532. }
  533. Http/Cache/Media instproc set-repl-style { style } {
  534. $self instvar pool_
  535. $pool_ set-repl-style $style
  536. }