Пример #1
0
BOOL CDOSObjectProxyService::OnRun()
{
	FUNCTION_BEGIN;
	EXCEPTION_CATCH_START

	m_ThreadPerformanceCounter.DoPerformanceCount();

	int ProcessCount=CNetService::Update();
	LPVOID Pos=m_ConnectionPool.GetFirstObjectPos();
	while(Pos)
	{
		CDOSProxyConnection * pConnection=m_ConnectionPool.GetNext(Pos);
		if(pConnection->IsConnected())
			ProcessCount+=pConnection->Update();
		else
			DeleteConnection(pConnection);
	}

	ProcessCount+=DoMessageProcess();

	if(ProcessCount==0)
	{
		DoSleep(1);
	}

	EXCEPTION_CATCH_END

	return TRUE;
	FUNCTION_END;
	return FALSE;
}
Пример #2
0
bool ClusterTransport::SetConnectionNodeID(Endpoint& endpoint, uint64_t nodeID)
{
    ClusterConnection* it;
    ClusterConnection* tdb;
    
    for (it = conns.First(); it != NULL;)
    {
        if (it->GetEndpoint() == endpoint)
        {
            if (it->GetProgress() != ClusterConnection::AWAITING_NODEID)
            {
                // the node had its db cleared, and this is our old connection to it
                tdb = it;
                it = conns.Next(it);
                DeleteConnection(tdb);
            }
            else
            {
                it->SetNodeID(nodeID);
                it->SetProgress(ClusterConnection::READY);
                return true;
            }
        }
        else
            it = conns.Next(it);
    }
    
    return false;
}
Пример #3
0
KThruput::KThruput(KConnection* newmainwin, QWidget *newframe, int newScale) : QFrame(newframe)
{
//	initMetaObject();

	setFixedSize(THRU_X,THRU_Y);
//	setFrameStyle(QFrame::WinPanel | QFrame::Raised);

	mainwin = newmainwin;
	frame = newframe; 

	TimeScale = newScale;

	BGColor.setRgb(0,0,0);
	PenColor[IN_DATA].setRgb(0,255,0);
	PenColor[OUT_DATA].setRgb(0,0,255);

	ValueSize = width()+1;
	Values[IN_DATA] = new int[ValueSize];
	Values[OUT_DATA] = new int[ValueSize];
	RunTime = new int[ValueSize];

	DeleteConnection();

	repaint();
}
Пример #4
0
bool KThruput::StartConnection()
{
	DeleteConnection();

	Connected = 0;
	NotConnected = FALSE;

	repaint();
	return TRUE;
}
ItemConnection::~ItemConnection()
{
	// delete child items
	DeleteConnection();
	// remove us from scene
	if (scene() != nullptr)
	{
		scene()->removeItem(this);
	}
}
Пример #6
0
void ClusterTransport::DropConnection(Endpoint endpoint)
{
    ClusterConnection* conn;
    
    conn = GetConnection(endpoint);
    
    if (!conn)
        return;
        
    DeleteConnection(conn);
}
Пример #7
0
void ClusterTransport::DropConnection(uint64_t nodeID)
{
    ClusterConnection* conn;
    
    conn = GetConnection(nodeID);
    
    if (!conn)
        return;
        
    DeleteConnection(conn);
}
Пример #8
0
void BaseSignal::OnDisconnect( CallbackBase* callback )
{
  DALI_ASSERT_ALWAYS( NULL != callback && "Invalid member function pointer passed to Disconnect()" );

  int index = FindCallback( callback );

  if( index > INVALID_CALLBACK_INDEX )
  {
    DeleteConnection( index );
  }

  // call back is a temporary created to find which slot should be disconnected.
  delete callback;
}
Пример #9
0
// for SlotObserver::SlotDisconnected
void BaseSignal::SlotDisconnected( CallbackBase* callback )
{
  for( std::size_t i=0; i < mSignalConnections.size(); ++i )
  {
    const CallbackBase* connectionCallback = GetCallback( i );

    // Pointer comparison i.e. SignalConnection contains pointer to same callback instance
    if( connectionCallback &&
        connectionCallback == callback )
    {
      DeleteConnection( i );

      // Disconnection complete
      return;
    }
  }

  DALI_ASSERT_ALWAYS( false && "Callback lost in SlotDisconnected()" );
}
Пример #10
0
void BaseSignal::OnDisconnect( ConnectionTrackerInterface* tracker, CallbackBase* callback )
{
  DALI_ASSERT_ALWAYS( NULL != tracker  && "Invalid ConnectionTrackerInterface pointer passed to Disconnect()" );
  DALI_ASSERT_ALWAYS( NULL != callback && "Invalid member function pointer passed to Disconnect()" );

  int index = FindCallback( callback );

  if( index > INVALID_CALLBACK_INDEX )
  {
    // temporary pointer to disconnected callback
    CallbackBase* disconnectedCallback = mSignalConnections[index]->GetCallback();

    // close the signal side connection first.
    DeleteConnection( index );

    // close the slot side connection
    tracker->SignalDisconnected( this, disconnectedCallback );
  }

  // call back is a temporary created to find which slot should be disconnected.
  delete callback;
}
Пример #11
0
void SCH_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event )
{
    int         id = event.GetId();
    wxPoint     pos;
    SCH_SCREEN* screen = GetScreen();
    SCH_ITEM*   item = screen->GetCurItem();

    pos = wxGetMousePosition();

    pos.y += 20;

    // If needed, stop the current command and deselect current tool
    switch( id )
    {
    case wxID_CUT:
    case wxID_COPY:
    case ID_POPUP_CANCEL_CURRENT_COMMAND:
    case ID_POPUP_SCH_ENTRY_SELECT_SLASH:
    case ID_POPUP_SCH_ENTRY_SELECT_ANTISLASH:
    case ID_POPUP_SCH_BEGIN_WIRE:
    case ID_POPUP_SCH_BEGIN_BUS:
    case ID_POPUP_END_LINE:
    case ID_POPUP_SCH_SET_SHAPE_TEXT:
    case ID_POPUP_SCH_CLEANUP_SHEET:
    case ID_POPUP_SCH_END_SHEET:
    case ID_POPUP_SCH_RESIZE_SHEET:
    case ID_POPUP_IMPORT_GLABEL:
    case ID_POPUP_SCH_INIT_CMP:
    case ID_POPUP_SCH_DISPLAYDOC_CMP:
    case ID_POPUP_SCH_EDIT_CONVERT_CMP:
    case ID_POPUP_DELETE_BLOCK:
    case ID_POPUP_PLACE_BLOCK:
    case ID_POPUP_ZOOM_BLOCK:
    case ID_POPUP_DRAG_BLOCK:
    case ID_POPUP_COPY_BLOCK:
    case ID_POPUP_SCH_DELETE_NODE:
    case ID_POPUP_SCH_DELETE_CONNECTION:
    case ID_POPUP_SCH_ENTER_SHEET:
    case ID_POPUP_SCH_LEAVE_SHEET:
    case ID_POPUP_SCH_ADD_JUNCTION:
    case ID_POPUP_SCH_ADD_LABEL:
    case ID_POPUP_SCH_GETINFO_MARKER:

        /* At this point: Do nothing. these commands do not need to stop the
         * current command (mainly a block command) or reset the current state
         * They will be executed later, in next switch structure.
         */
        break;

    case ID_POPUP_SCH_DELETE_CMP:
    case ID_POPUP_SCH_DELETE:

        // Stop the current command (if any) but keep the current tool
        m_canvas->EndMouseCapture();
        break;

    default:

        // Stop the current command and deselect the current tool
        m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor() );
        break;
    }

    INSTALL_UNBUFFERED_DC( dc, m_canvas );
    item = screen->GetCurItem();    // Can be modified by previous calls.

    switch( id )
    {
    case ID_HIERARCHY:
        InstallHierarchyFrame( &dc, pos );
        SetRepeatItem( NULL );
        break;

    case wxID_CUT:
        if( screen->m_BlockLocate.GetCommand() != BLOCK_MOVE )
            break;

        screen->m_BlockLocate.SetCommand( BLOCK_DELETE );
        screen->m_BlockLocate.SetMessageBlock( this );
        HandleBlockEnd( &dc );
        SetRepeatItem( NULL );
        SetSheetNumberAndCount();
        break;

    case wxID_PASTE:
        HandleBlockBegin( &dc, BLOCK_PASTE, GetCrossHairPosition() );
        break;

    case ID_POPUP_SCH_ENTRY_SELECT_SLASH:
        m_canvas->MoveCursorToCrossHair();
        SetBusEntryShape( &dc, dynamic_cast<SCH_BUS_ENTRY_BASE*>( item ), '/' );
        break;

    case ID_POPUP_SCH_ENTRY_SELECT_ANTISLASH:
        m_canvas->MoveCursorToCrossHair();
        SetBusEntryShape( &dc, dynamic_cast<SCH_BUS_ENTRY_BASE*>( item ), '\\' );
        break;

    case ID_POPUP_CANCEL_CURRENT_COMMAND:
        if( m_canvas->IsMouseCaptured() )
        {
            m_canvas->EndMouseCapture();
            SetToolID( GetToolId(), m_canvas->GetCurrentCursor(), wxEmptyString );
        }
        else
        {
            SetToolID( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor(), wxEmptyString );
        }

        break;

    case ID_POPUP_END_LINE:
        m_canvas->MoveCursorToCrossHair();
        EndSegment( &dc );
        break;

    case ID_POPUP_SCH_BEGIN_WIRE:
        m_canvas->MoveCursorToCrossHair();
        OnLeftClick( &dc, GetCrossHairPosition() );
        break;

    case ID_POPUP_SCH_BEGIN_BUS:
        m_canvas->MoveCursorToCrossHair();
        OnLeftClick( &dc, GetCrossHairPosition() );
        break;

    case ID_POPUP_SCH_SET_SHAPE_TEXT:
        // Not used
        break;

    case ID_POPUP_SCH_DELETE_NODE:
    case ID_POPUP_SCH_DELETE_CONNECTION:
        m_canvas->MoveCursorToCrossHair();
        DeleteConnection( id == ID_POPUP_SCH_DELETE_CONNECTION );
        screen->SetCurItem( NULL );
        SetRepeatItem( NULL );
        screen->TestDanglingEnds( m_canvas, &dc );
        m_canvas->Refresh();
        break;

    case ID_POPUP_SCH_BREAK_WIRE:
    {
        DLIST< SCH_ITEM > oldWires;

        oldWires.SetOwnership( false );      // Prevent DLIST for deleting items in destructor.
        m_canvas->MoveCursorToCrossHair();
        screen->ExtractWires( oldWires, true );
        screen->BreakSegment( GetCrossHairPosition() );

        if( oldWires.GetCount() != 0 )
        {
            PICKED_ITEMS_LIST oldItems;

            oldItems.m_Status = UR_WIRE_IMAGE;

            while( oldWires.GetCount() != 0 )
            {
                ITEM_PICKER picker = ITEM_PICKER( oldWires.PopFront(), UR_WIRE_IMAGE );
                oldItems.PushItem( picker );
            }

            SaveCopyInUndoList( oldItems, UR_WIRE_IMAGE );
        }

        screen->TestDanglingEnds( m_canvas, &dc );
    }
    break;

    case ID_POPUP_SCH_DELETE_CMP:
    case ID_POPUP_SCH_DELETE:
        if( item == NULL )
            break;

        DeleteItem( item );
        screen->SetCurItem( NULL );
        SetRepeatItem( NULL );
        screen->TestDanglingEnds( m_canvas, &dc );
        SetSheetNumberAndCount();
        OnModify();
        break;

    case ID_POPUP_SCH_END_SHEET:
        m_canvas->MoveCursorToCrossHair();
        addCurrentItemToList( &dc );
        break;

    case ID_POPUP_SCH_RESIZE_SHEET:
        ReSizeSheet( (SCH_SHEET*) item, &dc );
        screen->TestDanglingEnds( m_canvas, &dc );
        break;

    case ID_POPUP_IMPORT_GLABEL:
        if( item != NULL && item->Type() == SCH_SHEET_T )
            screen->SetCurItem( ImportSheetPin( (SCH_SHEET*) item, &dc ) );
        break;

    case ID_POPUP_SCH_CLEANUP_SHEET:
        if( item != NULL && item->Type() == SCH_SHEET_T )
        {
            SCH_SHEET* sheet = (SCH_SHEET*) item;

            if( !sheet->HasUndefinedPins() )
            {
                DisplayInfoMessage( this,
                                    _( "There are no undefined labels in this sheet to clean up." ) );
                return;
            }

            if( !IsOK( this, _( "Do you wish to cleanup this sheet?" ) ) )
                return;

            /* Save sheet in undo list before cleaning up unreferenced hierarchical labels. */
            SaveCopyInUndoList( sheet, UR_CHANGED );
            sheet->CleanupSheet();
            OnModify();
            m_canvas->RefreshDrawingRect( sheet->GetBoundingBox() );
        }
        break;

    case ID_POPUP_SCH_INIT_CMP:
        m_canvas->MoveCursorToCrossHair();
        break;

    case ID_POPUP_SCH_EDIT_CONVERT_CMP:

        // Ensure the struct is a component (could be a struct of a component, like Field, text..)
        if( item && item->Type() == SCH_COMPONENT_T )
        {
            m_canvas->MoveCursorToCrossHair();
            ConvertPart( (SCH_COMPONENT*) item, &dc );
        }

        break;

    case ID_POPUP_SCH_DISPLAYDOC_CMP:

        // Ensure the struct is a component (could be a piece of a component, like Field, text..)
        if( item && item->Type() == SCH_COMPONENT_T )
        {
            LIB_ALIAS* LibEntry;
            LibEntry = CMP_LIBRARY::FindLibraryEntry( ( (SCH_COMPONENT*) item )->GetLibName() );

            if( LibEntry && LibEntry->GetDocFileName() != wxEmptyString )
            {
                GetAssociatedDocument( this, LibEntry->GetDocFileName(),
                                       &wxGetApp().GetLibraryPathList() );
            }
        }
        break;

    case ID_POPUP_SCH_ENTER_SHEET:

        if( item && (item->Type() == SCH_SHEET_T) )
        {
            m_CurrentSheet->Push( (SCH_SHEET*) item );
            DisplayCurrentSheet();
        }

        break;

    case ID_POPUP_SCH_LEAVE_SHEET:
        m_CurrentSheet->Pop();
        DisplayCurrentSheet();
        break;

    case wxID_COPY:         // really this is a Save block for paste
        screen->m_BlockLocate.SetCommand( BLOCK_SAVE );
        screen->m_BlockLocate.SetMessageBlock( this );
        HandleBlockEnd( &dc );
        break;

    case ID_POPUP_PLACE_BLOCK:
        m_canvas->SetAutoPanRequest( false );
        m_canvas->MoveCursorToCrossHair();
        HandleBlockPlace( &dc );
        break;

    case ID_POPUP_ZOOM_BLOCK:
        screen->m_BlockLocate.SetCommand( BLOCK_ZOOM );
        screen->m_BlockLocate.SetMessageBlock( this );
        HandleBlockEnd( &dc );
        break;

    case ID_POPUP_DELETE_BLOCK:
        m_canvas->MoveCursorToCrossHair();
        screen->m_BlockLocate.SetCommand( BLOCK_DELETE );
        screen->m_BlockLocate.SetMessageBlock( this );
        HandleBlockEnd( &dc );
        SetSheetNumberAndCount();
        break;

    case ID_POPUP_COPY_BLOCK:
        m_canvas->MoveCursorToCrossHair();
        screen->m_BlockLocate.SetCommand( BLOCK_COPY );
        screen->m_BlockLocate.SetMessageBlock( this );
        HandleBlockEnd( &dc );
        break;

    case ID_POPUP_DRAG_BLOCK:
        m_canvas->MoveCursorToCrossHair();
        screen->m_BlockLocate.SetCommand( BLOCK_DRAG );
        screen->m_BlockLocate.SetMessageBlock( this );
        HandleBlockEnd( &dc );
        break;

    case ID_POPUP_SCH_ADD_JUNCTION:
        m_canvas->MoveCursorToCrossHair();
        screen->SetCurItem( AddJunction( &dc, GetCrossHairPosition(), true ) );
        screen->TestDanglingEnds( m_canvas, &dc );
        screen->SetCurItem( NULL );
        break;

    case ID_POPUP_SCH_ADD_LABEL:
    case ID_POPUP_SCH_ADD_GLABEL:
        screen->SetCurItem( CreateNewText( &dc, id == ID_POPUP_SCH_ADD_LABEL ?
                                           LAYER_LOCLABEL : LAYER_GLOBLABEL ) );
        item = screen->GetCurItem();

        if( item )
            addCurrentItemToList( &dc );

        break;

    case ID_POPUP_SCH_GETINFO_MARKER:
        if( item && item->Type() == SCH_MARKER_T )
            ( (SCH_MARKER*) item )->DisplayMarkerInfo( this );

        break;

    default:        // Log error:
        wxFAIL_MSG( wxString::Format( wxT( "Cannot process command event ID %d" ),
                                      event.GetId() ) );
        break;
    }

    // End switch ( id )    (Command execution)

    if( GetToolId() == ID_NO_TOOL_SELECTED )
        SetRepeatItem( NULL );
}
Пример #12
0
	void Server::AuthorizeConnection(const std::string &tempGuid, const std::string &message)
	{
		//обрабатываем подключение
		HandleMessage(tempGuid, message);
		DeleteConnection(tempGuid, false);//удаляем подключение из списка временных
	}
