/*++ Copyright (c) 2000, Microsoft Corporation Module Name: Abstract: Author: Savas Guven (savasg) 27-Nov-2000 Revision History: --*/ #include "stdafx.h" // // STATIC MEMBER Initialization // const PCHAR _ICQ_CLIENT::ObjectNamep = "ICQ_CLIENT"; const PCHAR _ICQ_PEER::ObjectNamep = "ICQ_PEER"; _ICQ_PEER::_ICQ_PEER() :ToClientSocketp(NULL), ToPeerSocketp(NULL), PeerUIN(0), PeerVer(0), PeerIp(0), PeerPort(0), bActivated(FALSE), bShadowMappingExists(FALSE), MappingDirection(IcqFlagNeutral), ShadowRedirectp(NULL), OutgoingPeerControlRedirectp(NULL), IncomingDataRedirectp(NULL) { } _ICQ_PEER::~_ICQ_PEER() /*++ Routine Description: Arguments: none. Return Value: --*/ { if(this->bCleanupCalled is FALSE) { _ICQ_PEER::ComponentCleanUpRoutine(); } this->bCleanupCalled = FALSE; } void _ICQ_PEER::ComponentCleanUpRoutine() /*++ Routine Description: Arguments: none. Return Value: --*/ { DispatchRequest DReq; PROFILER(TM_IO, TL_INFO, ("PEER COMPONENT_CLEANING %u", this->PeerUIN)); // Cancel the Shadow Mapping if there is any if(this->ShadowRedirectp) { this->ShadowRedirectp->Cancel(); this->ShadowRedirectp->Release(); this->ShadowRedirectp = NULL; this->MappingDirection = IcqFlagNeutral; } if(this->IncomingDataRedirectp != NULL) { this->IncomingDataRedirectp->Cancel(); this->IncomingDataRedirectp->Release(); this->IncomingDataRedirectp = NULL; } if(this->OutgoingPeerControlRedirectp) { this->OutgoingPeerControlRedirectp->Cancel(); this->OutgoingPeerControlRedirectp->Release(); this->OutgoingPeerControlRedirectp = NULL; } // // NOTE: Delete the Dispatcher entries // DReq.dstIp = this->PeerIp; DReq.dstPort= this->PeerPort; DReq.srcIp = 0; DReq.srcPort= 0; // g_IcqPeerDispatcherp->DeleteDispatchRequest( // // Close and Dereference the local sockets if there is any. // if ( ToPeerSocketp != NULL ) { STOP_COMPONENT( ToPeerSocketp ); DEREF_COMPONENT( ToPeerSocketp, eRefInitialization ); ToPeerSocketp = NULL; } if ( ToClientSocketp != NULL ) { STOP_COMPONENT( ToClientSocketp ); DEREF_COMPONENT( ToClientSocketp, eRefInitialization ); ToClientSocketp = NULL; } this->bCleanupCalled = TRUE; } void _ICQ_PEER::StopSync(void) /*++ Routine Description: Stop the sockets if there are any... Arguments: none. Return Value: --*/ { if(this->ToClientSocketp != NULL) { STOP_COMPONENT(this->ToClientSocketp); } if(this->ToPeerSocketp != NULL) { STOP_COMPONENT(this->ToPeerSocketp); } this->Deleted = TRUE; } ULONG _ICQ_PEER::EndPeerSessionForClient(PCNhSock ClosedSocketp) { PROFILER(TM_MSG, TL_INFO, ("> EndPeerSessionForClient")); // // Find the proper Socket and Dereference it. // if ( ClosedSocketp is this->ToClientSocketp ) { DEREF_COMPONENT( this->ToClientSocketp, eRefInitialization ); this->ToClientSocketp = NULL; if ( this->ToPeerSocketp != NULL ) { STOP_COMPONENT( this->ToPeerSocketp ); } } else if ( ClosedSocketp is this->ToPeerSocketp ) { DEREF_COMPONENT( this->ToPeerSocketp, eRefInitialization ); this->ToPeerSocketp = NULL; if( this->ToPeerSocketp != NULL ) { STOP_COMPONENT( this->ToPeerSocketp ); } } else { ASSERT(FALSE); } // // The Data Redirects Should be cleaned here. // if(this->IncomingDataRedirectp != NULL) { this->IncomingDataRedirectp->Cancel(); this->IncomingDataRedirectp->Release(); this->IncomingDataRedirectp = NULL; } if(this->ShadowRedirectp) { this->ShadowRedirectp->Cancel(); this->ShadowRedirectp->Release(); this->ShadowRedirectp = NULL; this->bActivated = FALSE; this->MappingDirection = IcqFlagNeutral; } return NO_ERROR; } // ************************************************ // ICQ_CLIENT MEMBER FUNCTION // ************************************************ // // // _ICQ_CLIENT::_ICQ_CLIENT() :ServerSocketp(NULL), ShadowRedirectp(NULL), IncomingPeerControlRedirectionp(NULL), ClientSocketp(NULL), ClientIp(0), ClientToServerPort(0), ClientToPeerPort(0), ImitatedPeerPort(0), UIN(0), ClientVer(0), ServerIp(0), ServerPort(0), TimerContextp(NULL) { } _ICQ_CLIENT::~_ICQ_CLIENT() /*++ Routine Description: Arguments: none. Return Value: --*/ { if(this->bCleanupCalled is FALSE) { _ICQ_CLIENT::ComponentCleanUpRoutine(); } this->bCleanupCalled = FALSE; } void _ICQ_CLIENT::ComponentCleanUpRoutine(void) /*++ Routine Description: Arguments: none. Return Value: --*/ { ULONG Error = NO_ERROR; DispatchRequest DReq; PICQ_PEER IcqPeerp = NULL; PROFILER(TM_MSG, TL_INFO, ("CLIENT COMPONENT_CLEANING %u", this->UIN)); // // We need to DELETE the Dispatcher Requests made for the // Peer, tracerse the List of the Peers and Request the Removal // of these (OUTGOING PEER SESSION - REDIRECT) deletion. // for(IcqPeerp = dynamic_cast (this->IcqPeerList.SearchNodeKeys(0, 0)); IcqPeerp != NULL; IcqPeerp = dynamic_cast(IcqPeerp->Nextp)) { DReq.dstIp = IcqPeerp->PeerIp; DReq.dstPort = IcqPeerp->PeerPort; DReq.srcIp = this->ClientIp; DReq.srcPort = 0; // // A Remove operation STOPs and DEREFs a Node. // this->IcqPeerList.RemoveNodeFromList(IcqPeerp); Error = g_IcqPeerDispatcherp->DeleteDispatchRequest(&DReq); if(Error) { ICQ_TRC(TM_MSG, TL_ERROR, ("** !!Can't delete Peer Redirection Dispatch Req !! **")); } } // // Delete the Dispatcher Requests for the Incoming // Peer Sessions Redirect Request // DReq.dstIp = g_MyPublicIp; DReq.dstPort = this->ImitatedPeerPort; DReq.srcIp = 0; DReq.srcPort = 0; Error = g_IcqPeerDispatcherp->DeleteDispatchRequest(&DReq); if(Error) { ICQ_TRC(TM_MSG, TL_ERROR, ("** !! Can't delete CLIENT Incoming Dispatch Req !! **")); } if ( FAILED( g_IcqPeerDispatcherp->RemoveDispatchee(this) ) ) { ICQ_TRC(TM_MSG, TL_ERROR, ("** !! Can't remove Dispatchee ")); ASSERT( FALSE); } // // Dereference the the Shared ClientSocketp if(ClientSocketp != NULL) { DEREF_COMPONENT( this->ClientSocketp, eRefInitialization ); this->ClientSocketp = NULL; } // // delete and/or Dereference the ServerSocketp if(ServerSocketp != NULL) { STOP_COMPONENT(ServerSocketp); DEREF_COMPONENT( this->ServerSocketp, eRefInitialization ); this->ServerSocketp; } // // Clear the Shadow Mappings if therer are any. // if(this->ShadowRedirectp != NULL) { this->ShadowRedirectp->Cancel(); this->ShadowRedirectp->Release(); this->ShadowRedirectp = NULL; } if ( IncomingPeerControlRedirectionp != NULL) { IncomingPeerControlRedirectionp->Cancel(); IncomingPeerControlRedirectionp->Release(); IncomingPeerControlRedirectionp = NULL; this->IncomingRedirectForPeerToClientp = NULL; } this->bCleanupCalled = TRUE; } // _ICQ_CLIENT::ComponentCleanUpRoutine void _ICQ_CLIENT::StopSync(void) /*++ Routine Description: We have to delete the ASYNC elements in the Peers or within the current Sockets. The Reads that are issued will have references to this components which needs to be removed for a complete Garbage collection. This component has to be declared deleted so that no body tries to reference it anymore. It also needs to travers the Peer structures and call the related StopSyncs approptiately. Then set this component as deleted. Arguments: none. Return Value: --*/ { PICQ_PEER IcqPeerp = NULL; ICQ_TRC(TM_MSG, TL_TRACE, ("%s> Stopping the COMPONENT", this->GetObjectName())); // // Stop the ServerSocketp STOP_COMPONENT(this->ServerSocketp); // // for each peer Element Call the STOP_COMPONENT. // It is important that the Peer Elements are not deleted here. // for(IcqPeerp = dynamic_cast(this->IcqPeerList.SearchNodeKeys(0,0)); IcqPeerp != NULL; IcqPeerp = dynamic_cast(this->IcqPeerList.SearchNodeKeys(0,0)) ) { STOP_COMPONENT(IcqPeerp); } this->Deleted = TRUE; } // _ICQ_CLIENT::StopSync ULONG _ICQ_CLIENT::DispatchCompletionRoutine(PDispatchReply DispatchReplyp) /*++ Routine Description: Arguments: none. Return Value: --*/ { PICQ_PEER IcqPeerp = NULL; PCNhSock * cupHolder = NULL; ULONG Error = NO_ERROR; // if(DispatchReplyp is NULL) return 0; ASSERT on it? ICQ_TRC(TM_MSG, TL_TRACE, (" Dispatch Completion Routine of ICQcl ")); // // Find the Appropriate Peer entry which has caused this completion routine // Note that all the peer entries have the UIN as the search Key. // thus if this Reply has the IcqFlagOutgoing as the flag we should just // Look at this list to see which or where we're sending.. // Otherwise we should look at the src addresses and either way we have to // scan the whole List to find the appropriate entry. // for(IcqPeerp = dynamic_cast (this->IcqPeerList.SearchNodeKeys(0, 0)); IcqPeerp != NULL; IcqPeerp = dynamic_cast(IcqPeerp->Nextp)) { if(DispatchReplyp->dispatch.DirectionContext is IcqFlagOutgoing) { if(IcqPeerp->PeerIp is DispatchReplyp->dispatch.dstIp && IcqPeerp->PeerPort is DispatchReplyp->dispatch.dstPort) { ICQ_TRC(TM_MSG, TL_TRACE, ("connection from inside to UIN %lu", IcqPeerp->PeerUIN)); IcqPeerp->ToClientSocketp = DispatchReplyp->Socketp; cupHolder = &IcqPeerp->ToClientSocketp ; IcqPeerp->MappingDirection = IcqFlagOutgoing; break; } } else // Incoming. BUG BUG: add feature #14 from -The- TEXT { //DispatchReplyp->dispatch.srcPort; if(IcqPeerp->PeerIp is DispatchReplyp->dispatch.srcIp) { ICQ_TRC(TM_MSG, TL_TRACE, ("connection -from- UIN %lu", IcqPeerp->PeerUIN)); IcqPeerp->ToPeerSocketp = DispatchReplyp->Socketp; cupHolder = &IcqPeerp->ToPeerSocketp ; DispatchReplyp->dispatch.dstIp = this->ClientIp; DispatchReplyp->dispatch.dstPort = this->ClientToPeerPort; IcqPeerp->MappingDirection = IcqFlagIncoming; break; } } // if-else } // for if(IcqPeerp is NULL) { ICQ_TRC(TM_MSG, TL_ERROR, ("NO IcqPeer has been found DELETING THE ACCEPTED SOCKET")); ReportExistingPeers(); DEREF_COMPONENT( DispatchReplyp->Socketp, eRefInitialization ); delete DispatchReplyp; return 0; } if(Error = IcqPeerp->InitiatePeerConnection(DispatchReplyp)) { ICQ_TRC(TM_MSG, TL_ERROR, ("Error - Initiation Peer connection has failed ")); STOP_COMPONENT(DispatchReplyp->Socketp); DEREF_COMPONENT( DispatchReplyp->Socketp, eRefInitialization ); *cupHolder = NULL; } delete DispatchReplyp; return Error; } ULONG _ICQ_CLIENT::Initialize( PNH_BUFFER Bufferp, ULONG clientIp, USHORT clientPort, ULONG serverIp, USHORT serverPort, PCNhSock localClientSocketp ) /*++ Routine Description: If there are existing set of informations then it should be noted that, We need to make a consistency check or pass on them. A new client ~ server session may effect the ongoing TCP streams.. Thus the decisions should be made wisely as it would mean of scavenging a lot of resources and cycles. - Initialy we don't have any data so, we store them. - Here we get the local TCP port information and need to create mappings for them. (defered) Arguments: none. Return Value: --*/ { ULONG hr = S_OK; ASSERT(Bufferp != NULL); ASSERT(localClientSocketp != NULL); do { if(this->ClientIp != 0) { ICQ_TRC(TM_MSG, TL_ERROR, ("** !! ERROR - RE-INITING of client %s", INET_NTOA(ClientIp))); ASSERT( FALSE ); } else // first time init { ULONG InterfaceIp; this->ClientIp = clientIp; this->ClientToServerPort = clientPort; this->ServerIp = serverIp; this->ServerPort = serverPort; // // Since we're sharing the socket back to the client // it should be properly referenced so that it is not deleted randomly // ClientSocketp = localClientSocketp; REF_COMPONENT( localClientSocketp, eRefIoSharing ); // // Create a new UDP socket; // NEW_OBJECT( ServerSocketp, CNhSock ); if( ServerSocketp is NULL ) { ICQ_TRC(TM_MSG, TL_ERROR, ("** !! Socket Creation hr")); hr = E_OUTOFMEMORY; break; } InterfaceIp = InterfaceForDestination(ServerIp); ICQ_TRC(TM_MSG, TL_TRACE, ("The InterfaceIP for the PRoxy ~ Server is %s", INET_NTOA(InterfaceIp))); hr = ServerSocketp->NhCreateDatagramSocket(InterfaceIp, 0, NULL); if ( hr ) { ICQ_TRC(TM_MSG, TL_ERROR, ("CLI !!> Socket Creation hr")); hr = HRESULT_FROM_WIN32( hr ); break; } PICQ_CLIENT tempClientp = this; REF_COMPONENT( tempClientp, eRefIoRead ); // issue a Read operation on the Server Socket here. hr = ServerSocketp->NhReadDatagramSocket(g_IcqComponentReferencep, NULL, ReadServerCompletionRoutine, this, NULL); if ( hr ) { ICQ_TRC(TM_MSG, TL_ERROR, ("Read hr ")); DEREF_COMPONENT( tempClientp, eRefIoRead ); hr = HRESULT_FROM_WIN32( hr ); break; } // // Initialize Once. // hr = g_IcqPeerDispatcherp->InitDispatchee(this); if ( hr ) { ASSERT( FALSE ); // handle this case later } // // Now we can pass the Buffer and the destination address to // the generic ServerRead // hr = this->ClientRead(Bufferp, serverIp, serverPort); if(hr) { ASSERT(FALSE); } } } while ( FALSE ); if ( FAILED(hr) ) { } // // The Search Key for this // this->iKey1 = clientIp; this->iKey2 = 0; return hr; } // // // ULONG _ICQ_CLIENT::ServerRead( PNH_BUFFER Bufferp, ULONG serverIp, USHORT serverPort ) /*++ Routine Description: Arguments: none. Return Value: --*/ { ULONG Error = NO_ERROR; if(Bufferp is NULL) { return E_INVALIDARG; } ICQ_TRC(TM_MSG, TL_DUMP, ("UDP - Server is Sending TO Client %s", INET_NTOA(ClientIp))); Error = IcqServerToClientUdp(Bufferp->Buffer, Bufferp->BytesTransferred); // // Write to Destination of the Processed packet // Error = ClientSocketp->NhWriteDatagramSocket(g_IcqComponentReferencep, this->ClientIp, this->ClientToServerPort, Bufferp, Bufferp->BytesTransferred, IcqWriteCompletionRoutine, NULL, NULL); if(Error) { ICQ_TRC(TM_MSG, TL_ERROR, ("** !! SRead> problem at writing to client %s", INET_NTOA(this->ClientIp))); NhReleaseBuffer(Bufferp); ErrorOut(); } return Error; } // // // ULONG _ICQ_CLIENT::ClientRead( PNH_BUFFER Bufferp, ULONG serverIp, USHORT serverPort ) /*++ Routine Description: Reads the data coming from a client, going to the server We're checking this UDP packet so that: * the client Address, and port numbers so that they are valid and up-to-date * the server address/port is also checked for verification * the packets are sent to processing function * and then UDP packets are forwarded to Server Arguments: none. Return Value: --*/ { ULONG srcIp, dstIp = this->ServerIp, Error; USHORT srcPort, dstPort = this->ServerPort; ULONG LocalIp = 0; USHORT LocalPort = 0; // // Decide = Where is the data coming from or ASSERT(Bufferp); // ASSERT(Bufferp != NULL); // // Outgoing packet reset the Timeout for this. // this->ResetTimer(); srcIp = Bufferp->ReadAddress.sin_addr.S_un.S_addr; srcPort = Bufferp->ReadAddress.sin_port; ICQ_TRC(TM_MSG, TL_DUMP, ("ICQ_CL->ClientRead> Sending TO Server %s", INET_NTOA(serverIp))); ASSERT(srcIp is ClientIp); // // ClientPort has changed. // if(srcPort != ClientToServerPort) { ICQ_TRC(TM_MSG, TL_INFO, ("CLIENT PORT HAS CHANGED !!!!!! new %hu: old %hu ", htons(srcPort), htons(ClientToServerPort))); ClientToServerPort = srcPort; } // // Decide wether shadow mapping is necessary or not. // if the destination is changed than we need another shadow mapping - delete the old one. // // // decide the Destination Address // if we have an existing mapping and the address has changed than // delete the OLD SHADOW mapping.. and re-init a new one. // if( (this->ServerIp != serverIp) || (this->ServerPort != serverPort) ) { ICQ_TRC(TM_MSG, TL_ERROR, ("!! A NEW SERVER IS SELECTED !! %s ", INET_NTOA(serverIp))); // // DELETE the existing shadow mapping if there is one. // if(this->ShadowRedirectp != NULL) { ICQ_TRC(TM_MSG, TL_TRACE, ("Cancelling the Shadow Redirect i.e. CreateProxyConnect")); Error = ShadowRedirectp->Cancel(); if( FAILED(Error) ) { ICQ_TRC(TM_MSG, TL_ERROR, ("** !! - Problemo with Cancelling ShadowRedirect- !! **")); } ShadowRedirectp->Release(); this->ShadowRedirectp = NULL; } // // store the new informaiton // this->ServerIp = serverIp; this->ServerPort = serverPort; } dstIp = this->ServerIp; dstPort = this->ServerPort; // // NOTE: Check for the Error value here.. // Process the Message // Error = IcqClientToServerUdp(Bufferp->Buffer, Bufferp->BytesTransferred); if(Error) { ICQ_TRC(TM_MSG, TL_ERROR, ("Can't Allocate enough resource for Login Packet")); NhReleaseBuffer(Bufferp); return Error; } // // Check the shadow-mapping to the destination from this port. // This should have been created in the Initialization phase. // if ( this->ShadowRedirectp is NULL ) { ICQ_TRC(TM_MSG, TL_TRACE, ("!! CREATING SHADOW redirect - !!")); // // Get the local endpoint?! for src address // ServerSocketp->NhQueryLocalEndpointSocket(&LocalIp, &LocalPort); Error = g_IAlgServicesp->GetBestSourceAddressForDestinationAddress(dstIp, TRUE, &LocalIp); if( FAILED(Error) ) { ICQ_TRC(TM_MSG, TL_ERROR, ("** !! - Best Source Address for Dest Failed !! **")); ASSERT ( FALSE ); } ICQ_TRC(TM_MSG, TL_TRACE, ("Best Source address is decided as %s", INET_NTOA(LocalIp))); Error = g_IAlgServicesp->PrepareProxyConnection(eALG_UDP, LocalIp, LocalPort, dstIp, dstPort, TRUE, &ShadowRedirectp); // // If the Shadow Redirect fails don't go further. // Release the Buffer and exit, // this may be a transitory behaviour. // if( FAILED(Error) ) { ICQ_TRC(TM_MSG, TL_ERROR, (" ** !! - ShadowRedirect has Failed - proxy connection !! **")); NhReleaseBuffer(Bufferp); this->ShadowRedirectp = NULL; return E_FAIL; } } // // Write to Destination of the Processed packet // Error = ServerSocketp->NhWriteDatagramSocket(g_IcqComponentReferencep, dstIp, dstPort, Bufferp, Bufferp->BytesTransferred, IcqWriteCompletionRoutine, NULL, NULL); if(Error) { ICQ_TRC(TM_MSG, TL_ERROR, ("** !! WRITE ERROR !!! **")); NhReleaseBuffer(Bufferp); } return Error; } // // // ISecondaryControlChannel * _ICQ_CLIENT::PeerRedirection( ULONG dstIp, USHORT dstPort, ULONG srcIp OPTIONAL, USHORT srcPort OPTIONAL, ICQ_DIRECTION_FLAGS DirectionContext ) /*++ Routine Description: The Advertised PEER-CONTROL connection port is the dstPort here. This function creates the Redirection for this connection as a SecondaryControl Channel connection. Then indicates that a incoming TCP connection is going to be dispatched by the Dispatcher Class to us. So it request a Dispatch Service. Arguments: none. Return Value: --*/ { ULONG Error = NO_ERROR; ISecondaryControlChannel* SecondaryControlRedirectionp = NULL; PDispatchRequest DRp = NULL; ULONG PrivateAddr = 0, PublicAddr = 0, RemoteAddr = 0, ListenAddr = 0; USHORT PrivatePort = 0, PublicPort = 0, RemotePort = 0, ListenPort = 0; do { // // step 2 - create a redirection for the TCP packets destined to this port // NOTE: should we change this to a FULL redirect one? // g_IcqPeerDispatcherp->GetDispatchInfo( &ListenAddr, &ListenPort ); ICQ_TRC(TM_MSG, TL_DUMP, ("Listen addr of Dispatcher %s(%hu)", INET_NTOA(ListenAddr), ListenPort)); ASSERT ( ListenAddr != 0 ); ASSERT ( ListenPort != 0 ); if ( DirectionContext is eALG_INBOUND ) { PrivateAddr = 0; PrivatePort = 0; PublicAddr = dstIp; PublicPort = dstPort; RemoteAddr = 0; RemotePort = 0; ICQ_TRC(TM_MSG, TL_INFO, ("CLIENT_CONTROL_CHANNEL> Inbound %s:%hu -> Local:%hu", INET_NTOA(dstIp), htons(dstPort), htons(ListenPort))); } else if ( DirectionContext is eALG_OUTBOUND ) { PrivateAddr = srcIp; PrivatePort = srcPort; PublicAddr = 0; PublicPort = 0; RemoteAddr = dstIp; RemotePort = dstPort; ICQ_TRC(TM_MSG, TL_INFO, ("CLIENT_CONTROL_CHANNEL> Outbound %s:%hu <- Local:%hu", INET_NTOA(dstIp), htons(dstPort), htons(ListenPort))); ICQ_TRC(TM_MSG, TL_INFO, ("PEER_CONTROL_CHANNEL> Restrict SRC to %s:%u", INET_NTOA(PrivateAddr), htons(PrivatePort))); } else { ASSERT(FALSE); } Error = g_IAlgServicesp->CreateSecondaryControlChannel(eALG_TCP, PrivateAddr, PrivatePort, PublicAddr, PublicPort, RemoteAddr, RemotePort, ListenAddr, ListenPort, (ALG_DIRECTION)DirectionContext, FALSE, &SecondaryControlRedirectionp); if( FAILED(Error) || (SecondaryControlRedirectionp is NULL) ) { ICQ_TRC(TM_MSG, TL_ERROR, ("Can't create the secondary ctrl redirect")); ASSERT(FALSE); break; } // // step 3 - Request a Dispatch for this TCP redirection // NEW_OBJECT( DRp, DispatchRequest ); if ( DRp is NULL ) { Error = E_OUTOFMEMORY; // // clear redirect // SecondaryControlRedirectionp->Cancel(); SecondaryControlRedirectionp->Release(); SecondaryControlRedirectionp = NULL; ICQ_TRC(TM_MSG, TL_ERROR, ("Error - Out of memory to create a new DispatchRequest")); break; } DRp->dstIp = dstIp; // * DRp->dstPort = dstPort; //* DRp->srcIp = srcIp; DRp->srcPort = srcPort; DRp->DirectionContext = DirectionContext; // // set the search Keys. // DRp->iKey1 = dstIp; DRp->iKey2 = dstPort; g_IcqPeerDispatcherp->AddDispatchRequest ( this, DRp ); // // Store the redirect, to be used in Searches. // if ( DirectionContext is eALG_INBOUND ) { this->IncomingRedirectForPeerToClientp = SecondaryControlRedirectionp; } // // Relinquish the ownwership of the request // DEREF_COMPONENT( DRp, eRefInitialization ); } while (FALSE); return SecondaryControlRedirectionp; } // _ICQ_CLIENT::PeerRedirection // scan the list to get the peers //CLIST g_IcqClientList; PICQ_CLIENT ScanTheListForLocalPeer ( PULONG PeerIp, PUSHORT PeerPort, ULONG IcqUIN ) /*++ Routine Description: Arguments: none. Return Value: --*/ { PICQ_CLIENT IcqClientp = NULL; for(IcqClientp = dynamic_cast(g_IcqClientList.SearchNodeKeys(0, 0)); IcqClientp != NULL; IcqClientp = dynamic_cast(IcqClientp->Nextp) ) { // // IF we have a hit return TRUE otherwise don't change anything // if(IcqClientp->UIN is IcqUIN) { if(PeerIp != NULL) { if(IcqClientp->ClientIp is g_MyPublicIp) { *PeerIp = g_MyPrivateIp; } else { *PeerIp = IcqClientp->ClientIp; } } if(PeerPort != NULL) { *PeerPort = IcqClientp->ClientToPeerPort; } return IcqClientp; } } return NULL; } // // Debugging utilities. // VOID _ICQ_CLIENT::ReportExistingPeers(VOID) /*++ Routine Description: Report Informations about the All the Peers existing for this client. Arguments: none. Return Value: none. --*/ { PICQ_PEER IcqPeerp = NULL; for(IcqPeerp = dynamic_cast (this->IcqPeerList.SearchNodeKeys(0, 0)); IcqPeerp != NULL; IcqPeerp = dynamic_cast(IcqPeerp->Nextp)) { ICQ_TRC(TM_MSG, TL_INFO, ("PeerIP(PORT) is %s(%hu)", INET_NTOA(IcqPeerp->PeerIp), htons(IcqPeerp->PeerPort))); ICQ_TRC(TM_MSG, TL_TRACE, ("IncomingDataRedirect %s, OutgoingRedirect %s, MappingDirection %s, "\ "ShadowRedirect %s, ToClientSocketp %s, ToPeerSocketp %s", (IcqPeerp->IncomingDataRedirectp is NULL)?"FALSE":"TRUE", (IcqPeerp->OutgoingPeerControlRedirectp is NULL)?"FALSE":"TRUE", (IcqPeerp->MappingDirection is eALG_OUTBOUND)?"OUT":"IN", (IcqPeerp->ShadowRedirectp is NULL)?"FALSE":"TRUE", (IcqPeerp->ToClientSocketp is NULL)?"FALSE":"TRUE", (IcqPeerp->ToPeerSocketp is NULL)?"FALSE":"TRUE")); } } ULONG _ICQ_CLIENT::DeleteTimer(TIMER_DELETION bHow) { if(this->TimerContextp != NULL) { if(bHow is eTIMER_DELETION_SYNC) { DeleteTimerQueueTimer(g_TimerQueueHandle, this->TimerContextp->TimerHandle, INVALID_HANDLE_VALUE); } else if(bHow is eTIMER_DELETION_ASYNC) { DeleteTimerQueueTimer(g_TimerQueueHandle, this->TimerContextp->TimerHandle, NULL); } NH_FREE(this->TimerContextp); this->TimerContextp = NULL; } return NO_ERROR; } ULONG _ICQ_CLIENT::ResetTimer(VOID) { this->DeleteTimer(eTIMER_DELETION_SYNC); this->TimerContextp = AllocateAndSetTimer(this->UIN, ICQ_CLIENT_TIMEOUT, IcqClientTimeoutHandler); if(TimerContextp != NULL) { return S_OK; } return E_FAIL; } // typedef VOID (NTAPI * WAITORTIMERCALLBACKFUNC) (PVOID, BOOLEAN ); // winnt VOID NTAPI IcqClientTimeoutHandler( PVOID Parameterp, BOOLEAN TimerOrWaitFired ) { PTIMER_CONTEXT TimerContextp = (PTIMER_CONTEXT)Parameterp; PICQ_CLIENT IcqClientp = NULL; if(TimerContextp is NULL) { return; } PROFILER(TM_TIMER, TL_INFO, ("TIME-OUT for Client (%u)", TimerContextp->uContext)); IcqClientp = ScanTheListForLocalPeer(NULL, NULL, TimerContextp->uContext); // // Delete the Client Here // if(IcqClientp != NULL) { IcqClientp->DeleteTimer(eTIMER_DELETION_ASYNC); g_IcqClientList.RemoveNodeFromList(IcqClientp); // stops and derefs } else { ASSERT(FALSE); } }