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