1 /*---------------------------------------------------------------
2 * Copyright (c) 1999,2000,2001,2002,2003
3 * The Board of Trustees of the University of Illinois
5 *---------------------------------------------------------------
6 * Permission is hereby granted, free of charge, to any person
7 * obtaining a copy of this software (Iperf) and associated
8 * documentation files (the "Software"), to deal in the Software
9 * without restriction, including without limitation the
10 * rights to use, copy, modify, merge, publish, distribute,
11 * sublicense, and/or sell copies of the Software, and to permit
12 * persons to whom the Software is furnished to do
13 * so, subject to the following conditions:
16 * Redistributions of source code must retain the above
17 * copyright notice, this list of conditions and
18 * the following disclaimers.
21 * Redistributions in binary form must reproduce the above
22 * copyright notice, this list of conditions and the following
23 * disclaimers in the documentation and/or other materials
24 * provided with the distribution.
27 * Neither the names of the University of Illinois, NCSA,
28 * nor the names of its contributors may be used to endorse
29 * or promote products derived from this Software without
30 * specific prior written permission.
32 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
33 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
34 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
35 * NONINFRINGEMENT. IN NO EVENT SHALL THE CONTIBUTORS OR COPYRIGHT
36 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
37 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
38 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE
39 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
40 * ________________________________________________________________
41 * National Laboratory for Applied Network Research
42 * National Center for Supercomputing Applications
43 * University of Illinois at Urbana-Champaign
44 * http://www.ncsa.uiuc.edu
45 * ________________________________________________________________
48 * by Kevin Gibbs <kgibbs@nlanr.net>
50 * ________________________________________________________________ */
53 #include "Settings.hpp"
58 #include "PerfSocket.hpp"
59 #include "SocketAddr.h"
66 The following 4 functions are provided for Reporting
67 styles that do not have all the reporting formats. For
68 instance the provided CSV format does not have a settings
69 report so it uses settings_notimpl.
71 void* connection_notimpl( Connection_Info * nused, int nuse ) {
74 void settings_notimpl( ReporterData * nused ) { }
75 void statistics_notimpl( Transfer_Info * nused ) { }
76 void serverstatistics_notimpl( Connection_Info *nused1, Transfer_Info *nused2 ) { }
78 // To add a reporting style include its header here.
79 #include "report_default.h"
80 #include "report_CSV.h"
82 // The following array of report structs contains the
83 // pointers required for reporting in different reporting
84 // styles. To add a reporting style add a report struct
86 report_connection connection_reports[kReport_MAXIMUM] = {
91 report_settings settings_reports[kReport_MAXIMUM] = {
92 reporter_reportsettings,
96 report_statistics statistics_reports[kReport_MAXIMUM] = {
101 report_serverstatistics serverstatistics_reports[kReport_MAXIMUM] = {
102 reporter_serverstats,
106 report_statistics multiple_reports[kReport_MAXIMUM] = {
111 char buffer[64]; // Buffer for printing
112 ReportHeader *ReportRoot = NULL;
113 extern Condition ReportCond;
114 extern Condition ReportDoneCond;
115 int reporter_process_report ( ReportHeader *report );
116 void process_report ( ReportHeader *report );
117 int reporter_handle_packet( ReportHeader *report );
118 int reporter_condprintstats( ReporterData *stats, MultiHeader *multireport, int force );
119 int reporter_print( ReporterData *stats, int type, int end );
120 void PrintMSS( ReporterData *stats );
122 MultiHeader* InitMulti( thread_Settings *agent, int inID ) {
123 MultiHeader *multihdr = NULL;
124 if ( agent->mThreads > 1 || agent->mThreadMode == kMode_Server ) {
125 if ( isMultipleReport( agent ) ) {
126 multihdr = malloc(sizeof(MultiHeader) + sizeof(ReporterData) +
127 NUM_MULTI_SLOTS * sizeof(Transfer_Info));
129 multihdr = malloc(sizeof(MultiHeader));
131 if ( multihdr != NULL ) {
132 memset( multihdr, 0, sizeof(MultiHeader) );
133 Condition_Initialize( &multihdr->barrier );
134 multihdr->groupID = inID;
135 multihdr->threads = agent->mThreads;
136 if ( isMultipleReport( agent ) ) {
138 ReporterData *data = NULL;
139 multihdr->report = (ReporterData*)(multihdr + 1);
140 memset(multihdr->report, 0, sizeof(ReporterData));
141 multihdr->data = (Transfer_Info*)(multihdr->report + 1);
142 data = multihdr->report;
143 for ( i = 0; i < NUM_MULTI_SLOTS; i++ ) {
144 multihdr->data[i].startTime = -1;
145 multihdr->data[i].transferID = inID;
146 multihdr->data[i].groupID = -2;
148 data->type = TRANSFER_REPORT;
149 if ( agent->mInterval != 0.0 ) {
150 struct timeval *interval = &data->intervalTime;
151 interval->tv_sec = (long) agent->mInterval;
152 interval->tv_usec = (long) ((agent->mInterval - interval->tv_sec)
155 data->mHost = agent->mHost;
156 data->mLocalhost = agent->mLocalhost;
157 data->mBufLen = agent->mBufLen;
158 data->mMSS = agent->mMSS;
159 data->mWinSize = agent->mWinSize;
160 data->flags = agent->flags;
161 data->mProtocol = agent->mProtocol;
162 data->mThreadMode = agent->mThreadMode;
163 data->mode = agent->mReportMode;
164 data->info.mFormat = agent->mFormat;
165 data->info.mTTL = agent->mTTL;
166 if ( isPacketOriented( agent ) ) {
167 multihdr->report->info.mUDP = (char)agent->mThreadMode;
169 if ( isConnectionReport( agent ) ) {
170 data->type |= CONNECTION_REPORT;
171 data->connection.peer = agent->peer;
172 data->connection.size_peer = agent->size_peer;
173 SockAddr_setPortAny( &data->connection.peer );
174 data->connection.local = agent->local;
175 data->connection.size_local = agent->size_local;
176 SockAddr_setPortAny( &data->connection.local );
180 FAIL(1, "Out of Memory!!\n", agent);
187 * BarrierClient allows for multiple stream clients to be syncronized
189 void BarrierClient( ReportHeader *agent ) {
190 Condition_Lock(agent->multireport->barrier);
191 agent->multireport->threads--;
192 if ( agent->multireport->threads == 0 ) {
193 // last one set time and wake up everyone
194 gettimeofday( &(agent->multireport->startTime), NULL );
195 Condition_Broadcast( &agent->multireport->barrier );
197 Condition_Wait( &agent->multireport->barrier );
199 agent->multireport->threads++;
200 Condition_Unlock( agent->multireport->barrier );
201 agent->report.startTime = agent->multireport->startTime;
202 agent->report.nextTime = agent->report.startTime;
203 TimeAdd( agent->report.nextTime, agent->report.intervalTime );
207 * InitReport is called by a transfer agent (client or
208 * server) to setup the needed structures to communicate
211 ReportHeader* InitReport( thread_Settings *agent ) {
212 ReportHeader *reporthdr = NULL;
213 ReporterData *data = NULL;
214 if ( isDataReport( agent ) ) {
216 * Create in one big chunk
218 reporthdr = malloc( sizeof(ReportHeader) +
219 NUM_REPORT_STRUCTS * sizeof(ReportStruct) );
220 if ( reporthdr != NULL ) {
221 // Only need to make sure the headers are clean
222 memset( reporthdr, 0, sizeof(ReportHeader));
223 reporthdr->data = (ReportStruct*)(reporthdr+1);
224 reporthdr->multireport = agent->multihdr;
225 data = &reporthdr->report;
226 reporthdr->reporterindex = NUM_REPORT_STRUCTS - 1;
227 data->info.transferID = agent->mSock;
228 data->info.groupID = (agent->multihdr != NULL ? agent->multihdr->groupID
230 data->type = TRANSFER_REPORT;
231 if ( agent->mInterval != 0.0 ) {
232 struct timeval *interval = &data->intervalTime;
233 interval->tv_sec = (long) agent->mInterval;
234 interval->tv_usec = (long) ((agent->mInterval - interval->tv_sec)
237 data->mHost = agent->mHost;
238 data->mLocalhost = agent->mLocalhost;
239 data->mBufLen = agent->mBufLen;
240 data->mMSS = agent->mMSS;
241 data->mWinSize = agent->mWinSize;
242 data->flags = agent->flags;
243 data->mProtocol = agent->mProtocol;
244 data->mThreadMode = agent->mThreadMode;
245 data->mode = agent->mReportMode;
246 data->info.mFormat = agent->mFormat;
247 data->info.mTTL = agent->mTTL;
248 if ( isPacketOriented( agent ) ) {
249 reporthdr->report.info.mUDP = (char)agent->mThreadMode;
252 FAIL(1, "Out of Memory!!\n", agent);
255 if ( isConnectionReport( agent ) ) {
256 if ( reporthdr == NULL ) {
258 * Create in one big chunk
260 reporthdr = malloc( sizeof(ReportHeader) );
261 if ( reporthdr != NULL ) {
262 // Only need to make sure the headers are clean
263 memset( reporthdr, 0, sizeof(ReportHeader));
264 data = &reporthdr->report;
265 data->info.transferID = agent->mSock;
266 data->info.groupID = -1;
268 FAIL(1, "Out of Memory!!\n", agent);
271 if ( reporthdr != NULL ) {
272 data->type |= CONNECTION_REPORT;
273 data->connection.peer = agent->peer;
274 data->connection.size_peer = agent->size_peer;
275 data->connection.local = agent->local;
276 data->connection.size_local = agent->size_local;
278 FAIL(1, "Out of Memory!!\n", agent);
281 if ( isConnectionReport( agent ) || isDataReport( agent ) ) {
285 * Update the ReportRoot to include this report.
287 if ( reporthdr->report.mThreadMode == kMode_Client &&
288 reporthdr->multireport != NULL ) {
289 // syncronize watches on my mark......
290 BarrierClient( reporthdr );
292 if ( reporthdr->multireport != NULL && isMultipleReport( agent )) {
293 reporthdr->multireport->threads++;
294 if ( reporthdr->multireport->report->startTime.tv_sec == 0 ) {
295 gettimeofday( &(reporthdr->multireport->report->startTime), NULL );
297 reporthdr->report.startTime = reporthdr->multireport->report->startTime;
300 gettimeofday( &(reporthdr->report.startTime), NULL );
302 reporthdr->report.nextTime = reporthdr->report.startTime;
303 TimeAdd( reporthdr->report.nextTime, reporthdr->report.intervalTime );
305 Condition_Lock( ReportCond );
306 reporthdr->next = ReportRoot;
307 ReportRoot = reporthdr;
308 Condition_Signal( &ReportCond );
309 Condition_Unlock( ReportCond );
312 gettimeofday( &(reporthdr->report.startTime), NULL );
314 * Process the report in this thread
316 reporthdr->next = NULL;
317 process_report ( reporthdr );
320 if ( !isDataReport( agent ) ) {
327 * ReportPacket is called by a transfer agent to record
328 * the arrival or departure of a "packet" (for TCP it
329 * will actually represent many packets). This needs to
330 * be as simple and fast as possible as it gets called for
333 void ReportPacket( ReportHeader* agent, ReportStruct *packet ) {
334 if ( agent != NULL ) {
335 int index = agent->reporterindex;
337 * First find the appropriate place to put the information
339 if ( agent->agentindex == NUM_REPORT_STRUCTS ) {
340 // Just need to make sure that reporter is not on the first
342 while ( index == 0 ) {
343 Condition_Signal( &ReportCond );
344 Condition_Wait( &ReportDoneCond );
345 index = agent->reporterindex;
347 agent->agentindex = 0;
349 // Need to make sure that reporter is not about to be "lapped"
350 while ( index - 1 == agent->agentindex ) {
351 Condition_Signal( &ReportCond );
352 Condition_Wait( &ReportDoneCond );
353 index = agent->reporterindex;
356 // Put the information there
357 memcpy( agent->data + agent->agentindex, packet, sizeof(ReportStruct) );
359 // Updating agentindex MUST be the last thing done
363 * Process the report in this thread
365 process_report ( agent );
371 * CloseReport is called by a transfer agent to finalize
372 * the report and signal transfer is over.
374 void CloseReport( ReportHeader *agent, ReportStruct *packet ) {
375 if ( agent != NULL) {
377 * Using PacketID of -1 ends reporting
379 packet->packetID = -1;
380 packet->packetLen = 0;
381 ReportPacket( agent, packet );
382 packet->packetID = agent->report.cntDatagrams;
387 * EndReport signifies the agent no longer is interested
388 * in the report. Calls to GetReport will no longer be
391 void EndReport( ReportHeader *agent ) {
392 if ( agent != NULL ) {
393 int index = agent->reporterindex;
394 while ( index != -1 ) {
396 index = agent->reporterindex;
398 agent->agentindex = -1;
401 * Process the report in this thread
403 process_report ( agent );
409 * GetReport is called by the agent after a CloseReport
410 * but before an EndReport to get the stats generated
411 * by the reporter thread.
413 Transfer_Info *GetReport( ReportHeader *agent ) {
414 int index = agent->reporterindex;
415 while ( index != -1 ) {
417 index = agent->reporterindex;
419 return &agent->report.info;
423 * ReportSettings will generate a summary report for
424 * settings being used with Listeners or Clients
426 void ReportSettings( thread_Settings *agent ) {
427 if ( isSettingsReport( agent ) ) {
429 * Create in one big chunk
431 ReportHeader *reporthdr = malloc( sizeof(ReportHeader) );
433 if ( reporthdr != NULL ) {
434 ReporterData *data = &reporthdr->report;
435 data->info.transferID = agent->mSock;
436 data->info.groupID = -1;
437 reporthdr->agentindex = -1;
438 reporthdr->reporterindex = -1;
440 data->mHost = agent->mHost;
441 data->mLocalhost = agent->mLocalhost;
442 data->mode = agent->mReportMode;
443 data->type = SETTINGS_REPORT;
444 data->mBufLen = agent->mBufLen;
445 data->mMSS = agent->mMSS;
446 data->mWinSize = agent->mWinSize;
447 data->flags = agent->flags;
448 data->mProtocol = agent->mProtocol;
449 data->mThreadMode = agent->mThreadMode;
450 data->mPort = agent->mPort;
451 data->info.mFormat = agent->mFormat;
452 data->info.mTTL = agent->mTTL;
453 data->connection.peer = agent->peer;
454 data->connection.size_peer = agent->size_peer;
455 data->connection.local = agent->local;
456 data->connection.size_local = agent->size_local;
460 * Update the ReportRoot to include this report.
462 Condition_Lock( ReportCond );
463 reporthdr->next = ReportRoot;
464 ReportRoot = reporthdr;
465 Condition_Signal( &ReportCond );
466 Condition_Unlock( ReportCond );
469 * Process the report in this thread
471 reporthdr->next = NULL;
472 process_report ( reporthdr );
475 FAIL(1, "Out of Memory!!\n", agent);
481 * ReportServerUDP will generate a report of the UDP
482 * statistics as reported by the server on the client
485 void ReportServerUDP( thread_Settings *agent, server_hdr *server ) {
486 if ( (ntohl(server->flags) & HEADER_VERSION1) != 0 &&
487 isServerReport( agent ) ) {
489 * Create in one big chunk
491 ReportHeader *reporthdr = malloc( sizeof(ReportHeader) );
492 Transfer_Info *stats = &reporthdr->report.info;
494 if ( reporthdr != NULL ) {
495 stats->transferID = agent->mSock;
496 stats->groupID = (agent->multihdr != NULL ? agent->multihdr->groupID
498 reporthdr->agentindex = -1;
499 reporthdr->reporterindex = -1;
501 reporthdr->report.type = SERVER_RELAY_REPORT;
502 reporthdr->report.mode = agent->mReportMode;
503 stats->mFormat = agent->mFormat;
504 stats->jitter = ntohl( server->jitter1 );
505 stats->jitter += ntohl( server->jitter2 ) / (double)rMillion;
506 stats->TotalLen = (((max_size_t) ntohl( server->total_len1 )) << 32) +
507 ntohl( server->total_len2 );
508 stats->startTime = 0;
509 stats->endTime = ntohl( server->stop_sec );
510 stats->endTime += ntohl( server->stop_usec ) / (double)rMillion;
511 stats->cntError = ntohl( server->error_cnt );
512 stats->cntOutofOrder = ntohl( server->outorder_cnt );
513 stats->cntDatagrams = ntohl( server->datagrams );
514 stats->mUDP = (char)kMode_Server;
515 reporthdr->report.connection.peer = agent->local;
516 reporthdr->report.connection.size_peer = agent->size_local;
517 reporthdr->report.connection.local = agent->peer;
518 reporthdr->report.connection.size_local = agent->size_peer;
522 * Update the ReportRoot to include this report.
524 Condition_Lock( ReportCond );
525 reporthdr->next = ReportRoot;
526 ReportRoot = reporthdr;
527 Condition_Signal( &ReportCond );
528 Condition_Unlock( ReportCond );
531 * Process the report in this thread
533 reporthdr->next = NULL;
534 process_report ( reporthdr );
537 FAIL(1, "Out of Memory!!\n", agent);
543 * This function is called only when the reporter thread
544 * This function is the loop that the reporter thread processes
546 void reporter_spawn( thread_Settings *thread ) {
548 // This section allows for safe exiting with Ctrl-C
549 Condition_Lock ( ReportCond );
550 if ( ReportRoot == NULL ) {
551 // Allow main thread to exit if Ctrl-C is received
553 Condition_Wait ( &ReportCond );
554 // Stop main thread from exiting until done with all reports
555 thread_unsetignore();
557 Condition_Unlock ( ReportCond );
560 if ( ReportRoot != NULL ) {
561 ReportHeader *temp = ReportRoot;
562 //Condition_Unlock ( ReportCond );
563 if ( reporter_process_report ( temp ) ) {
564 // This section allows for more reports to be added while
565 // the reporter is processing reports without needing to
566 // stop the reporter or immediately notify it
567 Condition_Lock ( ReportCond );
568 if ( temp == ReportRoot ) {
570 ReportRoot = temp->next;
573 ReportHeader *itr = ReportRoot;
574 while ( itr->next != temp ) {
577 itr->next = temp->next;
579 // finished with report so free it
581 Condition_Unlock ( ReportCond );
582 Condition_Signal( &ReportDoneCond );
586 Condition_Signal( &ReportDoneCond );
589 //Condition_Unlock ( ReportCond );
595 * Used for single threaded reporting
597 void process_report ( ReportHeader *report ) {
598 if ( report != NULL ) {
599 if ( reporter_process_report( report ) ) {
606 * Process reports starting with "reporthdr"
608 int reporter_process_report ( ReportHeader *reporthdr ) {
611 // Recursively process reports
612 if ( reporthdr->next != NULL ) {
613 if ( reporter_process_report( reporthdr->next ) ) {
614 // If we are done with this report then free it
615 ReportHeader *temp = reporthdr->next;
616 reporthdr->next = reporthdr->next->next;
621 if ( (reporthdr->report.type & SETTINGS_REPORT) != 0 ) {
622 reporthdr->report.type &= ~SETTINGS_REPORT;
623 return reporter_print( &reporthdr->report, SETTINGS_REPORT, 1 );
624 } else if ( (reporthdr->report.type & CONNECTION_REPORT) != 0 ) {
625 reporthdr->report.type &= ~CONNECTION_REPORT;
626 reporter_print( &reporthdr->report, CONNECTION_REPORT,
627 (reporthdr->report.type == 0 ? 1 : 0) );
628 if ( reporthdr->multireport != NULL && isMultipleReport( (&reporthdr->report) )) {
629 if ( (reporthdr->multireport->report->type & CONNECTION_REPORT) != 0 ) {
630 reporthdr->multireport->report->type &= ~CONNECTION_REPORT;
631 reporter_print( reporthdr->multireport->report, CONNECTION_REPORT,
632 (reporthdr->report.type == 0 ? 1 : 0) );
635 } else if ( (reporthdr->report.type & SERVER_RELAY_REPORT) != 0 ) {
636 reporthdr->report.type &= ~SERVER_RELAY_REPORT;
637 return reporter_print( &reporthdr->report, SERVER_RELAY_REPORT, 1 );
639 if ( (reporthdr->report.type & TRANSFER_REPORT) != 0 ) {
640 // If there are more packets to process then handle them
641 if ( reporthdr->reporterindex >= 0 ) {
642 // Need to make sure we do not pass the "agent"
643 while ( reporthdr->reporterindex != reporthdr->agentindex - 1 ) {
644 if ( reporthdr->reporterindex == NUM_REPORT_STRUCTS - 1 ) {
645 if ( reporthdr->agentindex == 0 ) {
648 reporthdr->reporterindex = 0;
651 reporthdr->reporterindex++;
653 if ( reporter_handle_packet( reporthdr ) ) {
654 // No more packets to process
655 reporthdr->reporterindex = -1;
660 // If the agent is done with the report then free it
661 if ( reporthdr->agentindex == -1 ) {
669 * Updates connection stats
671 int reporter_handle_packet( ReportHeader *reporthdr ) {
672 ReportStruct *packet = &reporthdr->data[reporthdr->reporterindex];
673 ReporterData *data = &reporthdr->report;
674 Transfer_Info *stats = &reporthdr->report.info;
677 // update received amount and time
678 data->TotalLen += packet->packetLen;
679 data->packetTime = packet->packetTime;
680 data->cntDatagrams++;
682 if (packet->packetID < 0) {
683 // This is the last packet (FIN)
685 if (isConnectionLess(&reporthdr->report)) {
686 // connectionless protocols don't count the last payload
687 if (reporthdr->report.mThreadMode == kMode_Client)
688 data->TotalLen -= packet->packetLen;
690 // connection-oriented protocols dont't count the FIN
691 data->cntDatagrams--;
693 } else if ( packet->packetID != 0 ) {
694 // UDP or DCCP packet
695 double transit, deltaTransit;
697 // from RFC 1889, Real Time Protocol (RTP)
698 // J = J + ( | D(i-1,i) | - J ) / 16
699 transit = TimeDifference( packet->packetTime, packet->sentTime );
700 if ( data->lastTransit != 0.0 ) {
701 deltaTransit = transit - data->lastTransit;
702 if ( deltaTransit < 0.0 ) {
703 deltaTransit = -deltaTransit;
705 stats->jitter += (deltaTransit - stats->jitter) / (16.0);
707 data->lastTransit = transit;
709 // packet loss occured if the datagram numbers aren't sequential
710 if ( packet->packetID != data->PacketID + 1 ) {
711 if ( packet->packetID < data->PacketID + 1 ) {
712 data->cntOutofOrder++;
714 data->cntError += packet->packetID - data->PacketID - 1;
717 // never decrease datagramID (e.g. if we get an out-of-order packet)
718 if ( packet->packetID > data->PacketID ) {
719 data->PacketID = packet->packetID;
722 // Print a report if appropriate
723 return reporter_condprintstats( &reporthdr->report, reporthdr->multireport, finished );
727 * Handles summing of threads
729 void reporter_handle_multiple_reports( MultiHeader *reporthdr, Transfer_Info *stats, int force ) {
730 if ( reporthdr != NULL ) {
731 if ( reporthdr->threads > 1 ) {
733 Transfer_Info *current = NULL;
734 // Search for start Time
735 for ( i = 0; i < NUM_MULTI_SLOTS; i++ ) {
736 current = &reporthdr->data[i];
737 if ( current->startTime == stats->startTime ) {
741 if ( current->startTime != stats->startTime ) {
742 // Find first available
743 for ( i = 0; i < NUM_MULTI_SLOTS; i++ ) {
744 current = &reporthdr->data[i];
745 if ( current->startTime < 0 ) {
749 current->cntDatagrams = stats->cntDatagrams;
750 current->cntError = stats->cntError;
751 current->cntOutofOrder = stats->cntOutofOrder;
752 current->TotalLen = stats->TotalLen;
753 current->mFormat = stats->mFormat;
754 current->endTime = stats->endTime;
755 current->jitter = stats->jitter;
756 current->startTime = stats->startTime;
759 current->cntDatagrams += stats->cntDatagrams;
760 current->cntError += stats->cntError;
761 current->cntOutofOrder += stats->cntOutofOrder;
762 current->TotalLen += stats->TotalLen;
763 current->mFormat = stats->mFormat;
764 if ( current->endTime < stats->endTime ) {
765 current->endTime = stats->endTime;
767 if ( current->jitter < stats->jitter ) {
768 current->jitter = stats->jitter;
771 if ( current->free == reporthdr->threads ) {
772 void *reserved = reporthdr->report->info.reserved_delay;
773 current->free = force;
774 memcpy( &reporthdr->report->info, current, sizeof(Transfer_Info) );
775 current->startTime = -1;
776 reporthdr->report->info.reserved_delay = reserved;
777 reporter_print( reporthdr->report, MULTIPLE_REPORT, force );
785 * Prints reports conditionally
787 int reporter_condprintstats( ReporterData *stats, MultiHeader *multireport, int force ) {
789 stats->info.cntOutofOrder = stats->cntOutofOrder;
790 // assume most of the time out-of-order packets are not
791 // duplicate packets, so conditionally subtract them from the lost packets.
792 stats->info.cntError = stats->cntError;
793 if ( stats->info.cntError > stats->info.cntOutofOrder ) {
794 stats->info.cntError -= stats->info.cntOutofOrder;
796 if (isConnectionLess(stats))
797 stats->info.cntDatagrams = stats->PacketID;
799 stats->info.cntDatagrams = stats->cntDatagrams;
800 stats->info.TotalLen = stats->TotalLen;
801 stats->info.startTime = 0;
802 stats->info.endTime = TimeDifference( stats->packetTime, stats->startTime );
803 stats->info.free = 1;
804 reporter_print( stats, TRANSFER_REPORT, force );
805 if ( isMultipleReport(stats) ) {
806 reporter_handle_multiple_reports( multireport, &stats->info, force );
808 } else while ((stats->intervalTime.tv_sec != 0 ||
809 stats->intervalTime.tv_usec != 0) &&
810 TimeDifference( stats->nextTime,
811 stats->packetTime ) < 0 ) {
812 stats->info.cntOutofOrder = stats->cntOutofOrder - stats->lastOutofOrder;
813 stats->lastOutofOrder = stats->cntOutofOrder;
814 // assume most of the time out-of-order packets are not
815 // duplicate packets, so conditionally subtract them from the lost packets.
816 stats->info.cntError = stats->cntError - stats->lastError;
817 if ( stats->info.cntError > stats->info.cntOutofOrder ) {
818 stats->info.cntError -= stats->info.cntOutofOrder;
820 stats->lastError = stats->cntError;
821 if (isConnectionLess(stats)) {
822 stats->info.cntDatagrams = stats->PacketID - stats->lastDatagrams;
823 stats->lastDatagrams = stats->PacketID;
825 stats->info.cntDatagrams = stats->cntDatagrams - stats->lastDatagrams;
826 stats->lastDatagrams = stats->cntDatagrams;
828 stats->info.TotalLen = stats->TotalLen - stats->lastTotal;
829 stats->lastTotal = stats->TotalLen;
830 stats->info.startTime = stats->info.endTime;
831 stats->info.endTime = TimeDifference( stats->nextTime, stats->startTime );
832 TimeAdd( stats->nextTime, stats->intervalTime );
833 stats->info.free = 0;
834 reporter_print( stats, TRANSFER_REPORT, force );
835 if ( isMultipleReport(stats) ) {
836 reporter_handle_multiple_reports( multireport, &stats->info, force );
843 * This function handles multiple format printing by sending to the
844 * appropriate dispatch function
846 int reporter_print( ReporterData *stats, int type, int end ) {
848 case TRANSFER_REPORT:
849 statistics_reports[stats->mode]( &stats->info );
850 if ( end != 0 && isPrintMSS( stats ) && !isConnectionLess( stats ) ) {
854 case SERVER_RELAY_REPORT:
855 serverstatistics_reports[stats->mode]( &stats->connection, &stats->info );
857 case SETTINGS_REPORT:
858 settings_reports[stats->mode]( stats );
860 case CONNECTION_REPORT:
861 stats->info.reserved_delay = connection_reports[stats->mode](
863 stats->info.transferID );
865 case MULTIPLE_REPORT:
866 multiple_reports[stats->mode]( &stats->info );
869 fprintf( stderr, "Printing type not implemented! No Output\n" );
875 /* -------------------------------------------------------------------
876 * Report the MSS and MTU, given the MSS (or a guess thereof)
877 * This works for connection-oriented protocols only: it expects
878 * the protocol to be either TCP or DCCP and will give error otherwise
879 * ------------------------------------------------------------------- */
881 // compare the MSS against the (MTU - 40) to (MTU - 80) bytes.
882 // 40 byte IP header and somewhat arbitrarily, 40 more bytes of IP options.
884 #define checkMSS_MTU( inMSS, inMTU ) (inMTU-40) >= inMSS && inMSS >= (inMTU-80)
886 void PrintMSS( ReporterData *stats )
888 int inMSS = stats->mProtocol == kProto_TCP
889 ? getsock_tcp_mss( stats->info.transferID )
890 : getsock_dccp_mps( stats->info.transferID );
893 printf( report_mss_unsupported, stats->info.transferID );
898 if ( checkMSS_MTU( inMSS, 1500 ) ) {
901 } else if ( checkMSS_MTU( inMSS, 4352 ) ) {
904 } else if ( checkMSS_MTU( inMSS, 9180 ) ) {
907 } else if ( checkMSS_MTU( inMSS, 65280 ) ) {
910 } else if ( checkMSS_MTU( inMSS, 576 ) ) {
913 printf( warn_no_pathmtu );
916 net = "unknown interface";
920 stats->info.transferID, inMSS, mtu, net );
926 } /* end extern "C" */