Пример #13
0
// Закрытие соединения.
String meth::ConnectionClose(String conn_id) {
	DeleteConnection(conn_id);
	return "null";
}
Пример #14
0
void
ReaderTask(int fd, const char *id)
{
    time_t dtime = 0;
    time_t ltime = 0;
    time_t itime = 0;
    time_t ftime = 0;
    time_t atime = 0;
    int counter = 0;
    int forceallcheck = 0;
    int check_disconn_counter = 0;

    TFd = fd;

    /*
     * [re]open RTStatus
     */
    RTStatusOpen(RTStatus, ThisReaderFork * DOpts.ReaderThreads + 1, DOpts.ReaderThreads);

    /*
     * Since we setuid(), we won't core.  This is for debugging
     */
    if (CoreDebugOpt || (DOpts.ReaderCrashHandler != NULL &&
			strcasecmp(DOpts.ReaderCrashHandler, "none") != 0)) {
	signal(SIGSEGV, sigSegVReader);
	signal(SIGBUS, sigSegVReader);
	signal(SIGFPE, sigSegVReader);
	signal(SIGILL, sigSegVReader);
    }

    signal(SIGHUP, sigHup);
    signal(SIGUSR1, sigUsr1);

    /*
     * Setup thread for passed pipe
     */
    ResetThreads();
    AddThread("reader", fd, -1, THREAD_READER, -1, 0);

    FD_SET(fd, &RFds);

    /*
     * Open KPDB database for active file
     */

    if ((KDBActive = KPDBOpen(PatDbExpand(ReaderDActivePat), O_RDWR)) == NULL) {
	logit(LOG_CRIT, "Unable to open %s", PatDbExpand(ReaderDActivePat));
	sleep(60);
	exit(1);
    }

    LoadExpireCtl(1);

    /*
     * Only startup connections to backend spools for reader threads
     */
    if (!FeedOnlyServer)
	CheckServerConfig(time(NULL), 1);

    /*
     * Selection core
     */

    while (!TerminatePending || NReadServAct || NumReaders) {
	/*
	 *  select core
	 */
	struct timeval tv;
	fd_set rfds = RFds;
	fd_set wfds = WFds;
	fd_set read_only_to_find_eof_fds;
	int i, sel_r;

	if (TerminatePending) {
	    if (TerminateTime == 0)
		TerminateTime = time(NULL) + 2;
	    if (TerminateTime < time(NULL) || !NumReaders)
		CanTerminate = 1;
	}

	/*
	 *  Get next scheduled timeout, no more then 2 seconds
	 *  (x 10 counter counts = 20 seconds max for {d,i,f}time 
	 *  check)
	 *
	 * If we are terminating, then speed up the select to clear
	 * out the connections.
	 *
	 */

	if (TerminatePending)
	    NextTimeout(&tv, 50);
	else
	    NextTimeout(&tv, 2 * 1000);

	stprintf("%s readers=%02d spoolsrv=%d/%d postsrv=%d/%d",
	    id,
	    NumReaders,
	    NReadServAct, NReadServers, 
	    NWriteServAct, NWriteServers
	);

	/* Check for disconnected clients every 50 times through the loop */
	FD_ZERO(&read_only_to_find_eof_fds);
	if (++check_disconn_counter == 50) {
	    for (i = 0; i < MaxFds; ++i) {
		if (FD_ISSET(i, &wfds) && (!(FD_ISSET(i, &rfds)))) {
		    FD_SET(i, &rfds);
		    FD_SET(i, &read_only_to_find_eof_fds);
		}
	    }
	    check_disconn_counter = 0;
	}

#if USE_AIO
	AIOUnblockSignal();
#endif
	sel_r = select(MaxFds, &rfds, &wfds, NULL, &tv);
#if USE_AIO
	AIOBlockSignal();
#endif

	gettimeofday(&CurTime, NULL);

	if(sel_r < 0 && errno != EINTR)
	    logit(LOG_CRIT,
		  "select error: %s (rfds=0x%x, wfds=0x%x)",
		  strerror(errno),
		  rfds,
		  wfds);

	/*
	 * select is critical, don't make unnecessary system calls.  Only
	 * test the time every 10 selects (20 seconds worst case), and
	 * only check for a new server configuration file every 60 seconds 
	 * after the initial load.  This may rearrange THREAD_SPOOL and
	 * THREAD_POST threads.
	 *
	 * We do not startup spool/post servers for feed-only forks
	 *
	 * However, flush overview cache even for feed-only forks.
	 */

	if (FeedOnlyServer <= 0) {
	    if (++counter == 10) {
		time_t t = CurTime.tv_sec;
		if (ltime) {
		    dtime += t - ltime;
		    itime += t - ltime;
		    ftime += t - ltime;
		    atime += t - ltime;
		}

		/*
		 * Check for server config change once a minute
		 */
		if (dtime < -5 || dtime >= 5) {
		    if (!TerminatePending)
			CheckServerConfig(t, ServersTerminated);
		    dtime = 0;
		}

		/*
		 * Flush overview every 30 seconds to allow dexpireover to work
		 */
		if (ftime < -5 || ftime >= 30) {
		    FlushOverCache();
		    LoadExpireCtl(0);
		    ftime = 0;
		}

		/*
		 * Poll all active descriptors once every 5 minutes.  This
		 * will work around a linux embrionic close bug that
		 * doesn't wakeup select(), and is used to idle-timeout
		 * connections. XXX
		 */
		if (itime < -5 || itime >= 300) {
		    rfds = RFds;
		    itime = 0;
		}

		/*
		 * Force a check all of FD's every 30 seconds to handle
		 * idle and session timeouts
		 */
		if (atime < -5 || atime >= 30) {
		    forceallcheck = 1;
		    atime = 0;
		}
		ltime = t;
		counter = 0;
	    }
	} else {
	    /*
	     * For a feed-only server, we only flush the overview FD
	     * cache every 5 minutes, and with a greater granularity.
	     * It should cycle much faster than that normally, and this
	     * is to prevent idle feed-only forks from keeping locks.
	     *
	     */

	    if (++counter == 10) {
		time_t t = CurTime.tv_sec;
		if (ltime) {
		    ftime += t - ltime;
		}

		if (ftime < -5 || ftime >= 300) {
		    FlushOverCache();
		    ftime = 0;
		}
		ltime = t;
		counter = 0;
	    }
	}

	for (i = 0; i < MaxFds; ++i) {
	    if (FD_ISSET(i, &rfds) && FD_ISSET(i, &read_only_to_find_eof_fds)) {
		char junk_byte;
		int ret_val;
		/*
		 * This FD is not marked for reading, but select() claims
		 * it has something to say. We don't actually want to read
		 * from it, but we do want to close it if the associated
		 * connection is dead.
		 */
		FD_CLR(i, &rfds);

		/* Use recv() with MSG_PEEK to see if it's closed.
		 * We shouldn't block because we're O_NONBLOCK.
		 */
		ret_val = recv(i, &junk_byte, 1, MSG_PEEK);

		/* If ret_val is zero, this means the socket is closed.
		 * Blast it. Otherwise, ignore it.
		 */
		if(ret_val == 0) {
		    ForkDesc *desc;
		    if((desc = FindThread(i, -1)) != NULL) {
			Connection *conn = desc->d_Data;

			if(conn) {
			    NNTerminate(conn);
			    DeleteConnection(conn);
			}
			DelThread(desc);
		    }
		}
	    }
	}

	for (i = 0; i < MaxFds; ++i) {
	    if (forceallcheck || TerminatePending ||
		FD_ISSET(i, &rfds) || FD_ISSET(i, &wfds)) {
		ForkDesc *desc;

		if ((desc = FindThread(i, -1)) != NULL) {
		    Connection *conn = desc->d_Data;

		    if (conn) {
			/*
			 * handle output I/O (optimization)
			 */

			MBFlush(conn, &conn->co_TMBuf);
			conn->co_FCounter = 0;
		    } 

		    /*
		     * Function dispatch
		     */

		    switch(desc->d_Type) {
		    case THREAD_READER:
			if (FD_ISSET(i, &rfds) || FD_ISSET(i, &wfds))
			    HandleReaderMsg(desc);
			break;
		    case THREAD_NNTP:		/* client	  */
			conn->co_Func(conn);
			if (conn->co_Auth.dr_ResultFlags & DR_REQUIRE_DNS) {
			    /* Go back to parent for DNS check */
			    conn->co_Auth.dr_Code = 0;
			    conn->co_TMBuf.mh_WEof = 1;
			}
			break;
		    case THREAD_SPOOL:		/* spool server	  */
		    case THREAD_POST:		/* posting server */
			conn->co_Func(conn);
			LogServerInfo(conn, TFd);
			break;
		    default:
			/* panic */
			break;
		    }

		    /*
		     * do not call MBFlush after the function because the
		     * function may be waiting for write data to drain and
		     * we don't want to cause write data to drain here and
		     * then not get a select wakeup later.
		     *
		     * check for connection termination
		     */

		    if (conn) {
			int idleTimeout = 0;
			if (conn->co_Auth.dr_ReaderDef) {
			    if (conn->co_Auth.dr_ReaderDef->rd_IdleTimeout &&
				    conn->co_LastActiveTime +
				    conn->co_Auth.dr_ReaderDef->rd_IdleTimeout <=
				    CurTime.tv_sec) {
				logit(LOG_INFO, "timeout idle %s",
				    conn->co_Auth.dr_Host);
				MBLogPrintf(conn,
				    &conn->co_TMBuf,
				    "400 %s: Idle timeout.\r\n",
				    conn->co_Auth.dr_VServerDef->vs_HostName
				);
				idleTimeout = 1;
				NNTerminate(conn);
			    }
			    if (conn->co_Auth.dr_ReaderDef->rd_SessionTimeout &&
				    conn->co_SessionStartTime +
				    conn->co_Auth.dr_ReaderDef->rd_SessionTimeout <=
				    CurTime.tv_sec) {
				logit(LOG_INFO, "timeout session %s",
				    conn->co_Auth.dr_Host);
				MBLogPrintf(conn,
				    &conn->co_TMBuf,
				    "400 %s: Session timeout.\r\n",
				    conn->co_Auth.dr_VServerDef->vs_HostName
				);
				idleTimeout = 1;
				NNTerminate(conn);
			    }
			}
			if ((!conn->co_Auth.dr_Code &&
				desc->d_Type == THREAD_NNTP) ||
			    idleTimeout ||
			    (conn->co_RMBuf.mh_REof && 
			    conn->co_TMBuf.mh_WEof &&
			    conn->co_TMBuf.mh_MBuf == NULL) ||
			    (TerminatePending &&
					!(conn->co_Flags & COF_MAYNOTCLOSE))
			) {
			    DeleteConnection(conn);
			    DelThread(desc);
			}
		    }
		}
	    }
	}
	forceallcheck = 0;
	(void)ScanTimers(1, 0);
	if (CanTerminate)
	    break;
    }
    RTStatusClose();
    KPDBClose(KDBActive);
    exit(0);
}