]> sjero.net Git - iperf/blob - src/Server.cpp
DCCP support for iperf
[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  * Receive data from the (connected) 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 dgram_record* dgram_rec  = (struct dgram_record*) 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 ( isPacketOriented( mSettings ) ) {
114                 // read the datagram ID and sentTime out of the buffer 
115                 reportstruct->packetID = ntohl( dgram_rec->id );
116                 reportstruct->sentTime.tv_sec = ntohl( dgram_rec->tv_sec  );
117                 reportstruct->sentTime.tv_usec = ntohl( dgram_rec->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                 // Don't count the FIN message in connection-oriented protocols.
128                 if (!isConnectionLess(mSettings))
129                    break;
130                 currLen = -1; 
131             }
132             ReportPacket( mSettings->reporthdr, reportstruct );
133         } while ( currLen > 0 ); 
134         
135         // stop timing 
136         gettimeofday( &(reportstruct->packetTime), NULL );
137         CloseReport( mSettings->reporthdr, reportstruct );
138         
139         // send back an acknowledgement of the terminating datagram
140         // send a acknowledgement back only if we're NOT receiving multicast 
141         if ( isPacketOriented( mSettings ) && !isMulticast( mSettings ) )
142             write_dgram_AckFin( );
143     } else {
144         FAIL(1, "Out of memory! Closing server thread\n", mSettings);
145     }
146
147     Mutex_Lock( &clients_mutex );     
148     Iperf_delete( &(mSettings->peer), &clients ); 
149     Mutex_Unlock( &clients_mutex );
150
151     DELETE_PTR( reportstruct );
152     EndReport( mSettings->reporthdr );
153
154 // end Recv 
155
156 /* ------------------------------------------------------------------- 
157  * Send an AckFIN (a datagram acknowledging a FIN) on the socket, 
158  * then select on the socket for some time. If additional datagrams 
159  * come in, probably our AckFIN was lost and they are re-transmitted 
160  * termination datagrams, so re-transmit our AckFIN. 
161  * ------------------------------------------------------------------- */ 
162
163 void Server::write_dgram_AckFin( ) {
164
165     int rc; 
166
167     fd_set readSet; 
168     FD_ZERO( &readSet ); 
169
170     struct timeval timeout; 
171
172     int count = 0; 
173     while ( count < 10 ) {
174         count++; 
175
176         dgram_record *dgram_rec;
177         server_hdr *hdr;
178
179         dgram_rec = (dgram_record*) mBuf;
180
181         if ( mSettings->mBufLen > (int) ( sizeof( dgram_record )
182                                           + sizeof( server_hdr ) ) ) {
183             Transfer_Info *stats = GetReport( mSettings->reporthdr );
184             hdr = (server_hdr*) (dgram_rec+1);
185
186             hdr->flags        = htonl( HEADER_VERSION1 );
187             hdr->total_len1   = htonl( (long) (stats->TotalLen >> 32) );
188             hdr->total_len2   = htonl( (long) (stats->TotalLen & 0xFFFFFFFF) );
189             hdr->stop_sec     = htonl( (long) stats->endTime );
190             hdr->stop_usec    = htonl( (long)((stats->endTime - (long)stats->endTime)
191                                               * rMillion));
192             hdr->error_cnt    = htonl( stats->cntError );
193             hdr->outorder_cnt = htonl( stats->cntOutofOrder );
194             hdr->datagrams    = htonl( stats->cntDatagrams );
195             hdr->jitter1      = htonl( (long) stats->jitter );
196             hdr->jitter2      = htonl( (long) ((stats->jitter - (long)stats->jitter) 
197                                                * rMillion) );
198
199         }
200
201         // write data 
202         write( mSettings->mSock, mBuf, mSettings->mBufLen ); 
203
204         // wait until the socket is readable, or our timeout expires 
205         FD_SET( mSettings->mSock, &readSet ); 
206         timeout.tv_sec  = 1; 
207         timeout.tv_usec = 0; 
208
209         rc = select( mSettings->mSock+1, &readSet, NULL, NULL, &timeout ); 
210         FAIL_errno( rc == SOCKET_ERROR, "select", mSettings ); 
211
212         if ( rc == 0 ) {
213             // select timed out 
214             return; 
215         } else {
216             // socket ready to read 
217             rc = read( mSettings->mSock, mBuf, mSettings->mBufLen ); 
218             WARN_errno( rc < 0, "read" );
219             if ( rc <= 0 ) {
220                 // Connection closed or errored
221                 // Stop using it.
222                 return;
223             }
224         } 
225     } 
226
227     fprintf( stderr, warn_ack_failed, mSettings->mSock, count ); 
228