4 namespace eval excentis {
13 namespace eval ByteBlower {
22 proc TcpAckSuppression { args } {
57 set resultInfoList [ list ]
60 set serverPortInfoList [ list ]
61 set nrOfServerPorts -1
63 set clientPortInfoList [ list ]
64 set nrOfClientPorts -1
66 set httpServerInfo [ list ]
67 set httpClientInfoList [ list ]
70 set portInfoList [
eval parseTcpAckSuppressionParams $args ]
71 set serverPortInfoList [
lindex $portInfoList 0 ]
72 set clientPortInfoList [
lindex $portInfoList 1 ]
74 if { [ set nrOfServerPorts [ llength $serverPortInfoList ] ] == 0 || [
set nrOfClientPorts [
llength $clientPortInfoList ] ] == 0} {
75 error "Please provide at least one option -rx and one option -tx"
77 puts "Performing ACK Suppression Test on $nrOfServerPorts HTTP Servers and $nrOfClientPorts HTTP Clients"
80 puts "Initializing HTTP Server"
81 set serverPortInfo [
lindex $serverPortInfoList 0 ]
86 foreach clientPortInfo $clientPortInfoList {
87 puts "Initializing HTTP Client [
incr httpClientNr ]"
92 puts "Starting HTTP Server"
97 foreach httpClientInfo $httpClientInfoList {
98 puts "Starting HTTP Client [
incr httpClientNr ]"
104 foreach httpClientInfo $httpClientInfoList {
105 puts "Waiting for HTTP Client [
incr httpClientNr ] to finish..."
107 puts "Current Status $httpClientStatus"
108 set httpClientStatus [
stopHttpClient $httpClientInfo $httpClientNr ]
109 puts "Final Status : $httpClientStatus"
136 foreach httpClientInfo $httpClientInfoList {
137 puts "Getting HTTP Client [
incr httpClientNr ] results"
145 set statusInfo [
lindex $resultInfo 0 ]
146 set tcpAckInfo [
lindex $resultInfo 1 ]
148 if { [ lindex $statusInfo 0 ] == 1} {
149 set statusIoChannel stdout
151 set statusIoChannel stderr
154 if { [ lindex $statusInfo 0 ] == 1} {
155 set tcpAckIoChannel stdout
157 set tcpAckIoChannel stderr
160 puts $statusIoChannel "Final Client Status : [
lindex $statusInfo 1 ]"
161 puts $statusIoChannel "Received bytes : [
lindex $statusInfo 2 ]"
162 puts $tcpAckIoChannel "Transmitted TCP ACKs : [
lindex $tcpAckInfo 1 ]"
163 puts $tcpAckIoChannel "Received TCP ACKs : [
lindex $tcpAckInfo 2 ]"
164 puts $tcpAckIoChannel "Suppressed TCP ACKs : [
lindex $tcpAckInfo 3 ]"
166 lappend resultInfoList $resultInfo
172 return $resultInfoList
176 proc parseTcpAckSuppressionParams { args } {
182 set serverPortInfoList [ list ]
183 set clientPortInfoList [ list ]
185 if { [ llength $args ] == 0 || [
llength $args ] % 2 != 0} {
187 error "Invalid number of arguments"
189 foreach {option value} $args {
192 set requestSize 1000000
195 set addCommand {lappend clientPortInfoList [ list $portObject $portNumber $requestSize ]}
198 if { [
llength $serverPortInfoList ] > 0 } {
199 error "Only one server is allowed."
201 #if { [
llength $value ] == 0 || [
llength $value ] % 2 != 0 } {
202 # # TODO: Convert this to TCL Throw...
203 # error "Invalid number of option <$option> arguments"
205 set addCommand {lappend serverPortInfoList [ list $portObject $portNumber ]}
208 error "Unknown option <$option> = <$value>"
211 if { [ llength $value ] == 0 || [
llength $value ] % 2 != 0} {
213 error "Invalid number of option <$option> arguments"
215 foreach {option2 value2} $value {
218 set portObject $value2
221 set portNumber $value2
224 if { [
string equal $option "-tx" ] } {
225 error "Unknown option <$option> value argument <$option2> = <$value2>"
227 set requestSize $value2
230 error "Unknown option <$option> value argument <$option2> = <$value2>"
234 if { [ string equal $portObject "null" ] || [
string equal $portNumber "null" ]} {
235 error "Please provide -port AND -portNumber to option <$option>"
240 return [ list $serverPortInfoList $clientPortInfoList ]
243 proc initializeHttpServer { serverPortInfo } {
254 set serverPortObject [
lindex $serverPortInfo 0 ]
255 set serverTcpPort [
lindex $serverPortInfo 1 ]
257 puts stderr "Server Port $serverPortObject"
260 set currentHttpServerList [ $serverPortObject Protocol.Http.Server.Get ]
261 foreach currentHttpServer $currentHttpServerList {
262 if { [ $currentHttpServer Port.Get ] == $serverTcpPort} {
263 set httpServer $currentHttpServer
264 puts "Initializing EXISTING HTTP SERVER : Listen Port == $serverTcpPort"
269 if { $httpServer == {}} {
270 puts "Initializing NEW HTTP SERVER : Listen Port == $serverTcpPort"
271 set httpServer [ $serverPortObject Protocol.Http.Server.Add ]
273 $httpServer Port.Set $serverTcpPort
276 puts stderr "HTTP Server Port $httpServer"
278 return [ list $httpServer ]
282 proc initializeHttpClient { clientPortInfo serverPortInfo } {
295 set httpClientInfo [ list ]
299 set serverPortObject [
lindex $serverPortInfo 0 ]
301 set serverTcpPort [
lindex $serverPortInfo 1 ]
304 set serverLayer3 [ $serverPortObject Layer3.IPv4.Get ]
305 set serverIpAddress [ $serverLayer3 Ip.Get ]
308 set clientPortObject [
lindex $clientPortInfo 0 ]
309 set clientTcpPort [
lindex $clientPortInfo 1 ]
310 set requestSize [
lindex $clientPortInfo 2 ]
312 puts stderr "Client Port $clientPortObject"
315 set clientLayer3 [ $clientPortObject Layer3.IPv4.Get ]
318 set currentHttpClientList [ $clientPortObject Protocol.Http.Client.Get ]
319 foreach currentHttpClient $currentHttpClientList {
320 if { [ $currentHttpClient Local.Port.Get ] == $clientTcpPort &&
321 [ $currentHttpClient Remote.Address.Get ] == $serverIpAddress &&
322 [ $currentHttpClient Remote.Port.Get ] == $serverTcpPort} {
323 set httpClient $currentHttpClient
324 puts "Initializing EXISTING HTTP Client : Local Port == $clientTcpPort, Remote Address == $serverIpAddress, Remote Port == $serverTcpPort"
330 if { $httpClient == {}} {
331 puts "Initializing NEW HTTP Client : Local Port == $clientTcpPort, Remote Address == $serverIpAddress, Remote Port == $serverTcpPort"
332 set httpClient [ $clientPortObject Protocol.Http.Client.Add ]
335 $httpClient Remote.Address.Set $serverIpAddress
336 $httpClient Remote.Port.Set $serverTcpPort
338 $httpClient Local.Port.Set $clientTcpPort
341 puts stderr "HTTP Client Port $httpClient"
344 set serverCapture [ $serverPortObject Rx.Capture.Basic.Add ]
345 set clientCapture [ $clientPortObject Rx.Capture.Basic.Add ]
348 $serverCapture Filter.Set "host [ $clientLayer3 Ip.Get ]"
349 $clientCapture Filter.Set "host [ $clientLayer3 Ip.Get ]"
352 return [ list $httpClient $requestSize $clientCapture $serverCapture ]
356 proc startHttpServer { httpServerInfo } {
364 set httpServer [
lindex $httpServerInfo 0 ]
372 proc startHttpClient { httpClientInfo } {
381 set httpClient [
lindex $httpClientInfo 0 ]
382 set requestSize [
lindex $httpClientInfo 1 ]
383 set clientCapture [
lindex $httpClientInfo 2 ]
384 set serverCapture [
lindex $httpClientInfo 3 ]
393 $httpClient Request.Size.Set $requestSize
394 $httpClient Request.Start
400 proc waitForHttpClientFinish { httpClientInfo } {
409 set httpClient [
lindex $httpClientInfo 0 ]
411 set clientCapture [
lindex $httpClientInfo 2 ]
412 set serverCapture [
lindex $httpClientInfo 3 ]
414 set httpClientStatus "<UNKNOWN>"
416 while { ![ $httpClient Finished.Get ]} {
418 after 1000 "set wait 1"
420 puts -nonewline "*"
flush stdout
427 return [ $httpClient Request.Status.Get ]
431 proc stopHttpClient { httpClientInfo httpClientId } {
444 set httpClient [
lindex $httpClientInfo 0 ]
445 set clientCapture [
lindex $httpClientInfo 2 ]
446 set serverCapture [
lindex $httpClientInfo 3 ]
452 after 200 "set wait 1"
456 puts "Stopping captures.."
460 puts "Saving captures.."
flush stdout
461 puts "Saving captures: server"
flush stdout
462 [ $serverCapture Result.Get ] Pcap.Save "httpServer${httpClientId}.pcap"
463 puts "Saving captures: client"
flush stdout
464 [ $clientCapture Result.Get ] Pcap.Save "httpClient${httpClientId}.pcap"
465 puts "Saving captures: done"
flush stdout
466 return [ $httpClient Request.Status.Get ]
470 proc stopHttpServer { httpServerInfo } {
478 set httpServer [
lindex $httpServerInfo 0 ]
486 proc getHttpClientResults { httpClientInfo httpServerInfo } {
497 set resultInfo [ list ]
499 set httpServer [
lindex $httpServerInfo 0 ]
500 set httpClient [
lindex $httpClientInfo 0 ]
501 set requestSize [
lindex $httpClientInfo 1 ]
506 lappend resultInfo $statusInfo
507 lappend resultInfo $tcpAckInfo
513 proc parseHttpClientStatusResult { httpClient requestSize } {
525 set statusInfo [ list ]
528 set httpClientSessionInfo [ $httpClient Http.Session.Info.Get ]
530 set result [ $httpClientSessionInfo Result.Get ]
532 set rxBytes [ $result Rx.ByteCount.Total.Get ]
534 set requestStatus [ $httpClient Request.Status.Get ]
535 if { ![ string equal $requestStatus "finished" ] && ! [
string equal $requestStatus "stopped" ]} {
536 puts stderr "The Client is not in a <finished> state"
540 if { $rxBytes != $requestSize} {
541 puts stderr "The Number of received bits is not the same as the number of requested bits."
545 lappend statusInfo $pf
546 lappend statusInfo $requestStatus
547 lappend statusInfo $rxBytes
553 proc parseHttpClientTcpAckResult { httpClient httpServer } {
564 puts "HTTP Sessions available on the server: [ $httpServer Client.Identifiers.Get ]"
565 set clientTcpSessionResult [ [ [ $httpClient Http.Session.Info.Get ] Tcp.Session.Info.Get ] Result.Get ]
568 set scId [ $httpClient ServerClientId.Get ]
571 while { $hasSession == 0} {
572 set hasSession [ $httpServer HasSession $scId ]
573 if { $hasSession == 0} {
574 set wait 0 after 500 "set wait 1"
vwait wait unset wait
577 set httpServerSessionInfo [ $httpServer Http.Session.Info.Get $scId ]
579 set serverTcpSessionResult [ [ $httpServerSessionInfo Tcp.Session.Info.Get ] Result.Get ]
580 $clientTcpSessionResult Refresh
581 $serverTcpSessionResult Refresh
583 puts stderr "clientTcpSession : [ $clientTcpSessionResult Description.Get ]"
584 puts stderr "serverTcpSession : [ $serverTcpSessionResult Description.Get ]"
586 set tcpAckInfo [ list ]
590 set nrOfSuppressedACKs -1
593 set txSyns [ $clientTcpSessionResult NumberOfSynSent.Get ]
594 set txSegments [ $clientTcpSessionResult Tx.SegmentCount.Total.Get ]
595 set txACKs [
expr $txSegments - $txSyns ]
596 puts stderr "Sent TCP ACKs : $txACKs"
598 set rxSyns [ $serverTcpSessionResult NumberOfSynReceived.Get ]
599 set rxSegments [ $serverTcpSessionResult Rx.SegmentCount.Total.Get ]
600 set rxACKs [
expr $rxSegments - $rxSyns ]
601 puts stderr "Received TCP ACKs : $rxACKs"
605 puts stderr "No ACKs transmitted"
608 set nrOfSuppressedACKs [
expr $txACKs - $rxACKs ]
609 puts stderr "$nrOfSuppressedACKs ACKs suppressed ($txACKs transmitted)"
612 lappend tcpAckInfo $pf
613 lappend tcpAckInfo $txACKs
614 lappend tcpAckInfo $rxACKs
615 lappend tcpAckInfo $nrOfSuppressedACKs