📄 listener.cpp
字号:
/*--------------------------------------------------------------- * Copyright (c) 1999,2000,2001,2002,2003 * The Board of Trustees of the University of Illinois * All Rights Reserved. *--------------------------------------------------------------- * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software (Iperf) and associated * documentation files (the "Software"), to deal in the Software * without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, * sublicense, and/or sell copies of the Software, and to permit * persons to whom the Software is furnished to do * so, subject to the following conditions: * * * Redistributions of source code must retain the above * copyright notice, this list of conditions and * the following disclaimers. * * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimers in the documentation and/or other materials * provided with the distribution. * * * Neither the names of the University of Illinois, NCSA, * nor the names of its contributors may be used to endorse * or promote products derived from this Software without * specific prior written permission. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE CONTIBUTORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ________________________________________________________________ * National Laboratory for Applied Network Research * National Center for Supercomputing Applications * University of Illinois at Urbana-Champaign * http://www.ncsa.uiuc.edu * ________________________________________________________________ * * Listener.cpp * by Mark Gates <mgates@nlanr.net> * & Ajay Tirumala <tirumala@ncsa.uiuc.edu> * ------------------------------------------------------------------- * Listener sets up a socket listening on the server host. For each * connected socket that accept() returns, this creates a Server * socket and spawns a thread for it. * * Changes to the latest version. Listener will run as a daemon * Multicast Server is now Multi-threaded * ------------------------------------------------------------------- * headers * uses * <stdlib.h> * <stdio.h> * <string.h> * <errno.h> * * <sys/types.h> * <unistd.h> * * <netdb.h> * <netinet/in.h> * <sys/socket.h> * ------------------------------------------------------------------- */ #define HEADERS() #include "headers.h" #include "Listener.hpp"#include "SocketAddr.h"#include "PerfSocket.hpp"#include "List.h"#include "util.h" /* ------------------------------------------------------------------- * Stores local hostname and socket info. * ------------------------------------------------------------------- */ Listener::Listener( thread_Settings *inSettings ) { mClients = inSettings->mThreads; mBuf = NULL; mSettings = inSettings; // initialize buffer mBuf = new char[ mSettings->mBufLen ]; // open listening socket Listen( ); ReportSettings( inSettings );} // end Listener /* ------------------------------------------------------------------- * Delete memory (buffer). * ------------------------------------------------------------------- */ Listener::~Listener() { if ( mSettings->mSock != INVALID_SOCKET ) { int rc = close( mSettings->mSock ); WARN_errno( rc == SOCKET_ERROR, "close" ); mSettings->mSock = INVALID_SOCKET; } DELETE_ARRAY( mBuf );} // end ~Listener /* ------------------------------------------------------------------- * Listens for connections and starts Servers to handle data. * For TCP, each accepted connection spawns a Server thread. * For UDP, handle all data in this thread for Win32 Only, otherwise * spawn a new Server thread. * ------------------------------------------------------------------- */ void Listener::Run( void ) {#ifdef WIN32 if ( isUDP( mSettings ) && !isSingleUDP( mSettings ) ) { UDPSingleServer(); } else#else#ifdef sun if ( ( isUDP( mSettings ) && isMulticast( mSettings ) && !isSingleUDP( mSettings ) ) || isSingleUDP( mSettings ) ) { UDPSingleServer(); } else#else if ( isSingleUDP( mSettings ) ) { UDPSingleServer(); } else#endif#endif { bool client = false, UDP = isUDP( mSettings ), mCount = (mSettings->mThreads != 0); thread_Settings *tempSettings = NULL; Iperf_ListEntry *exist, *listtemp; client_hdr* hdr = ( UDP ? (client_hdr*) (((UDP_datagram*)mBuf) + 1) : (client_hdr*) mBuf); if ( mSettings->mHost != NULL ) { client = true; SockAddr_remoteAddr( mSettings ); } Settings_Copy( mSettings, &server ); server->mThreadMode = kMode_Server; // Accept each packet, // If there is no existing client, then start // a new thread to service the new client // The listener runs in a single thread // Thread per client model is followed do { // Get a new socket Accept( server ); if ( server->mSock == INVALID_SOCKET ) { break; } if ( sInterupted != 0 ) { close( server->mSock ); break; } // Reset Single Client Stuff if ( isSingleClient( mSettings ) && clients == NULL ) { mSettings->peer = server->peer; mClients--; client = true; // Once all the server threads exit then quit // Must keep going in case this client sends // more streams if ( mClients == 0 ) { thread_release_nonterm( 0 ); mClients = 1; } } // Verify that it is allowed if ( client ) { if ( !SockAddr_Hostare_Equal( (sockaddr*) &mSettings->peer, (sockaddr*) &server->peer ) ) { // Not allowed try again close( server->mSock ); if ( isUDP( mSettings ) ) { mSettings->mSock = -1; Listen(); } continue; } } // Create an entry for the connection list listtemp = new Iperf_ListEntry; memcpy(listtemp, &server->peer, sizeof(iperf_sockaddr)); listtemp->next = NULL; // See if we need to do summing Mutex_Lock( &clients_mutex ); exist = Iperf_hostpresent( &server->peer, clients); if ( exist != NULL ) { // Copy group ID listtemp->holder = exist->holder; server->multihdr = exist->holder; } else { server->mThreads = 0; Mutex_Lock( &groupCond ); groupID--; listtemp->holder = InitMulti( server, groupID ); server->multihdr = listtemp->holder; Mutex_Unlock( &groupCond ); } // Store entry in connection list Iperf_pushback( listtemp, &clients ); Mutex_Unlock( &clients_mutex ); tempSettings = NULL; if ( !isCompat( mSettings ) && !isMulticast( mSettings ) ) { if ( !UDP ) { // TCP does not have the info yet if ( recv( server->mSock, (char*)hdr, sizeof(client_hdr), 0) > 0 ) { Settings_GenerateClientSettings( server, &tempSettings, hdr ); } } else { Settings_GenerateClientSettings( server, &tempSettings, hdr ); } } if ( tempSettings != NULL ) { client_init( tempSettings ); if ( tempSettings->mMode == kTest_DualTest ) {#ifdef HAVE_THREAD server->runNow = tempSettings;#else server->runNext = tempSettings;#endif } else { server->runNext = tempSettings; } } // Start the server#if defined(WIN32) && defined(HAVE_THREAD) if ( UDP ) { // WIN32 does bad UDP handling so run single threaded if ( server->runNow != NULL ) { thread_start( server->runNow ); } server_spawn( server ); if ( server->runNext != NULL ) { thread_start( server->runNext ); } } else#endif thread_start( server ); // create a new socket if ( UDP ) { mSettings->mSock = -1; Listen( ); } // Prep for next connection if ( !isSingleClient( mSettings ) ) { mClients--; } Settings_Copy( mSettings, &server ); server->mThreadMode = kMode_Server; } while ( !sInterupted && (!mCount || ( mCount && mClients > 0 )) ); Settings_Destroy( server ); }} // end Run /* ------------------------------------------------------------------- * Setup a socket listening on a port. * For TCP, this calls bind() and listen(). * For UDP, this just calls bind(). * If inLocalhost is not null, bind to that address rather than the * wildcard server address, specifying what incoming interface to * accept connections on. * ------------------------------------------------------------------- */void Listener::Listen( ) { int rc; SockAddr_localAddr( mSettings ); // create an internet TCP socket int type = (isUDP( mSettings ) ? SOCK_DGRAM : SOCK_STREAM); int domain = (SockAddr_isIPv6( &mSettings->local ) ? #ifdef HAVE_IPV6 AF_INET6#else AF_INET#endif : AF_INET);#ifdef WIN32 if ( SockAddr_isMulticast( &mSettings->local ) ) { // Multicast on Win32 requires special handling mSettings->mSock = WSASocket( domain, type, 0, 0, 0, WSA_FLAG_MULTIPOINT_C_LEAF | WSA_FLAG_MULTIPOINT_D_LEAF ); WARN_errno( mSettings->mSock == INVALID_SOCKET, "socket" ); } else#endif { mSettings->mSock = socket( domain, type, 0 ); WARN_errno( mSettings->mSock == INVALID_SOCKET, "socket" ); } SetSocketOptions( mSettings ); // reuse the address, so we can run if a former server was killed off int boolean = 1; Socklen_t len = sizeof(boolean); setsockopt( mSettings->mSock, SOL_SOCKET, SO_REUSEADDR, (char*) &boolean, len ); // bind socket to server address#ifdef WIN32 if ( SockAddr_isMulticast( &mSettings->local ) ) { // Multicast on Win32 requires special handling rc = WSAJoinLeaf( mSettings->mSock, (sockaddr*) &mSettings->local, mSettings->size_local,0,0,0,0,JL_BOTH); WARN_errno( rc == SOCKET_ERROR, "WSAJoinLeaf (aka bind)" ); } else#endif { rc = bind( mSettings->mSock, (sockaddr*) &mSettings->local, mSettings->size_local ); WARN_errno( rc == SOCKET_ERROR, "bind" ); } // listen for connections (TCP only). // default backlog traditionally 5 if ( !isUDP( mSettings ) ) { rc = listen( mSettings->mSock, 5 ); WARN_errno( rc == SOCKET_ERROR, "listen" ); }#ifndef WIN32 // if multicast, join the group if ( SockAddr_isMulticast( &mSettings->local ) ) { McastJoin( ); }#endif} // end Listen/* ------------------------------------------------------------------- * Joins the multicast group, with the default interface. * ------------------------------------------------------------------- */void Listener::McastJoin( ) {#ifdef HAVE_MULTICAST if ( !SockAddr_isIPv6( &mSettings->local ) ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -