Logo Search packages:      
Sourcecode: znc version File versions  Download package

template<class T>
virtual void TSocketManager< T >::Select ( std::map< T *, EMessages > &  mpeSocks  )  [inline, private, virtual]

fills a map of socks to a message for check map is empty if none are ready, check GetErrno() for the error, if not SUCCESS Select() failed each struct contains the socks error

See also:
GetErrno()

Definition at line 1860 of file Csocket.h.

      {
            mpeSocks.clear();
            struct timeval tv;
            fd_set rfds, wfds;

            tv.tv_sec = m_iSelectWait / 1000000;
            tv.tv_usec = m_iSelectWait % 1000000;
            u_int iQuickReset = 100;
            if ( m_iSelectWait == 0 )
                  iQuickReset = 0;

            TFD_ZERO( &rfds );
            TFD_ZERO( &wfds );

            // before we go any further, Process work needing to be done on the job
            for( unsigned int i = 0; i < this->size(); i++ )
            {
                  if ( ( (*this)[i]->GetCloseType() == T::CLT_NOW ) || ( ( (*this)[i]->GetCloseType() == T::CLT_AFTERWRITE ) && ( (*this)[i]->GetWriteBuffer().empty() ) ) )
                        DelSock( i-- ); // close any socks that have requested it
                  else
                        (*this)[i]->Cron(); // call the Cron handler here
            }

            bool bHasWriteable = false;
            bool bHasAvailSocks = false;
            unsigned long long iNOW = 0;

            for( unsigned int i = 0; i < this->size(); i++ )
            {
                  T *pcSock = (*this)[i];

                  if ( pcSock->GetConState() != T::CST_OK )
                        continue;

                  bHasAvailSocks = true;

                  int & iRSock = pcSock->GetRSock();
                  int & iWSock = pcSock->GetWSock();
                  bool bIsReadPaused = pcSock->IsReadPaused();
                  if ( bIsReadPaused )
                  {
                        pcSock->ReadPaused();
                        bIsReadPaused = pcSock->IsReadPaused(); // re-read it again, incase it changed status)
                  }
                  if ( ( iRSock < 0 ) || ( iWSock < 0 ) )
                  {
                        SelectSock( mpeSocks, SUCCESS, pcSock );
                        continue;   // invalid sock fd
                  }

                  if ( pcSock->GetType() != T::LISTENER )
                  {
                        if ( ( pcSock->GetSSL() ) && ( pcSock->GetType() == T::INBOUND ) && ( !pcSock->FullSSLAccept() ) )
                        {
                              tv.tv_usec = iQuickReset;     // just make sure this returns quick incase we still need pending
                              tv.tv_sec = 0;
                              // try accept on this socket again
                              if ( !pcSock->AcceptSSL() )
                                    pcSock->Close();

                        } else if ( ( pcSock->IsConnected() ) && ( pcSock->GetWriteBuffer().empty() ) )
                        {
                              if ( !bIsReadPaused )
                                    TFD_SET( iRSock, &rfds );

                        } else if ( ( pcSock->GetSSL() ) && ( !pcSock->SslIsEstablished() ) && ( !pcSock->GetWriteBuffer().empty() ) )
                        {
                              // do this here, cause otherwise ssl will cause a small
                              // cpu spike waiting for the handshake to finish
                              TFD_SET( iRSock, &rfds );
                              // resend this data
                              if ( !pcSock->Write( "" ) )
                              {
                                    pcSock->Close();
                              }
                        } else
                        {
                              if ( !bIsReadPaused )
                                    TFD_SET( iRSock, &rfds );

                              if( pcSock->AllowWrite( iNOW ) )
                              {
                                    TFD_SET( iWSock, &wfds );
                                    bHasWriteable = true;
                              }
                        }

                  } else
                        TFD_SET( iRSock, &rfds );
            }

            // first check to see if any ssl sockets are ready for immediate read
            // a mini select() type deal for ssl
            for( unsigned int i = 0; i < this->size(); i++ )
            {
                  T *pcSock = (*this)[i];

                  if ( pcSock->GetConState() != T::CST_OK )
                        continue;

                  if ( ( pcSock->GetSSL() ) && ( pcSock->GetType() != Csock::LISTENER ) )
                  {
                        if ( ( pcSock->GetPending() > 0 ) && ( !pcSock->IsReadPaused() ) )
                              SelectSock( mpeSocks, SUCCESS, pcSock );
                  }
            }

            // old fashion select, go fer it
            int iSel;

            if ( !mpeSocks.empty() ) // .1 ms pause to see if anything else is ready (IE if there is SSL data pending, don't wait too long)
            {
                  tv.tv_usec = iQuickReset;
                  tv.tv_sec = 0;
            }
            else if ( ( !this->empty() ) && ( !bHasAvailSocks ) )
            {
                  tv.tv_usec = iQuickReset;
                  tv.tv_sec = 0;
            }


            if ( bHasWriteable )
                  iSel = select(FD_SETSIZE, &rfds, &wfds, NULL, &tv);
            else
                  iSel = select(FD_SETSIZE, &rfds, NULL, NULL, &tv);
            if ( iSel == 0 )
            {
                  if ( mpeSocks.empty() )
                        m_errno = SELECT_TIMEOUT;
                  else
                        m_errno = SUCCESS;

                  return;
            }

            if ( ( iSel == -1 ) && ( errno == EINTR ) )
            {
                  if ( mpeSocks.empty() )
                        m_errno = SELECT_TRYAGAIN;
                  else
                        m_errno = SUCCESS;

                  return;
            } else if ( iSel == -1 )
            {
                  if ( mpeSocks.empty() )
                        m_errno = SELECT_ERROR;
                  else
                        m_errno = SUCCESS;

                  return;
            } else
            {
                  m_errno = SUCCESS;
            }

            // find out wich one is ready
            for( unsigned int i = 0; i < this->size(); i++ )
            {
                  T *pcSock = (*this)[i];

                  if ( pcSock->GetConState() != T::CST_OK )
                        continue;

                  int & iRSock = pcSock->GetRSock();
                  int & iWSock = pcSock->GetWSock();
                  EMessages iErrno = SUCCESS;

                  if ( ( iRSock < 0 ) || ( iWSock < 0 ) )
                  {
                        // trigger a success so it goes through the normal motions
                        // and an error is produced
                        SelectSock( mpeSocks, SUCCESS, pcSock );
                        continue; // watch for invalid socks
                  }

                  if ( TFD_ISSET( iWSock, &wfds ) )
                  {
                        if ( iSel > 0 )
                        {
                              iErrno = SUCCESS;
                              if ( ( !pcSock->GetWriteBuffer().empty() ) && ( pcSock->IsConnected() ) )
                              { // write whats in the socks send buffer
                                    if ( !pcSock->Write( "" ) )
                                    {
                                          // write failed, sock died :(
                                          iErrno = SELECT_ERROR;
                                    }
                              }
                        } else
                              iErrno = SELECT_ERROR;

                        SelectSock( mpeSocks, iErrno, pcSock );

                  } else if ( TFD_ISSET( iRSock, &rfds ) )
                  {
                        if ( iSel > 0 )
                              iErrno = SUCCESS;
                        else
                              iErrno = SELECT_ERROR;

                        if ( pcSock->GetType() != T::LISTENER )
                              SelectSock( mpeSocks, iErrno, pcSock );
                        else // someone is coming in!
                        {
                              CS_STRING sHost;
                              u_short port;
                              int inSock = pcSock->Accept( sHost, port );

                              if ( inSock != -1 )
                              {
                                    if ( T::TMO_ACCEPT & pcSock->GetTimeoutType() )
                                          pcSock->ResetTimer();   // let them now it got dinged

                                    // if we have a new sock, then add it
                                    T *NewpcSock = (T *)pcSock->GetSockObj( sHost, port );

                                    if ( !NewpcSock )
                                          NewpcSock = new T( sHost, port );

                                    NewpcSock->BlockIO( false );
                                    NewpcSock->SetType( T::INBOUND );
                                    NewpcSock->SetRSock( inSock );
                                    NewpcSock->SetWSock( inSock );
                                    NewpcSock->SetIPv6( pcSock->GetIPv6() );

                                    bool bAddSock = true;
#ifdef HAVE_LIBSSL
                                    //
                                    // is this ssl ?
                                    if ( pcSock->GetSSL() )
                                    {
                                          NewpcSock->SetCipher( pcSock->GetCipher() );
                                          NewpcSock->SetPemLocation( pcSock->GetPemLocation() );
                                          NewpcSock->SetPemPass( pcSock->GetPemPass() );
                                          NewpcSock->SetRequiresClientCert( pcSock->RequiresClientCert() );
                                          bAddSock = NewpcSock->AcceptSSL();
                                    }

#endif /* HAVE_LIBSSL */
                                    if ( bAddSock )
                                    {
                                          // set the name of the listener
                                          NewpcSock->SetParentSockName( pcSock->GetSockName() );
                                          NewpcSock->SetRate( pcSock->GetRateBytes(), pcSock->GetRateTime() );
                                          if ( NewpcSock->GetSockName().empty() )
                                          {
                                                std::stringstream s;
                                                s << sHost << ":" << port;
                                                AddSock( NewpcSock,  s.str() );

                                          } else
                                                AddSock( NewpcSock, NewpcSock->GetSockName() );
                                    } else
                                          CS_Delete( NewpcSock );
                              }
                        }
                  }
            }
      }


Generated by  Doxygen 1.6.0   Back to index