]> sjero.net Git - iperf/blob - src/Server.cpp
da7ef146fadca67c222dccf10879d4e2b1069f41
[iperf] / src / Server.cpp
1 /*--------------------------------------------------------------- 
2  * Copyright (c) 1999,2000,2001,2002,2003                              
3  * The Board of Trustees of the University of Illinois            
4  * All Rights Reserved.                                           
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: 
14  *
15  *     
16  * Redistributions of source code must retain the above 
17  * copyright notice, this list of conditions and 
18  * the following disclaimers. 
19  *
20  *     
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. 
25  * 
26  *     
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. 
31  * 
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  * ________________________________________________________________ 
46  *
47  * Server.cpp
48  * by Mark Gates <mgates@nlanr.net>
49  *     Ajay Tirumala (tirumala@ncsa.uiuc.edu>.
50  * -------------------------------------------------------------------
51  * A server thread is initiated for each connection accept() returns.
52  * Handles sending and receiving data, and then closes socket.
53  * Changes to this version : The server can be run as a daemon
54  * ------------------------------------------------------------------- */
55
56 #define HEADERS()
57
58 #include "headers.h"
59 #include "Server.hpp"
60 #include "List.h"
61 #include "Extractor.h"
62 #include "Reporter.h"
63 #include "Locale.h"
64
65 /* -------------------------------------------------------------------
66  * Stores connected socket and socket info.
67  * ------------------------------------------------------------------- */
68
69 Server::Server( thread_Settings *inSettings ) {
70     mSettings = inSettings;
71     mBuf = NULL;
72
73     // initialize buffer
74     mBuf = new char[ mSettings->mBufLen ];
75     FAIL_errno( mBuf == NULL, "No memory for buffer\n", mSettings );
76 }
77
78 /* -------------------------------------------------------------------
79  * Destructor close socket.
80  * ------------------------------------------------------------------- */
81
82 Server::~Server() {
83     if ( mSettings->mSock != INVALID_SOCKET ) {
84         int rc = close( mSettings->mSock );
85         WARN_errno( rc == SOCKET_ERROR, "close" );
86         mSettings->mSock = INVALID_SOCKET;
87     }
88     DELETE_ARRAY( mBuf );
89 }
90
91 void Server::Sig_Int( int inSigno ) {
92 }
93
94 /* ------------------------------------------------------------------- 
95  * Receieve data from the (connected) TCP/UDP socket. 
96  * Sends termination flag several times at the end. 
97  * Does not close the socket. 
98  * ------------------------------------------------------------------- */ 
99 void Server::Run( void ) {
100     long currLen; 
101     struct UDP_datagram* mBuf_UDP  = (struct UDP_datagram*) mBuf; 
102
103     ReportStruct *reportstruct = NULL;
104
105     reportstruct = new ReportStruct;
106     if ( reportstruct != NULL ) {
107         reportstruct->packetID = 0;
108         mSettings->reporthdr = InitReport( mSettings );
109         do {
110             // perform read 
111             currLen = recv( mSettings->mSock, mBuf, mSettings->mBufLen, 0 ); 
112         
113             if ( isUDP( mSettings ) ) {
114                 // read the datagram ID and sentTime out of the buffer 
115                 reportstruct->packetID = ntohl( mBuf_UDP->id ); 
116                 reportstruct->sentTime.tv_sec = ntohl( mBuf_UDP->tv_sec  );
117                 reportstruct->sentTime.tv_usec = ntohl( mBuf_UDP->tv_usec ); 
118             }
119         
120             reportstruct->packetLen = currLen;
121             gettimeofday( &(reportstruct->packetTime), NULL );
122         
123             // terminate when datagram begins with negative index 
124             // the datagram ID should be correct, just negated 
125             if ( reportstruct->packetID < 0 ) {
126                 reportstruct->packetID = -reportstruct->packetID;
127                 currLen = -1; 
128             }
129             ReportPacket( mSettings->reporthdr, reportstruct );
130         } while ( currLen > 0 ); 
131         
132         // stop timing 
133         gettimeofday( &(reportstruct->packetTime), NULL );
134         CloseReport( mSettings->reporthdr, reportstruct );
135         
136         // send a acknowledgement back only if we're NOT receiving multicast 
137         if ( isUDP( mSettings ) && !isMulticast( mSettings ) ) {
138             // send back an acknowledgement of the terminating datagram 
139             write_UDP_AckFIN( ); 
140         }
141     } else {
142         FAIL(1, "Out of memory! Closing server thread\n", mSettings);
143     }
144
145     Mutex_Lock( &clients_mutex );     
146     Iperf_delete( &(mSettings->peer), &clients ); 
147     Mutex_Unlock( &clients_mutex );
148
149     DELETE_PTR( reportstruct );
150     EndReport( mSettings->reporthdr );
151
152 // end Recv 
153
154 /* ------------------------------------------------------------------- 
155  * Send an AckFIN (a datagram acknowledging a FIN) on the socket, 
156  * then select on the socket for some time. If additional datagrams 
157  * come in, probably our AckFIN was lost and they are re-transmitted 
158  * termination datagrams, so re-transmit our AckFIN. 
159  * ------------------------------------------------------------------- */ 
160
161 void Server::write_UDP_AckFIN( ) {
162
163     int rc; 
164
165     fd_set readSet; 
166     FD_ZERO( &readSet ); 
167
168     struct timeval timeout; 
169
170     int count = 0; 
171     while ( count < 10 ) {
172         count++; 
173
174         UDP_datagram *UDP_Hdr;
175         server_hdr *hdr;
176
177         UDP_Hdr = (UDP_datagram*) mBuf;
178
179         if ( mSettings->mBufLen > (int) ( sizeof( UDP_datagram )
180                                           + sizeof( server_hdr ) ) ) {
181             Transfer_Info *stats = GetReport( mSettings->reporthdr );
182             hdr = (server_hdr*) (UDP_Hdr+1);
183
184             hdr->flags        = htonl( HEADER_VERSION1 );
185             hdr->total_len1   = htonl( (long) (stats->TotalLen >> 32) );
186             hdr->total_len2   = htonl( (long) (stats->TotalLen & 0xFFFFFFFF) );
187             hdr->stop_sec     = htonl( (long) stats->endTime );
188             hdr->stop_usec    = htonl( (long)((stats->endTime - (long)stats->endTime)
189                                               * rMillion));
190             hdr->error_cnt    = htonl( stats->cntError );
191             hdr->outorder_cnt = htonl( stats->cntOutofOrder );
192             hdr->datagrams    = htonl( stats->cntDatagrams );
193             hdr->jitter1      = htonl( (long) stats->jitter );
194             hdr->jitter2      = htonl( (long) ((stats->jitter - (long)stats->jitter) 
195                                                * rMillion) );
196
197         }
198
199         // write data 
200         write( mSettings->mSock, mBuf, mSettings->mBufLen ); 
201
202         // wait until the socket is readable, or our timeout expires 
203         FD_SET( mSettings->mSock, &readSet ); 
204         timeout.tv_sec  = 1; 
205         timeout.tv_usec = 0; 
206
207         rc = select( mSettings->mSock+1, &readSet, NULL, NULL, &timeout ); 
208         FAIL_errno( rc == SOCKET_ERROR, "select", mSettings ); 
209
210         if ( rc == 0 ) {
211             // select timed out 
212             return; 
213         } else {
214             // socket ready to read 
215             rc = read( mSettings->mSock, mBuf, mSettings->mBufLen ); 
216             WARN_errno( rc < 0, "read" );
217             if ( rc <= 0 ) {
218                 // Connection closed or errored
219                 // Stop using it.
220                 return;
221             }
222         } 
223     } 
224
225     fprintf( stderr, warn_ack_failed, mSettings->mSock, count ); 
226
227 // end write_UDP_AckFIN 
228