]> sjero.net Git - iperf/blob - src/Listener.cpp
Original 2.0.2 iperf sources
[iperf] / src / Listener.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  * Listener.cpp
48  * by Mark Gates <mgates@nlanr.net> 
49  * &  Ajay Tirumala <tirumala@ncsa.uiuc.edu> 
50  * ------------------------------------------------------------------- 
51  * Listener sets up a socket listening on the server host. For each 
52  * connected socket that accept() returns, this creates a Server 
53  * socket and spawns a thread for it. 
54  * 
55  * Changes to the latest version. Listener will run as a daemon 
56  * Multicast Server is now Multi-threaded 
57  * ------------------------------------------------------------------- 
58  * headers 
59  * uses 
60  *   <stdlib.h> 
61  *   <stdio.h> 
62  *   <string.h> 
63  *   <errno.h> 
64  * 
65  *   <sys/types.h> 
66  *   <unistd.h> 
67  * 
68  *   <netdb.h> 
69  *   <netinet/in.h> 
70  *   <sys/socket.h> 
71  * ------------------------------------------------------------------- */ 
72
73
74 #define HEADERS() 
75
76 #include "headers.h" 
77 #include "Listener.hpp"
78 #include "SocketAddr.h"
79 #include "PerfSocket.hpp"
80 #include "List.h"
81 #include "util.h" 
82
83 /* ------------------------------------------------------------------- 
84  * Stores local hostname and socket info. 
85  * ------------------------------------------------------------------- */ 
86
87 Listener::Listener( thread_Settings *inSettings ) {
88
89     mClients = inSettings->mThreads;
90     mBuf = NULL;
91     mSettings = inSettings;
92
93     // initialize buffer
94     mBuf = new char[ mSettings->mBufLen ];
95
96     // open listening socket 
97     Listen( ); 
98     ReportSettings( inSettings );
99
100 } // end Listener 
101
102 /* ------------------------------------------------------------------- 
103  * Delete memory (buffer). 
104  * ------------------------------------------------------------------- */ 
105 Listener::~Listener() {
106     if ( mSettings->mSock != INVALID_SOCKET ) {
107         int rc = close( mSettings->mSock );
108         WARN_errno( rc == SOCKET_ERROR, "close" );
109         mSettings->mSock = INVALID_SOCKET;
110     }
111     DELETE_ARRAY( mBuf );
112 } // end ~Listener 
113
114 /* ------------------------------------------------------------------- 
115  * Listens for connections and starts Servers to handle data. 
116  * For TCP, each accepted connection spawns a Server thread. 
117  * For UDP, handle all data in this thread for Win32 Only, otherwise
118  *          spawn a new Server thread. 
119  * ------------------------------------------------------------------- */ 
120 void Listener::Run( void ) {
121 #ifdef WIN32
122     if ( isUDP( mSettings ) && !isSingleUDP( mSettings ) ) {
123         UDPSingleServer();
124     } else
125 #else
126 #ifdef sun
127     if ( ( isUDP( mSettings ) && 
128            isMulticast( mSettings ) && 
129            !isSingleUDP( mSettings ) ) ||
130          isSingleUDP( mSettings ) ) {
131         UDPSingleServer();
132     } else
133 #else
134     if ( isSingleUDP( mSettings ) ) {
135         UDPSingleServer();
136     } else
137 #endif
138 #endif
139     {
140         bool client = false, UDP = isUDP( mSettings ), mCount = (mSettings->mThreads != 0);
141         thread_Settings *tempSettings = NULL;
142         Iperf_ListEntry *exist, *listtemp;
143         client_hdr* hdr = ( UDP ? (client_hdr*) (((UDP_datagram*)mBuf) + 1) : 
144                                   (client_hdr*) mBuf);
145         
146         if ( mSettings->mHost != NULL ) {
147             client = true;
148             SockAddr_remoteAddr( mSettings );
149         }
150         Settings_Copy( mSettings, &server );
151         server->mThreadMode = kMode_Server;
152     
153     
154         // Accept each packet, 
155         // If there is no existing client, then start  
156         // a new thread to service the new client 
157         // The listener runs in a single thread 
158         // Thread per client model is followed 
159         do {
160             // Get a new socket
161             Accept( server );
162             if ( server->mSock == INVALID_SOCKET ) {
163                 break;
164             }
165             if ( sInterupted != 0 ) {
166                 close( server->mSock );
167                 break;
168             }
169             // Reset Single Client Stuff
170             if ( isSingleClient( mSettings ) && clients == NULL ) {
171                 mSettings->peer = server->peer;
172                 mClients--;
173                 client = true;
174                 // Once all the server threads exit then quit
175                 // Must keep going in case this client sends
176                 // more streams
177                 if ( mClients == 0 ) {
178                     thread_release_nonterm( 0 );
179                     mClients = 1;
180                 }
181             }
182             // Verify that it is allowed
183             if ( client ) {
184                 if ( !SockAddr_Hostare_Equal( (sockaddr*) &mSettings->peer, 
185                                               (sockaddr*) &server->peer ) ) {
186                     // Not allowed try again
187                     close( server->mSock );
188                     if ( isUDP( mSettings ) ) {
189                         mSettings->mSock = -1;
190                         Listen();
191                     }
192                     continue;
193                 }
194             }
195     
196             // Create an entry for the connection list
197             listtemp = new Iperf_ListEntry;
198             memcpy(listtemp, &server->peer, sizeof(iperf_sockaddr));
199             listtemp->next = NULL;
200     
201             // See if we need to do summing
202             Mutex_Lock( &clients_mutex );
203             exist = Iperf_hostpresent( &server->peer, clients); 
204     
205             if ( exist != NULL ) {
206                 // Copy group ID
207                 listtemp->holder = exist->holder;
208                 server->multihdr = exist->holder;
209             } else {
210                 server->mThreads = 0;
211                 Mutex_Lock( &groupCond );
212                 groupID--;
213                 listtemp->holder = InitMulti( server, groupID );
214                 server->multihdr = listtemp->holder;
215                 Mutex_Unlock( &groupCond );
216             }
217     
218             // Store entry in connection list
219             Iperf_pushback( listtemp, &clients ); 
220             Mutex_Unlock( &clients_mutex ); 
221     
222             tempSettings = NULL;
223             if ( !isCompat( mSettings ) && !isMulticast( mSettings ) ) {
224                 if ( !UDP ) {
225                     // TCP does not have the info yet
226                     if ( recv( server->mSock, (char*)hdr, sizeof(client_hdr), 0) > 0 ) {
227                         Settings_GenerateClientSettings( server, &tempSettings, 
228                                                           hdr );
229                     }
230                 } else {
231                     Settings_GenerateClientSettings( server, &tempSettings, 
232                                                       hdr );
233                 }
234             }
235     
236     
237             if ( tempSettings != NULL ) {
238                 client_init( tempSettings );
239                 if ( tempSettings->mMode == kTest_DualTest ) {
240 #ifdef HAVE_THREAD
241                     server->runNow =  tempSettings;
242 #else
243                     server->runNext = tempSettings;
244 #endif
245                 } else {
246                     server->runNext =  tempSettings;
247                 }
248             }
249     
250             // Start the server
251 #if defined(WIN32) && defined(HAVE_THREAD)
252             if ( UDP ) {
253                 // WIN32 does bad UDP handling so run single threaded
254                 if ( server->runNow != NULL ) {
255                     thread_start( server->runNow );
256                 }
257                 server_spawn( server );
258                 if ( server->runNext != NULL ) {
259                     thread_start( server->runNext );
260                 }
261             } else
262 #endif
263             thread_start( server );
264     
265             // create a new socket
266             if ( UDP ) {
267                 mSettings->mSock = -1; 
268                 Listen( );
269             }
270     
271             // Prep for next connection
272             if ( !isSingleClient( mSettings ) ) {
273                 mClients--;
274             }
275             Settings_Copy( mSettings, &server );
276             server->mThreadMode = kMode_Server;
277         } while ( !sInterupted && (!mCount || ( mCount && mClients > 0 )) );
278     
279         Settings_Destroy( server );
280     }
281 } // end Run 
282
283 /* -------------------------------------------------------------------
284  * Setup a socket listening on a port.
285  * For TCP, this calls bind() and listen().
286  * For UDP, this just calls bind().
287  * If inLocalhost is not null, bind to that address rather than the
288  * wildcard server address, specifying what incoming interface to
289  * accept connections on.
290  * ------------------------------------------------------------------- */
291 void Listener::Listen( ) {
292     int rc;
293
294     SockAddr_localAddr( mSettings );
295
296     // create an internet TCP socket
297     int type = (isUDP( mSettings )  ?  SOCK_DGRAM  :  SOCK_STREAM);
298     int domain = (SockAddr_isIPv6( &mSettings->local ) ? 
299 #ifdef HAVE_IPV6
300                   AF_INET6
301 #else
302                   AF_INET
303 #endif
304                   : AF_INET);
305
306 #ifdef WIN32
307     if ( SockAddr_isMulticast( &mSettings->local ) ) {
308         // Multicast on Win32 requires special handling
309         mSettings->mSock = WSASocket( domain, type, 0, 0, 0, WSA_FLAG_MULTIPOINT_C_LEAF | WSA_FLAG_MULTIPOINT_D_LEAF );
310         WARN_errno( mSettings->mSock == INVALID_SOCKET, "socket" );
311
312     } else
313 #endif
314     {
315         mSettings->mSock = socket( domain, type, 0 );
316         WARN_errno( mSettings->mSock == INVALID_SOCKET, "socket" );
317     } 
318
319     SetSocketOptions( mSettings );
320
321     // reuse the address, so we can run if a former server was killed off
322     int boolean = 1;
323     Socklen_t len = sizeof(boolean);
324     setsockopt( mSettings->mSock, SOL_SOCKET, SO_REUSEADDR, (char*) &boolean, len );
325
326     // bind socket to server address
327 #ifdef WIN32
328     if ( SockAddr_isMulticast( &mSettings->local ) ) {
329         // Multicast on Win32 requires special handling
330         rc = WSAJoinLeaf( mSettings->mSock, (sockaddr*) &mSettings->local, mSettings->size_local,0,0,0,0,JL_BOTH);
331         WARN_errno( rc == SOCKET_ERROR, "WSAJoinLeaf (aka bind)" );
332     } else
333 #endif
334     {
335         rc = bind( mSettings->mSock, (sockaddr*) &mSettings->local, mSettings->size_local );
336         WARN_errno( rc == SOCKET_ERROR, "bind" );
337     }
338     // listen for connections (TCP only).
339     // default backlog traditionally 5
340     if ( !isUDP( mSettings ) ) {
341         rc = listen( mSettings->mSock, 5 );
342         WARN_errno( rc == SOCKET_ERROR, "listen" );
343     }
344
345 #ifndef WIN32
346     // if multicast, join the group
347     if ( SockAddr_isMulticast( &mSettings->local ) ) {
348         McastJoin( );
349     }
350 #endif
351 } // end Listen
352
353 /* -------------------------------------------------------------------
354  * Joins the multicast group, with the default interface.
355  * ------------------------------------------------------------------- */
356
357 void Listener::McastJoin( ) {
358 #ifdef HAVE_MULTICAST
359     if ( !SockAddr_isIPv6( &mSettings->local ) ) {
360         struct ip_mreq mreq;
361
362         memcpy( &mreq.imr_multiaddr, SockAddr_get_in_addr( &mSettings->local ), 
363                 sizeof(mreq.imr_multiaddr));
364
365         mreq.imr_interface.s_addr = htonl( INADDR_ANY );
366
367         int rc = setsockopt( mSettings->mSock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
368                              (char*) &mreq, sizeof(mreq));
369         WARN_errno( rc == SOCKET_ERROR, "multicast join" );
370     }
371 #ifdef HAVE_IPV6_MULTICAST
372       else {
373         struct ipv6_mreq mreq;
374
375         memcpy( &mreq.ipv6mr_multiaddr, SockAddr_get_in6_addr( &mSettings->local ), 
376                 sizeof(mreq.ipv6mr_multiaddr));
377
378         mreq.ipv6mr_interface = 0;
379
380         int rc = setsockopt( mSettings->mSock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
381                              (char*) &mreq, sizeof(mreq));
382         WARN_errno( rc == SOCKET_ERROR, "multicast join" );
383     }
384 #endif
385 #endif
386 }
387 // end McastJoin
388
389 /* -------------------------------------------------------------------
390  * Sets the Multicast TTL for outgoing packets.
391  * ------------------------------------------------------------------- */
392
393 void Listener::McastSetTTL( int val ) {
394 #ifdef HAVE_MULTICAST
395     if ( !SockAddr_isIPv6( &mSettings->local ) ) {
396         int rc = setsockopt( mSettings->mSock, IPPROTO_IP, IP_MULTICAST_TTL,
397                              (char*) &val, sizeof(val));
398         WARN_errno( rc == SOCKET_ERROR, "multicast ttl" );
399     }
400 #ifdef HAVE_IPV6_MULTICAST
401       else {
402         int rc = setsockopt( mSettings->mSock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
403                              (char*) &val, sizeof(val));
404         WARN_errno( rc == SOCKET_ERROR, "multicast ttl" );
405     }
406 #endif
407 #endif
408 }
409 // end McastSetTTL
410
411 /* -------------------------------------------------------------------
412  * After Listen() has setup mSock, this will block
413  * until a new connection arrives.
414  * ------------------------------------------------------------------- */
415
416 void Listener::Accept( thread_Settings *server ) {
417
418     server->size_peer = sizeof(iperf_sockaddr); 
419     if ( isUDP( server ) ) {
420         /* ------------------------------------------------------------------- 
421          * Do the equivalent of an accept() call for UDP sockets. This waits 
422          * on a listening UDP socket until we get a datagram. 
423          * ------------------------------------------------------------------- */
424         int rc;
425         Iperf_ListEntry *exist;
426         int32_t datagramID;
427         server->mSock = INVALID_SOCKET;
428         while ( server->mSock == INVALID_SOCKET ) {
429             rc = recvfrom( mSettings->mSock, mBuf, mSettings->mBufLen, 0, 
430                            (struct sockaddr*) &server->peer, &server->size_peer );
431             FAIL_errno( rc == SOCKET_ERROR, "recvfrom", mSettings );
432
433             Mutex_Lock( &clients_mutex );
434     
435             // Handle connection for UDP sockets.
436             exist = Iperf_present( &server->peer, clients);
437             datagramID = ntohl( ((UDP_datagram*) mBuf)->id ); 
438             if ( exist == NULL && datagramID >= 0 ) {
439                 server->mSock = mSettings->mSock;
440                 int rc = connect( server->mSock, (struct sockaddr*) &server->peer,
441                                   server->size_peer );
442                 FAIL_errno( rc == SOCKET_ERROR, "connect UDP", mSettings );
443             } else {
444                 server->mSock = INVALID_SOCKET;
445             }
446             Mutex_Unlock( &clients_mutex );
447         }
448     } else {
449         // Handles interupted accepts. Returns the newly connected socket.
450         server->mSock = INVALID_SOCKET;
451     
452         while ( server->mSock == INVALID_SOCKET ) {
453             // accept a connection
454             server->mSock = accept( mSettings->mSock, 
455                                     (sockaddr*) &server->peer, &server->size_peer );
456             if ( server->mSock == INVALID_SOCKET &&  errno == EINTR ) {
457                 continue;
458             }
459         }
460     }
461     server->size_local = sizeof(iperf_sockaddr); 
462     getsockname( server->mSock, (sockaddr*) &server->local, 
463                  &server->size_local );
464 } // end Accept
465
466 void Listener::UDPSingleServer( ) {
467     
468     bool client = false, UDP = isUDP( mSettings ), mCount = (mSettings->mThreads != 0);
469     thread_Settings *tempSettings = NULL;
470     Iperf_ListEntry *exist, *listtemp;
471     int rc;
472     int32_t datagramID;
473     client_hdr* hdr = ( UDP ? (client_hdr*) (((UDP_datagram*)mBuf) + 1) : 
474                               (client_hdr*) mBuf);
475     ReportStruct *reportstruct = new ReportStruct;
476     
477     if ( mSettings->mHost != NULL ) {
478         client = true;
479         SockAddr_remoteAddr( mSettings );
480     }
481     Settings_Copy( mSettings, &server );
482     server->mThreadMode = kMode_Server;
483
484
485     // Accept each packet, 
486     // If there is no existing client, then start  
487     // a new report to service the new client 
488     // The listener runs in a single thread 
489     Mutex_Lock( &clients_mutex );
490     do {
491         // Get next packet
492         while ( sInterupted == 0) {
493             server->size_peer = sizeof( iperf_sockaddr );
494             rc = recvfrom( mSettings->mSock, mBuf, mSettings->mBufLen, 0, 
495                            (struct sockaddr*) &server->peer, &server->size_peer );
496             WARN_errno( rc == SOCKET_ERROR, "recvfrom" );
497             if ( rc == SOCKET_ERROR ) {
498                 return;
499             }
500         
501         
502             // Handle connection for UDP sockets.
503             exist = Iperf_present( &server->peer, clients);
504             datagramID = ntohl( ((UDP_datagram*) mBuf)->id ); 
505             if ( datagramID >= 0 ) {
506                 if ( exist != NULL ) {
507                     // read the datagram ID and sentTime out of the buffer 
508                     reportstruct->packetID = datagramID; 
509                     reportstruct->sentTime.tv_sec = ntohl( ((UDP_datagram*) mBuf)->tv_sec  );
510                     reportstruct->sentTime.tv_usec = ntohl( ((UDP_datagram*) mBuf)->tv_usec ); 
511         
512                     reportstruct->packetLen = rc;
513                     gettimeofday( &(reportstruct->packetTime), NULL );
514         
515                     ReportPacket( exist->server->reporthdr, reportstruct );
516                 } else {
517                     Mutex_Lock( &groupCond );
518                     groupID--;
519                     server->mSock = -groupID;
520                     Mutex_Unlock( &groupCond );
521                     server->size_local = sizeof(iperf_sockaddr); 
522                     getsockname( mSettings->mSock, (sockaddr*) &server->local, 
523                                  &server->size_local );
524                     break;
525                 }
526             } else {
527                 if ( exist != NULL ) {
528                     // read the datagram ID and sentTime out of the buffer 
529                     reportstruct->packetID = -datagramID; 
530                     reportstruct->sentTime.tv_sec = ntohl( ((UDP_datagram*) mBuf)->tv_sec  );
531                     reportstruct->sentTime.tv_usec = ntohl( ((UDP_datagram*) mBuf)->tv_usec ); 
532         
533                     reportstruct->packetLen = rc;
534                     gettimeofday( &(reportstruct->packetTime), NULL );
535         
536                     ReportPacket( exist->server->reporthdr, reportstruct );
537                     // stop timing 
538                     gettimeofday( &(reportstruct->packetTime), NULL );
539                     CloseReport( exist->server->reporthdr, reportstruct );
540         
541                     if ( rc > (int) ( sizeof( UDP_datagram )
542                                                       + sizeof( server_hdr ) ) ) {
543                         UDP_datagram *UDP_Hdr;
544                         server_hdr *hdr;
545         
546                         UDP_Hdr = (UDP_datagram*) mBuf;
547                         Transfer_Info *stats = GetReport( exist->server->reporthdr );
548                         hdr = (server_hdr*) (UDP_Hdr+1);
549         
550                         hdr->flags        = htonl( HEADER_VERSION1 );
551                         hdr->total_len1   = htonl( (long) (stats->TotalLen >> 32) );
552                         hdr->total_len2   = htonl( (long) (stats->TotalLen & 0xFFFFFFFF) );
553                         hdr->stop_sec     = htonl( (long) stats->endTime );
554                         hdr->stop_usec    = htonl( (long)((stats->endTime - (long)stats->endTime)
555                                                           * rMillion));
556                         hdr->error_cnt    = htonl( stats->cntError );
557                         hdr->outorder_cnt = htonl( stats->cntOutofOrder );
558                         hdr->datagrams    = htonl( stats->cntDatagrams );
559                         hdr->jitter1      = htonl( (long) stats->jitter );
560                         hdr->jitter2      = htonl( (long) ((stats->jitter - (long)stats->jitter) 
561                                                            * rMillion) );
562         
563                     }
564                     EndReport( exist->server->reporthdr );
565                     exist->server->reporthdr = NULL;
566                     Iperf_delete( &(exist->server->peer), &clients );
567                 } else if ( rc > (int) ( sizeof( UDP_datagram )
568                                                   + sizeof( server_hdr ) ) ) {
569                     UDP_datagram *UDP_Hdr;
570                     server_hdr *hdr;
571         
572                     UDP_Hdr = (UDP_datagram*) mBuf;
573                     hdr = (server_hdr*) (UDP_Hdr+1);
574                     hdr->flags = htonl( 0 );
575                 }
576                 sendto( mSettings->mSock, mBuf, mSettings->mBufLen, 0,
577                         (struct sockaddr*) &server->peer, server->size_peer);
578             }
579         }
580         if ( server->mSock == INVALID_SOCKET ) {
581             break;
582         }
583         if ( sInterupted != 0 ) {
584             close( server->mSock );
585             break;
586         }
587         // Reset Single Client Stuff
588         if ( isSingleClient( mSettings ) && clients == NULL ) {
589             mSettings->peer = server->peer;
590             mClients--;
591             client = true;
592             // Once all the server threads exit then quit
593             // Must keep going in case this client sends
594             // more streams
595             if ( mClients == 0 ) {
596                 thread_release_nonterm( 0 );
597                 mClients = 1;
598             }
599         }
600         // Verify that it is allowed
601         if ( client ) {
602             if ( !SockAddr_Hostare_Equal( (sockaddr*) &mSettings->peer, 
603                                           (sockaddr*) &server->peer ) ) {
604                 // Not allowed try again
605                 connect( mSettings->mSock, 
606                          (sockaddr*) &server->peer, 
607                          server->size_peer );
608                 close( mSettings->mSock );
609                 mSettings->mSock = -1; 
610                 Listen( );
611                 continue;
612             }
613         }
614
615         // Create an entry for the connection list
616         listtemp = new Iperf_ListEntry;
617         memcpy(listtemp, &server->peer, sizeof(iperf_sockaddr));
618         listtemp->server = server;
619         listtemp->next = NULL;
620
621         // See if we need to do summing
622         exist = Iperf_hostpresent( &server->peer, clients); 
623
624         if ( exist != NULL ) {
625             // Copy group ID
626             listtemp->holder = exist->holder;
627             server->multihdr = exist->holder;
628         } else {
629             server->mThreads = 0;
630             Mutex_Lock( &groupCond );
631             groupID--;
632             listtemp->holder = InitMulti( server, groupID );
633             server->multihdr = listtemp->holder;
634             Mutex_Unlock( &groupCond );
635         }
636
637         // Store entry in connection list
638         Iperf_pushback( listtemp, &clients ); 
639
640         tempSettings = NULL;
641         if ( !isCompat( mSettings ) && !isMulticast( mSettings ) ) {
642             Settings_GenerateClientSettings( server, &tempSettings, 
643                                               hdr );
644         }
645
646
647         if ( tempSettings != NULL ) {
648             client_init( tempSettings );
649             if ( tempSettings->mMode == kTest_DualTest ) {
650 #ifdef HAVE_THREAD
651                 thread_start( tempSettings );
652 #else
653                 server->runNext = tempSettings;
654 #endif
655             } else {
656                 server->runNext =  tempSettings;
657             }
658         }
659         server->reporthdr = InitReport( server );
660
661         // Prep for next connection
662         if ( !isSingleClient( mSettings ) ) {
663             mClients--;
664         }
665         Settings_Copy( mSettings, &server );
666         server->mThreadMode = kMode_Server;
667     } while ( !sInterupted && (!mCount || ( mCount && mClients > 0 )) );
668     Mutex_Unlock( &clients_mutex );
669
670     Settings_Destroy( server );
671 }
672
673 /* -------------------------------------------------------------------- 
674  * Run the server as a daemon  
675  * --------------------------------------------------------------------*/ 
676
677 void Listener::runAsDaemon(const char *pname, int facility) {
678 #ifndef WIN32 
679     pid_t pid; 
680
681     /* Create a child process & if successful, exit from the parent process */ 
682     if ( (pid = fork()) == -1 ) {
683         fprintf( stderr, "error in first child create\n");     
684         exit(0); 
685     } else if ( pid != 0 ) {
686         exit(0); 
687     }
688
689     /* Try becoming the session leader, once the parent exits */
690     if ( setsid() == -1 ) {           /* Become the session leader */ 
691         fprintf( stderr, "Cannot change the session group leader\n"); 
692     } else {
693     } 
694     signal(SIGHUP,SIG_IGN); 
695
696
697     /* Now fork() and get released from the terminal */  
698     if ( (pid = fork()) == -1 ) {
699         fprintf( stderr, "error\n");   
700         exit(0); 
701     } else if ( pid != 0 ) {
702         exit(0); 
703     }
704
705     chdir("."); 
706     fprintf( stderr, "Running Iperf Server as a daemon\n"); 
707     fprintf( stderr, "The Iperf daemon process ID : %d\n",((int)getpid())); 
708     fflush(stderr); 
709
710     fclose(stdin); 
711 #else 
712     fprintf( stderr, "Use the precompiled windows version for service (daemon) option\n"); 
713 #endif  
714
715 }
716