#include "precomp.h" DEBUG_FILEZONE(ZONE_T120_MCSNC); /* * connect.cpp * * Copyright (c) 1993 - 1995 by DataBeam Corporation, Lexington, KY * * Abstract: * This is the implementation file for class Connection. It contains * all code necessary to encode MCS commands as T.125 PDUs, and to * decode T.125 back into MCS commands. * * The primary responsibility of this class is to act as a Remote * Procedure Call facility for MCS commands. A CommandTarget object * uses a Connection object to encode an MCS command as a PDU, and send it * across to a remote Connection object. That Connection object will * decode the PDU back into an MCS command, at which time it will send * it to the attached CommandTarget object on that side. The intervening * transport layer is transparent to the CommandTargets utilizing * Connection class services. * * A secondary responsibility of this class is to provide a layer of * flow control between the attached CommandTarget object and the * transport layer. PDUs are queued until the transport layer can take * them. * * Private Instance Variables: * Encoding_Rules * This is a variable which holds a value indicating what type of * rules (Basic or Packed) are used for encoding and decoding the PDUs. * m_pDomain * This is a pointer to the domain to which this connection is bound. * m_pPendingDomain * This is a pointer to the domain to which this connection will be * bound upon successful completion of the connection process. * Connection_Handle * This is the handle for the current transport connection. It allows * callback functions to be associated with the current transport * connection so that any events which occur on this transport * connection will be routed to any object that has registered its * callbacks. * m_pszCalledAddress * The transport address of the party being called. * Upward_Connection * This is a boolean flag which indicates whether or not this is * an upward connection. * Domain_Parameters * This is a structure which holds the set of domain parameters * associated with this connection. * Connect_Response_Memory * This is a pointer to a memory object which is used to hold any * user data contained within a ConnectResponse PDU. * Merge_In_Progress * This is a boolean flag that indicates whether or not the attached * Domain object is in the merge state. When in the merge state it * is invalid to send it any MCS commands. * Domain_Traffic_Allowed * This is a boolean flag used to indicate when this connection object * has been successfully created and bound to the domain, thus allowing * PDU traffic to commence. * Connect_Provider_Confirm_Pending * This is a boolean flag used to dictate the behavior if this * connection becomes invalid. If a connect provider confirm is * pending when the connection becomes invalid, then a failed confirm * is issued to the controller. If there is not a confirm pending, * then we simply issue a delete connection to the controller. * Transport_Connection * This is an array used to hold handles for the transport connections * available for use by this connection object. There is a transport * connection associated with each of the four data priorities. * Transport_Connection_PDU_Type * This is an array which holds values indicating what type of PDU * (Connect or Domain) is expected for each priority level. * Transport_Connection_State * This is an array which holds values indicating the state of the * transport connection associated with each prioriy level. * Transport_Connection_Count * This is a counter which keeps track of the number of transport * connections. * m_OutPktQueue * This is a queue used to hold data units to be transmitted. * * Private Member Functions: * ConnectInitial * This routine is called by the domain when a connection is being * created. It places the necessary domain information into a data * packet and queues the data to be transmitted through the transport * interface. * ConnectResponse * This routine is called when issuing a response to a * "ConnectInitial" PDU. The result of the attempted connection, the * connection ID, the domain parameters, and any user data are all put * into the packet and queued for transmission through the transport * interface. If the result of the attempted connection is negative, * the controller and transport interface are notified. * ConnectAdditional * This routine is called after successfully processing a * "ConnectResponse" PDU in order to create any addition necessary * transport connections. * ConnectResult * This routine is called indirectly when issuing a positive response * to a "ConnectAdditional" PDU. The "ConnectAdditional" PDUs are * processed by the controller and therefore any negative * "ConnectResult" PDU will be issued by the controller. * ProcessConnectResponse * This routine processes "Connect Response" PDU's coming from the * transport interface. Domain parameters are retrieved and the * PDU sent on to the proper domain. * ProcessConnectResult * This routine processes "Connect Result" PDU's coming from the * transport interface. For successful "Connect Result" PDU's this * connection is bound to the domain and a positive Connect Provider * Confirm issued to the controller. If unsuccessful, a negative * Connect Provider Confirm is issued to the controller. * IssueConnectProviderConfirm * This routine is called in order to send a "Connect Provider Confirm" * to the controller through a callback. * DestroyConnection * This routine is called in order to delete this connection because it * has become invalid. This is done by issuing a failed confirm to the * controller or, if no confirm is pending, by issuing a delete * connection to the controller. * AssignRemainingTransportConnections * This routine is called when there are no more transport connections * to create in order to copy the lowest priority transport connection * into all unassigned priorities. * CreateTransportConnection * This routine is called in order to create new transport connections. * AcceptTransportConnection * This routine is called in order to register this connection object * with the transport interface. * AdjustDomainParameters * This routine is called in order to adjust the domain parameters so * that they fall within the allowable range. * MergeDomainParameters * This routine is called in order to calculate the optimum overlap * between the local and remote domain parameters. If there is no * overlap, this routine will return a value causing this connection * to be destroyed. * PrintDomainParameters * This routine is used for debug purposes in order to print out the * current set of domain parameters. * SendPacket * This routine is called in order to create a packet which will hold * the PDU to be sent to the remote provider. The packet will be * queued up for transmission through the transport interface. * QueueForTransmission * This routine places data units into the transmission queue so * they can be transmitted through the transport interface when * possible. * ProcessMergeChannelsRequest * This routine processes "Merge Channel Request" PDU's coming from the * transport interface by retrieving any necessary information from the * packet and sending the PDU on to the proper domain. * ProcessMergeChannelsConfirm * This routine processes "Merge Channel Confirm" PDU's coming from the * transport interface by retrieving any necessary information from the * packet and sending the PDU on to the proper domain. * ProcessPurgeChannelsIndication * This routine processes "Purge Channel Indication" PDU's coming from * the transport interface by retrieving any necessary information from * the packet and sending the PDU on to the proper domain. * ProcessMergeTokenRequest * This routine processes "Merge Token Request" PDU's coming from the * transport interface by retrieving any necessary information from the * packet and sending the PDU on to the proper domain. * ProcessMergeTokenConfirm * This routine processes "Merge Token Confirm" PDU's coming from the * transport interface by retrieving any necessary information from the * packet and sending the PDU on to the proper domain. * ProcessPurgeTokenIndication * This routine processes "Purge Token Indication" PDU's coming from * the transport interface by retrieving any necessary information from * the packet and sending the PDU on to the proper domain. * ProcessDisconnectProviderUltimatum * This routine processes "Disconnect Provider Ultimatum" PDU's coming * from the transport interface by retrieving any necessary information * from the packet and sending the PDU on to the proper domain. * ProcessAttachUserRequest * This routine processes "Attach User Request" PDU's coming from the * transport interface by sending the PDU on to the proper domain. * ProcessAttachUserConfirm * This routine processes "Attach User Confirm" PDU's coming from the * transport interface by retrieving any necessary information from the * packet and sending the PDU on to the proper domain. * ProcessDetachUserRequest * This routine processes "Detach User Request" PDU's coming from the * transport interface by retrieving any necessary information from the * packet and sending the PDU on to the proper domain. * ProcessDetachUserIndication * This routine processes "Detach User Request" PDU's coming from the * transport interface by retrieving any necessary information from the * packet and sending the PDU on to the proper domain. * ProcessChannelJoinRequest * This routine processes "Channel Join Request" PDU's coming from the * transport interface by retrieving any necessary information from the * packet and sending the PDU on to the proper domain. * ProcessChannelJoinConfirm * This routine processes "Channel Join Confirm" PDU's coming from the * transport interface by retrieving any necessary information from the * packet and sending the PDU on to the proper domain. * ProcessChannelLeaveRequest * This routine processes "Channel Leave Request" PDU's coming from the * transport interface by retrieving any necessary information from the * packet and sending the PDU on to the proper domain. * ProcessChannelConveneRequest * This routine processes the "ChannelConveneRequest" PDU's being * received through the transport interface. The pertinent data is * read from the incoming packet and passed on to the domain. * ProcessChannelConveneConfirm * This routine processes the "ChannelConveneConfirm" PDU's being * received through the transport interface. The pertinent data is * read from the incoming packet and passed on to the domain. * ProcessChannelDisbandRequest * This routine processes the "ChannelDisbandRequest" PDU's being * received through the transport interface. The pertinent data is * read from the incoming packet and passed on to the domain. * ProcessChannelDisbandIndication * This routine processes the "ChannelDisbandIndication" PDU's being * received through the transport interface. The pertinent data is * read from the incoming packet and passed on to the domain. * ProcessChannelAdmitRequest * This routine processes the "ChannelAdmitRequest" PDU's being * received through the transport interface. The pertinent data is * read from the incoming packet and passed on to the domain. * ProcessChannelAdmitIndication * This routine processes the "ChannelAdmitIndication" PDU's being * received through the transport interface. The pertinent data is * read from the incoming packet and passed on to the domain. * ProcessChannelExpelRequest * This routine processes the "ChannelExpelRequest" PDU's being * received through the transport interface. The pertinent data is * read from the incoming packet and passed on to the domain. * ProcessChannelExpelIndication * This routine processes the "ChannelExpelIndication" PDU's being * received through the transport interface. The pertinent data is * read from the incoming packet and passed on to the domain. * ProcessSendDataRequest * This routine processes "Send Data Request" PDU's coming from the * transport interface by retrieving any necessary information from the * packet, allocating any memory needed, and sending the PDU on to the * proper domain. * ProcessSendDataIndication * This routine processes "Send Data Indication" PDU's coming from the * transport interface by retrieving any necessary information from the * packet, allocating any memory needed, and sending the PDU on to the * proper domain. * ProcessUniformSendDataRequest * This routine processes "Uniform Send Data Indication" PDU's coming * from the transport interface by retrieving any necessary information * from the packet, allocating any memory needed, and sending the PDU * on to the proper domain. * ProcessUniformSendDataIndication * This routine processes "Uniform Send Data Indication" PDU's coming * from the transport interface by retrieving any necessary information * from the packet, allocating any memory needed, and sending the PDU * on to the proper domain. * ProcessTokenGrabRequest * This routine processes "Token Grab Request" PDU's coming from the * transport interface by retrieving any necessary information from the * packet and sending the PDU on to the proper domain. * ProcessTokenGrabConfirm * This routine processes "Token Grab Confirm" PDU's coming from the * transport interface by retrieving any necessary information from the * packet and sending the PDU on to the proper domain. * ProcessTokenInhibitRequest * This routine processes "Token Inhibit Request" PDU's coming from the * transport interface by retrieving any necessary information from the * packet and sending the PDU on to the proper domain. * ProcessTokenInhibitConfirm * This routine processes "Token Inhibit Confirm" PDU's coming from the * transport interface by retrieving any necessary information from the * packet and sending the PDU on to the proper domain. * ProcessTokenReleaseRequest * This routine processes "Token Release Request" PDU's coming from the * transport interface by retrieving any necessary information from the * packet and sending the PDU on to the proper domain. * ProcessTokenReleaseConfirm * This routine processes "Token Release Confirm" PDU's coming from the * transport interface by retrieving any necessary information from the * packet and sending the PDU on to the proper domain. * ProcessTokenTestRequest * This routine processes "Token Test Request" PDU's coming from the * transport interface by retrieving any necessary information from the * packet and sending the PDU on to the proper domain. * ProcessTokenTestConfirm * This routine processes "Token Test Confirm" PDU's coming from the * transport interface by retrieving any necessary information from the * packet and sending the PDU on to the proper domain. * ProcessRejectUltimatum * This routine processes "RejectUltimatum" PDU's coming from the * transport interface by retrieving any necessary information from the * packet and sending the PDU on to the proper domain. * ProcessTokenGiveRequest * This routine processes "TokenGiveRequest" PDU's coming from the * transport interface by retrieving any necessary information from the * packet and sending the PDU on to the proper domain. * ProcessTokenGiveIndication * This routine processes "TokenGiveIndication" PDU's coming from the * transport interface by retrieving any necessary information from the * packet and sending the PDU on to the proper domain. * ProcessTokenGiveResponse * This routine processes "TokenGiveResponse" PDU's coming from the * transport interface by retrieving any necessary information from the * packet and sending the PDU on to the proper domain. * ProcessTokenGiveConfirm * This routine processes "TokenGiveConfirm" PDU's coming from the * transport interface by retrieving any necessary information from the * packet and sending the PDU on to the proper domain. * ProcessTokenPleaseRequest * This routine processes "TokenPleaseRequest" PDU's coming from the * transport interface by retrieving any necessary information from the * packet and sending the PDU on to the proper domain. * ProcessTokenPleaseIndication * This routine processes "TokenPleaseIndication" PDU's coming from the * transport interface by retrieving any necessary information from the * packet and sending the PDU on to the proper domain. * ProcessPlumbDomainIndication * This routine processes "PlumbDomainIndication" PDU's coming from the * transport interface by retrieving any necessary information from the * packet and sending the PDU on to the proper domain. * ProcessErectDomainRequest * This routine processes "ErectDomainRequest" PDU's coming from the * transport interface by retrieving any necessary information from the * packet and sending the PDU on to the proper domain. * ValidateConnectionRequest * This function is used to determine if it is valid to process an * incoming request at the current time. * * Caveats: * None. * * Author: * James P. Galvin, Jr. * John B. O'Nan */ /* * External Interfaces */ #include "omcscode.h" #include "tprtntfy.h" #include "plgxprt.h" /* * This is a global variable that has a pointer to the one MCS coder that * is instantiated by the MCS Controller. Most objects know in advance * whether they need to use the MCS or the GCC coder, so, they do not need * this pointer in their constructors. */ extern CMCSCoder *g_MCSCoder; // The external MCS Controller object extern PController g_pMCSController; // The global TransportInterface pointer (for transport access) extern PTransportInterface g_Transport; /* * Connection () * * Public * * Functional Description: * This is a constructor for the Connection class. This constructor * is used for creating outbound connections. It initializes private * instance variables and calls the transport interface to set up a * transport connection and register this connection object (through a * callback structure) with the transport object. * * Caveats: * None. */ Connection::Connection ( PDomain attachment, ConnectionHandle connection_handle, GCCConfID *calling_domain, GCCConfID *called_domain, PChar called_address, BOOL fSecure, BOOL upward_connection, PDomainParameters domain_parameters, PUChar user_data, ULong user_data_length, PMCSError connection_error ) : CAttachment(CONNECT_ATTACHMENT), Encoding_Rules (BASIC_ENCODING_RULES), m_pDomain(NULL), m_pPendingDomain(attachment), Connection_Handle (connection_handle), Upward_Connection (upward_connection), Deletion_Reason (REASON_USER_REQUESTED), Connect_Response_Memory (NULL), Merge_In_Progress (FALSE), Domain_Traffic_Allowed (FALSE), Connect_Provider_Confirm_Pending (TRUE), m_fSecure(fSecure) { UINT priority; TransportError transport_error; DomainParameters min_domain_parameters; DomainParameters max_domain_parameters; BOOL fPluggableTransport = ::GetPluggableTransportConnID((LPCSTR) called_address); /* * If the passed in pointer is valid, then set the local domain * parameters to the values contained therein. Otherwise, use * defaults for everything. */ if (domain_parameters != NULL) Domain_Parameters = *domain_parameters; else { /* * Use default values for all domain parameters. */ Domain_Parameters.max_channel_ids = DEFAULT_MAXIMUM_CHANNELS; Domain_Parameters.max_user_ids = DEFAULT_MAXIMUM_USERS; Domain_Parameters.max_token_ids = DEFAULT_MAXIMUM_TOKENS; Domain_Parameters.number_priorities = DEFAULT_NUMBER_OF_PRIORITIES; Domain_Parameters.min_throughput = DEFAULT_MINIMUM_THROUGHPUT; Domain_Parameters.max_height = DEFAULT_MAXIMUM_DOMAIN_HEIGHT; Domain_Parameters.max_mcspdu_size = DEFAULT_MAXIMUM_PDU_SIZE; Domain_Parameters.protocol_version = DEFAULT_PROTOCOL_VERSION; if (fPluggableTransport || g_fWinsockDisabled) { Domain_Parameters.number_priorities = DEFAULT_NUM_PLUGXPRT_PRIORITIES; } } /* * Initialize the arrays indicating that the transport connections * are not yet valid, and that none of the queues have data in them * yet. */ for (priority = 0; priority < MAXIMUM_PRIORITIES; priority++) { Transport_Connection_State[priority] = TRANSPORT_CONNECTION_UNASSIGNED; } Transport_Connection_Count = 0; if (NULL == (m_pszCalledAddress = ::My_strdupA(called_address))) { ERROR_OUT(("Connection::Connection: can't create called address")); *connection_error = MCS_ALLOCATION_FAILURE; return; } /* * Send a connect request to the transport layer to create the Top * Priority transport connection. */ transport_error = CreateTransportConnection (m_pszCalledAddress, m_fSecure, TOP_PRIORITY); if (transport_error == TRANSPORT_NO_ERROR) { /* * Call upon the domain to find out the appropriate minimum and * maximum domain parameter values. Then call a private member * function to adjust the target parameters to fit into that range. */ m_pPendingDomain->GetDomainParameters(NULL, &min_domain_parameters, &max_domain_parameters); AdjustDomainParameters (&min_domain_parameters, &max_domain_parameters, &Domain_Parameters); #ifdef DEBUG TRACE_OUT (("Connection::Connection: CONNECT_INITIAL target parameters")); PrintDomainParameters (&Domain_Parameters); TRACE_OUT (("Connection::Connection: CONNECT_INITIAL minimum parameters")); PrintDomainParameters (&min_domain_parameters); TRACE_OUT (("Connection::Connection: CONNECT_INITIAL maximum parameters")); PrintDomainParameters (&max_domain_parameters); #endif // DEBUG /* * Issue the ConnectInitial on the newly created transport * connection. Note that the queue will not actually try to * send the data until the confirm is received from the * transport layer. */ ConnectInitial (calling_domain, called_domain, Upward_Connection, &Domain_Parameters, &min_domain_parameters, &max_domain_parameters, user_data, user_data_length); *connection_error = MCS_NO_ERROR; } else { WARNING_OUT (("Connection::Connection: transport ConnectRequest failed")); /* * Set the return code according to the nature of the failure. */ switch (transport_error) { case TRANSPORT_MEMORY_FAILURE: *connection_error = MCS_ALLOCATION_FAILURE; break; case TRANSPORT_SECURITY_FAILED: *connection_error = MCS_SECURITY_FAILED; break; default: *connection_error = MCS_TRANSPORT_NOT_READY; break; } } } /* * Connection () * * Public * * Functional Description: * This is a constructor for the Connection class. This constructor is * used for creating inbound connections and is called when a transport * connection already exists. It initializes private instance variables * and calls the transport interface to register this connection object * (through a callback structure) with the transport object. * * Caveats: * None. */ Connection::Connection ( PDomain attachment, ConnectionHandle connection_handle, TransportConnection transport_connection, BOOL upward_connection, PDomainParameters domain_parameters, PDomainParameters min_domain_parameters, PDomainParameters max_domain_parameters, PUChar user_data, ULong user_data_length, PMCSError connection_error) : CAttachment(CONNECT_ATTACHMENT), m_pszCalledAddress(NULL), Encoding_Rules (BASIC_ENCODING_RULES), m_pDomain(NULL), m_pPendingDomain(attachment), Connection_Handle (connection_handle), Upward_Connection (upward_connection), Deletion_Reason (REASON_USER_REQUESTED), Connect_Response_Memory (NULL), Merge_In_Progress (FALSE), Domain_Traffic_Allowed (FALSE), Connect_Provider_Confirm_Pending (FALSE) { UINT priority; TransportError transport_error; DomainParameters local_min_domain_parameters; DomainParameters local_max_domain_parameters; // // BUGBUG: set m_fSecure from transport connection? // /* * If the passed in pointer is valid, then set the local domain * parameters to the values contained therein. Otherwise, use * defaults for everything. */ if (domain_parameters != NULL) Domain_Parameters = *domain_parameters; else { /* * Use default values for all domain parameters. */ Domain_Parameters.max_channel_ids = DEFAULT_MAXIMUM_CHANNELS; Domain_Parameters.max_user_ids = DEFAULT_MAXIMUM_USERS; Domain_Parameters.max_token_ids = DEFAULT_MAXIMUM_TOKENS; Domain_Parameters.number_priorities = DEFAULT_NUMBER_OF_PRIORITIES; Domain_Parameters.min_throughput = DEFAULT_MINIMUM_THROUGHPUT; Domain_Parameters.max_height = DEFAULT_MAXIMUM_DOMAIN_HEIGHT; Domain_Parameters.max_mcspdu_size = DEFAULT_MAXIMUM_PDU_SIZE; Domain_Parameters.protocol_version = DEFAULT_PROTOCOL_VERSION; if (IS_PLUGGABLE(transport_connection) || g_fWinsockDisabled) { Domain_Parameters.number_priorities = DEFAULT_NUM_PLUGXPRT_PRIORITIES; } } /* * Initialize the arrays indicating that the transport connections * are not yet valid, and that none of the queues have data in them * yet. */ for (priority=0; priority < MAXIMUM_PRIORITIES; priority++) { Transport_Connection_State[priority] = TRANSPORT_CONNECTION_UNASSIGNED; } Transport_Connection_Count = 0; transport_error = AcceptTransportConnection (transport_connection, TOP_PRIORITY); if (transport_error == TRANSPORT_NO_ERROR) { /* * Call the domain object to find out the local minimum and maximum * permissible values for the domain parameters. */ m_pPendingDomain->GetDomainParameters (NULL, &local_min_domain_parameters, &local_max_domain_parameters); /* * Now call a private member function to calculate the optimum overlap * between the local and remote domain parameters. Note that if there * is no overlap, this connection will be destroyed. */ if (MergeDomainParameters (min_domain_parameters, max_domain_parameters, &local_min_domain_parameters, &local_max_domain_parameters)) { /* * The merge of the domain parameters was acceptable, so now we * must adjust the target parameters to fit within the agreed * upon range. */ AdjustDomainParameters (&local_min_domain_parameters, &local_max_domain_parameters, &Domain_Parameters); #ifdef DEBUG TRACE_OUT (("Connection::Connection: CONNECT_RESPONSE parameters")); PrintDomainParameters (&Domain_Parameters); #endif // DEBUG /* * Issue the ConnectResponse on the new transport connection. */ ConnectResponse (RESULT_SUCCESSFUL, &Domain_Parameters, Connection_Handle, user_data, user_data_length); /* * Check to see if this completes the list of transport * connections that will be used in this MCS connection. */ if (Transport_Connection_Count == Domain_Parameters.number_priorities) { /* * There are no more transport connections to accept. We must * now assign the lowest priority TC to all unassigned * priorities. */ AssignRemainingTransportConnections (); } else { /* * Issue a ConnectResult for each remaining priority. Note * that these TCs have not been created yet, so the PDUs will * remain in the queue until they are created. They are put in * the queue here to assure that they are the first PDUs * transmitted over a given TC. */ for (priority = Transport_Connection_Count; priority < Domain_Parameters.number_priorities; priority++) ConnectResult (RESULT_SUCCESSFUL, (Priority) priority); } /* * Now that we know what the domain parameters will be for this * connection, we can determine what type of encoding rules will * be used for domain PDUs (basic or packed). */ #if 0 if (Domain_Parameters.protocol_version == PROTOCOL_VERSION_BASIC) { TRACE_OUT(("Connection::Connection: using basic encoding rules")); Encoding_Rules = BASIC_ENCODING_RULES; } else #endif // 0 { TRACE_OUT (("Connection::Connection: using packed encoding rules")); Encoding_Rules = PACKED_ENCODING_RULES; } /* * Bind the pending attachment to the domain. Note that this * is necessary on the called provider in order to allow access * to domain services immediately after the return from * MCSConnectProviderResponse (which is what got us here). */ TRACE_OUT (("Connection::Connection: binding MCS connection to domain")); m_pDomain = m_pPendingDomain; m_pDomain->BindConnAttmnt(this, Upward_Connection, &Domain_Parameters); *connection_error = MCS_NO_ERROR; } else { /* * Issue the ConnectResponse informing the remote side that the * domain parameters are unacceptable. We must flush the message * queue from here to force the response packet to be transmitted. * This is because this object will be deleted by the controller * as soon as this call returns. */ WARNING_OUT (("Connection::Connection: " "unacceptable domain parameters")); ConnectResponse (RESULT_PARAMETERS_UNACCEPTABLE, &Domain_Parameters, Connection_Handle, user_data, user_data_length); FlushMessageQueue (); *connection_error = MCS_DOMAIN_PARAMETERS_UNACCEPTABLE; } } else { WARNING_OUT (("Connection::Connection: " "register transport connection failed")); *connection_error = MCS_NO_SUCH_CONNECTION; } } /* * ~Connection () * * Public * * Functional Description: * This is the destructor for the Connection class. If no connection * deletion is pending, it terminates the current connection by issuing * a DisconnectProviderUltimatum to the domain, transmitting a * "DISCONNECT_PROVIDER_ULTIMATUM" PDU, and issuing a DisconnectRequest * to the transport interface. The destructor also clears the transmission * queue and frees any allocated memory. * * Caveats: * None. */ Connection::~Connection () { DomainMCSPDU disconnect_provider_ultimatum_pdu; PSimplePacket packet; PacketError packet_error; UShort priority; /* * If we still have an upward attachment, then issue a disconnect * provider ultimatum to terminate it. */ if (m_pDomain != NULL) m_pDomain->DisconnectProviderUltimatum(this, Deletion_Reason); /* * Check to see if the Top Priority transport connection is still valid. * If so, we need to try and send a disconnect ultimatum PDU through it * before hanging up. */ if (Transport_Connection_State[TOP_PRIORITY] == TRANSPORT_CONNECTION_READY) { /* * We must first purge all packets that are waiting in the transport * queue, to expediate the disconnect process. */ ::PurgeRequest (Transport_Connection[TOP_PRIORITY]); /* * If there are any remaining data units in the queue for this * priority, walk through the list releasing all memory associated * with them. */ while (NULL != (packet = m_OutPktQueue[TOP_PRIORITY].Get())) { packet->Unlock(); } if (Domain_Traffic_Allowed) { PPacket disconnect_packet; /* * Fill in the PDU structure to be encoded. */ disconnect_provider_ultimatum_pdu.choice = DISCONNECT_PROVIDER_ULTIMATUM_CHOSEN; disconnect_provider_ultimatum_pdu.u. disconnect_provider_ultimatum.reason = (PDUReason)Deletion_Reason; /* * Create a packet which will be used to hold the data to be sent * through the transport interface. If the packet creation fails it * doesn't matter since this connection is being deleted anyway. */ DBG_SAVE_FILE_LINE disconnect_packet = new Packet ( (PPacketCoder) g_MCSCoder, Encoding_Rules, (PVoid) &disconnect_provider_ultimatum_pdu, DOMAIN_MCS_PDU, Upward_Connection, &packet_error); if (disconnect_packet != NULL) { if (packet_error == PACKET_NO_ERROR) { /* * Lock the encoded PDU data and queue the packet up for * transmission through the transport interface. */ QueueForTransmission ((PSimplePacket) disconnect_packet, TOP_PRIORITY); /* * Attempt to flush the message queue. Since this is the * object destructor, this is the last chance we will get to * send queued up PDUs (including the disconnect PDU that we * just put there). */ FlushMessageQueue (); } disconnect_packet->Unlock (); } } // Domain_Traffic_Allowed == TRUE /* * Issue a disconnect request to the top priority transport connection, * telling it to wait until the disconnect provider ultimatum has * cleared the transmitter. */ ASSERT(g_Transport != NULL); g_Transport->DisconnectRequest (Transport_Connection[TOP_PRIORITY]); Transport_Connection_State[TOP_PRIORITY] = TRANSPORT_CONNECTION_UNASSIGNED; } /* * Clear the transmission queue and free any allocated memory. */ for (priority = 0; priority < MAXIMUM_PRIORITIES; priority++) { /* * If we are holding a valid connection handle for this priority, then * it is necessary to issue a disconnect. */ if (Transport_Connection_State[priority] != TRANSPORT_CONNECTION_UNASSIGNED) { ASSERT(g_Transport != NULL); g_Transport->DisconnectRequest ( Transport_Connection[priority]); } /* * If there are any remaining data units in the queue for this * priority, walk through the list releasing all memory associated * with them. */ while (NULL != (packet = m_OutPktQueue[priority].Get())) { packet->Unlock(); } } /* * If there is a memory block holding the user data field of a pending * connect provider confirm, then free it. */ FreeMemory (Connect_Response_Memory); delete m_pszCalledAddress; } /* * void RegisterTransportConnection () * * Public * * Functional Description: * This routine is called in order to register the transport connection * with the connection object. */ void Connection::RegisterTransportConnection ( TransportConnection transport_connection, Priority priority) { TransportError transport_error; /* * Make sure that the specified priority is one of those outstanding. */ if (Transport_Connection_State[priority] != TRANSPORT_CONNECTION_READY) { /* * Register this connection object as the owner of the new * transport connection. */ transport_error = AcceptTransportConnection (transport_connection, priority); if (transport_error == TRANSPORT_NO_ERROR) { TRACE_OUT (("Connection::RegisterTransportConnection: " "transport connection accepted")); /* * Check to see if this completes the list of transport * connections that will be used in this MCS connection. */ if (Transport_Connection_Count == Domain_Parameters.number_priorities) { /* * There are no more transport connections to accept. We must * now assign the lowest priority TC to all unassigned * priorities. */ AssignRemainingTransportConnections (); } } else { /* * The transport connection must be invalid or already assigned * to another connection object. We therefore cannot use it. */ ERROR_OUT (("Connection::RegisterTransportConnection: " "register transport connection failed")); } } else { /* * A transport connection is not pending for this priority level. * Reject the registration. */ ERROR_OUT (("Connection::RegisterTransportConnection: " "priority already assigned")); } } /* * Void ConnectInitial () * * Private * * Functional Description: * This routine is called by the domain when a connection is being created. * It places the necessary domain information into a data packet and * queues the data to be transmitted through the transport interface. * * Caveats: * None. */ // LONCHANC: we send out calling and called domain selectors but // at the receiver side, we ignore them completely. Void Connection::ConnectInitial ( GCCConfID *calling_domain, GCCConfID *called_domain, BOOL upward_connection, PDomainParameters domain_parameters, PDomainParameters min_domain_parameters, PDomainParameters max_domain_parameters, PUChar user_data, ULong user_data_length) { ConnectMCSPDU connect_initial_pdu; /* * Fill in the PDU structure to be encoded. */ connect_initial_pdu.choice = CONNECT_INITIAL_CHOSEN; connect_initial_pdu.u.connect_initial.calling_domain_selector.length = sizeof(GCCConfID); connect_initial_pdu.u.connect_initial.calling_domain_selector.value = (LPBYTE) calling_domain; connect_initial_pdu.u.connect_initial.called_domain_selector.length = sizeof(GCCConfID); connect_initial_pdu.u.connect_initial.called_domain_selector.value = (LPBYTE) called_domain; connect_initial_pdu.u.connect_initial.upward_flag = (ASN1bool_t)upward_connection; memcpy (&(connect_initial_pdu.u.connect_initial.target_parameters), domain_parameters, sizeof (PDUDomainParameters)); memcpy (&(connect_initial_pdu.u.connect_initial.minimum_parameters), min_domain_parameters, sizeof(PDUDomainParameters)); memcpy (&(connect_initial_pdu.u.connect_initial.maximum_parameters), max_domain_parameters, sizeof(PDUDomainParameters)); connect_initial_pdu.u.connect_initial.user_data.length = user_data_length; connect_initial_pdu.u.connect_initial.user_data.value = user_data; /* * Send the packet to the remote provider. */ SendPacket ((PVoid) &connect_initial_pdu, CONNECT_MCS_PDU, TOP_PRIORITY); } /* * Void ConnectResponse () * * Private * * Functional Description: * This routine is called when issuing a response to a "ConnectInitial" * PDU. The result of the attempted connection, the connection ID, the * domain parameters, and any user data are all put into the packet and * queued for transmission through the transport interface. If the result * of the attempted connection is negative, the controller and transport * interface are notified. * * Caveats: * None. */ Void Connection::ConnectResponse ( Result result, PDomainParameters domain_parameters, ConnectID connect_id, PUChar user_data, ULong user_data_length) { ConnectMCSPDU connect_response_pdu; /* * Fill in the PDU structure to be encoded. */ connect_response_pdu.choice = CONNECT_RESPONSE_CHOSEN; connect_response_pdu.u.connect_response.result = (PDUResult)result; connect_response_pdu.u.connect_response.called_connect_id = connect_id; memcpy (&(connect_response_pdu.u.connect_response.domain_parameters), domain_parameters, sizeof(PDUDomainParameters)); connect_response_pdu.u.connect_response.user_data.length = user_data_length; connect_response_pdu.u.connect_response.user_data.value = user_data; /* * Send the packet to the remote provider. */ SendPacket ((PVoid) &connect_response_pdu, CONNECT_MCS_PDU, TOP_PRIORITY); } /* * Void ConnectAdditional () * * Private * * Functional Description: * This routine is called after successfully processing a"ConnectResponse" * PDU in order to create any addition necessary transport connections. * * Caveats: * None. */ Void Connection::ConnectAdditional ( ConnectID connect_id, Priority priority) { ConnectMCSPDU connect_additional_pdu; /* * Fill in the PDU structure to be encoded. */ connect_additional_pdu.choice = CONNECT_ADDITIONAL_CHOSEN; connect_additional_pdu.u.connect_additional.called_connect_id = connect_id; connect_additional_pdu.u.connect_additional.data_priority = (PDUPriority)priority; /* * Send the packet to the remote provider. */ SendPacket ((PVoid) &connect_additional_pdu, CONNECT_MCS_PDU, priority); } /* * Void ConnectResult () * * Private * * Functional Description: * This routine is called indirectly when issuing a positive response * to a "ConnectAdditional" PDU. The "ConnectAdditional" PDUs are * processed by the controller and therefore any negative * "ConnectResult" PDU will be issued by the controller. * * Caveats: * None. */ Void Connection::ConnectResult ( Result result, Priority priority) { ConnectMCSPDU connect_result_pdu; /* * Fill in the PDU structure to be encoded. */ connect_result_pdu.choice = CONNECT_RESULT_CHOSEN; connect_result_pdu.u.connect_result.result = (PDUResult)result; /* * Send the packet to the remote provider. */ SendPacket ((PVoid) &connect_result_pdu, CONNECT_MCS_PDU, priority); } /* * ULong ProcessConnectResponse() * * Private * * Functional Description: * This routine processes the "ConnectResponse" PDU's being received * through the transport interface. The result of the connection attempt, * the connection ID, and the domain parameters are read from the packet * and the domain notified of the connection response. * * Caveats: * None. */ ULong Connection::ProcessConnectResponse (PConnectResponsePDU pdu_structure) { TransportError return_value=TRANSPORT_NO_ERROR; UINT priority; TransportError transport_error; /* * Allocate any memory needed to pass user data on to the domain. */ if (pdu_structure->user_data.length != 0) { DBG_SAVE_FILE_LINE Connect_Response_Memory = AllocateMemory ( pdu_structure->user_data.value, pdu_structure->user_data.length); if (Connect_Response_Memory == NULL) { ("Connection::ProcessConnectResponse: " "memory allocation failed"); return_value = TRANSPORT_READ_QUEUE_FULL; } } else Connect_Response_Memory = NULL; /* * If everything is okay, then process the PDU. Note that the only way * for there to be a problem at this point, is if the memory allocation * above has failed. If this is the case, returning an error without * processing the PDU will cause the transport layer to retry the PDU * at a future time. */ if (return_value == TRANSPORT_NO_ERROR) { /* * Was the connection accepted by the remote side? If so, then begin * the process of creating additional TCs (if necessary). */ if (pdu_structure->result == RESULT_SUCCESSFUL) { /* * Get the domain parameters that are to be used for this MCS * connection. */ memcpy (&Domain_Parameters, &(pdu_structure->domain_parameters), sizeof(PDUDomainParameters)); /* * Now that we know what the domain parameters will be for this * connection, we can determine what type of encoding rules will * be used for domain PDUs (basic or packed). * NOTE: The Teles ASN.1 coder assumes the use of packed encoding rules. */ ASSERT (Domain_Parameters.protocol_version != PROTOCOL_VERSION_BASIC); TRACE_OUT (("Connection::ProcessConnectResponse: " "using packed encoding rules")); Encoding_Rules = PACKED_ENCODING_RULES; /* * Increment the number of transport connections that are now ready * for domain MCSPDU traffic. */ Transport_Connection_Count++; /* * If there is at least one additional TC required, then it is * necessary to create it before this connection can be bound to * the local domain. */ if (Transport_Connection_Count < Domain_Parameters.number_priorities) { /* * Loop through, creating the proper number of additional * transport connections. */ for (priority = Transport_Connection_Count; priority < Domain_Parameters.number_priorities; priority++) { /* * Attempt to create an outbound transport connection. */ transport_error = CreateTransportConnection (m_pszCalledAddress, m_fSecure, (Priority) priority); if (transport_error == TRANSPORT_NO_ERROR) { /* * If we were able to successfully request a new TC, * then queue up a connect additional, which will * automatically be sent when the TC becomes valid. */ ConnectAdditional ( (UShort) pdu_structure->called_connect_id, (Priority) priority); } else { /* * If we were not able to create one of the required * TCs, then this MCS connection is invalid. Issue * a failed connect provider confirm. */ IssueConnectProviderConfirm ( RESULT_UNSPECIFIED_FAILURE); /* * Its pointless to try and create any more TCs, so * break out of this loop. */ break; } } } else { /* * If there are no more TCs to create, then copy the lowest * priority TC into all unassigned priorities. */ AssignRemainingTransportConnections (); /* * Bind this MCS connection to the domain, now that it is * ready for use. */ TRACE_OUT (("Connection::ProcessConnectResponse: " "binding MCS connection to domain")); m_pDomain = m_pPendingDomain; m_pDomain->BindConnAttmnt(this, Upward_Connection, &Domain_Parameters); /* * Issue a successful connect provider confirm to the node * controller. */ IssueConnectProviderConfirm (RESULT_SUCCESSFUL); } } else { /* * This connection was rejected by the remote side. It is * therefore necessary to issue a failed connect provider confirm. */ IssueConnectProviderConfirm ((Result)pdu_structure->result); } } return ((ULong) return_value); } /* * Void ProcessConnectResult () * * Private * * Functional Description: * This routine processes "Connect Result" PDU's coming from the * transport interface. For successful "Connect Result" PDU's this * connection is bound to the domain and a positive Connect Provider * Confirm issued to the controller. If unsuccessful, a negative * Connect Provider Confirm is issued to the controller. * * Caveats: * None. */ Void Connection::ProcessConnectResult (PConnectResultPDU pdu_structure) { Result result; result = (Result)pdu_structure->result; /* * Was the transport connection accepted by the remote system? */ if (result == RESULT_SUCCESSFUL) { /* * Increment the number of transport connections that are now ready * for domain MCSPDU traffic. */ Transport_Connection_Count++; /* * Do we now have all transport connections accounted for? */ if (Transport_Connection_Count == Domain_Parameters.number_priorities) { /* * If there are no more TCs to create, then copy the lowest * priority TC into all unassigned priorities. */ AssignRemainingTransportConnections (); /* * Bind this MCS connection to the domain, now that it is * ready for use. */ TRACE_OUT (("Connection::ProcessConnectResult: " "binding MCS connection to domain")); m_pDomain = m_pPendingDomain; m_pDomain->BindConnAttmnt(this, Upward_Connection, &Domain_Parameters); /* * Issue a successful connect provider confirm to the node * controller. */ IssueConnectProviderConfirm (RESULT_SUCCESSFUL); } } else { /* * This connection was rejected by the remote side. It is * therefore necessary to issue a failed connect provider confirm. */ IssueConnectProviderConfirm (result); } } /* * Void IssueConnectProviderConfirm () * * Private * * Functional Description: * This routine is called in order to send a "Connect Provider Confirm" * to the controller through a callback. * * Caveats: * None. */ Void Connection::IssueConnectProviderConfirm ( Result result) { ConnectConfirmInfo connect_confirm_info; /* * Make sure there is a confirm pending before issuing one to the * controller. */ if (Connect_Provider_Confirm_Pending) { /* * Pack the information into the structure for passing in the owner * callback. */ ASSERT (g_Transport != NULL); connect_confirm_info.domain_parameters = &Domain_Parameters; connect_confirm_info.result = result; connect_confirm_info.memory = Connect_Response_Memory; /* * Issue the callback to the controller. */ TRACE_OUT (("Connection::IssueConnectProviderConfirm: " "sending CONNECT_PROVIDER_CONFIRM")); g_pMCSController->HandleConnConnectProviderConfirm(&connect_confirm_info, Connection_Handle); /* * If there was user data associated with this confirm, free the memory * block that contained it. */ if (Connect_Response_Memory != NULL) { FreeMemory (Connect_Response_Memory); Connect_Response_Memory = NULL; } /* * Reset the confirm pending flag, to prevent this object from sending * a second confirm to the controller. */ Connect_Provider_Confirm_Pending = FALSE; } } /* * Void DestroyConnection () * * Private * * Functional Description: * This routine is called in order to delete this connection because it has * become invalid. This is done by issuing a failed confirm to the * controller or, if no confirm is pending, by issuing a delete connection * to the controller. * * Caveats: * None. */ Void Connection::DestroyConnection ( Reason reason) { Result result = RESULT_UNSPECIFIED_FAILURE; /* * Modify the Deletion_Reason to reflect why this connection is being * destroyed. */ Deletion_Reason = reason; /* * Something catastrophic has occurred, so we must ask the controller to * delete this object. There are two possible ways of doing this * (depending on circumstances). If a connect provider confirm is still * pending, then we issue a failed confirm to the controller (who will * forward it to the node controller and destroy this object). If there * is not a confirm pending, then we simply issue a delete connection to * the controller (who will issue a disconnect provider indication to the * node controller and destroy this object). */ if (Connect_Provider_Confirm_Pending) { /* * Send the failed confirm to the controller. */ switch (reason) { case REASON_REMOTE_NO_SECURITY : result = RESULT_REMOTE_NO_SECURITY; break; case REASON_REMOTE_DOWNLEVEL_SECURITY : result = RESULT_REMOTE_DOWNLEVEL_SECURITY; break; case REASON_REMOTE_REQUIRE_SECURITY : result = RESULT_REMOTE_REQUIRE_SECURITY; break; case REASON_AUTHENTICATION_FAILED : result = RESULT_AUTHENTICATION_FAILED; break; default : result = RESULT_UNSPECIFIED_FAILURE; break; } IssueConnectProviderConfirm (result); } else { ASSERT (g_Transport != NULL); /* * Issue a delete connection callback to the controller. When the * controller deletes this object, it will correctly disconnect itself * from the layers above and below, and clean up all outstanding * resources. */ TRACE_OUT (("Connection::DestroyConnection: sending DELETE_CONNECTION")); g_pMCSController->HandleConnDeleteConnection(Connection_Handle); } } /* * Void AssignRemainingTransportConnections () * * Private * * Functional Description: * This routine is called when there are no more transport connections to * create in order to copy the lowest priority transport connection into * all unassigned priorities. * * Caveats: * None. */ Void Connection::AssignRemainingTransportConnections () { unsigned int priority; TransportConnection transport_connection; /* * Verify that this MCS connection is in the initializing state before * proceeding with this request. */ if (Transport_Connection_State[TOP_PRIORITY] == TRANSPORT_CONNECTION_READY) { /* * Loop through for each priority, copying transport connections from * higher priorities into lower priorities that do not have a * transport connection assigned. */ for (priority=0; priority < MAXIMUM_PRIORITIES; priority++) { if (Transport_Connection_State[priority] == TRANSPORT_CONNECTION_READY) transport_connection = Transport_Connection[priority]; else { Transport_Connection[priority] = transport_connection; Transport_Connection_PDU_Type[priority] = DOMAIN_MCS_PDU; Transport_Connection_State[priority] = TRANSPORT_CONNECTION_READY; } } /* * Set the flag indicating that the transmission of domain PDUs is * now permitted on this MCS connection. Also, flush any queued msgs * in case they were prevented earlier. * bugbug: the FlushMessageQueue may fail. */ Domain_Traffic_Allowed = TRUE; FlushMessageQueue (); } else { /* * We have no valid transport connections. It is therefore not * possible to bind to the domain. */ WARNING_OUT (("Connection::AssignRemainingTransportConnections: " "no valid transport connections")); } } /* * TransportError CreateTransportConnection () * * Private * * Functional Description: * This routine is called in order to create new transport connections. * * Caveats: * None. */ TransportError Connection::CreateTransportConnection ( LPCTSTR called_address, BOOL fSecure, Priority priority) { TransportConnection transport_connection; TransportError transport_error; /* * Send a connect request to the transport layer to create the transport * connection. */ ASSERT(g_Transport != NULL); transport_error = g_Transport->ConnectRequest ( (PChar) called_address, fSecure, priority < MEDIUM_PRIORITY, this, &transport_connection); if (transport_error == TRANSPORT_NO_ERROR) { /* * Mark the transport connection as pending, which indicates that * it has been assigned, but is not yet ready for use. This will * be set to ready when a successsful confirm is received from the * transport layer. */ Transport_Connection[priority] = transport_connection; Transport_Connection_PDU_Type[priority] = CONNECT_MCS_PDU; Transport_Connection_State[priority] = TRANSPORT_CONNECTION_PENDING; } else { /* * The call to the transport layer failed. Report the error to the * diagnostic window, and let the error fall through. */ WARNING_OUT (("Connection::CreateTransportConnection: " "connect request failed")); } return (transport_error); } /* * TransportError AcceptTransportConnection () * * Private * * Functional Description: * This routine is called in order to register this connection object * with the transport interface. * * Caveats: * None. */ TransportError Connection::AcceptTransportConnection ( TransportConnection transport_connection, Priority priority) { TransportError transport_error; /* * Attempt to register this object with the transport interface. If * successful, all indications associated with this transport connection * will be sent directly to this object. */ ASSERT(g_Transport != NULL); transport_error = g_Transport->RegisterTransportConnection ( transport_connection, this, priority < MEDIUM_PRIORITY); if (transport_error == TRANSPORT_NO_ERROR) { /* * Save the transport connection handle that we are supposed to use * for top priority data transfer. Also, since this is an inbound * request, the top priority transport connection IS valid. Mark * it as such, allowing data transfer to occur immediately. */ Transport_Connection[priority] = transport_connection; Transport_Connection_PDU_Type[priority] = DOMAIN_MCS_PDU; Transport_Connection_State[priority] = TRANSPORT_CONNECTION_READY; Transport_Connection_Count++; } else { /* * The call to the transport layer failed. Report the error to the * diagnostic window, and let the error fall through. */ WARNING_OUT (("Connection::AcceptTransportConnection: " "invalid transport connection")); } return (transport_error); } /* * Void AdjustDomainParameters () * * Private * * Functional Description: * This routine is called in order to adjust the domain parameters so that * they fall within the allowable range. * * Caveats: * None. */ Void Connection::AdjustDomainParameters ( PDomainParameters min_domain_parameters, PDomainParameters max_domain_parameters, PDomainParameters domain_parameters) { /* * Adjust the maximum number of channels to fall within the range. */ if (domain_parameters->max_channel_ids < min_domain_parameters->max_channel_ids) domain_parameters->max_channel_ids = min_domain_parameters->max_channel_ids; else if (domain_parameters->max_channel_ids > max_domain_parameters->max_channel_ids) domain_parameters->max_channel_ids = max_domain_parameters->max_channel_ids; /* * Adjust the maximum number of users to fall within the range. */ if (domain_parameters->max_user_ids < min_domain_parameters->max_user_ids) domain_parameters->max_user_ids = min_domain_parameters->max_user_ids; else if (domain_parameters->max_user_ids > max_domain_parameters->max_user_ids) domain_parameters->max_user_ids = max_domain_parameters->max_user_ids; /* * Adjust the maximum number of tokens to fall within the range. */ if (domain_parameters->max_token_ids < min_domain_parameters->max_token_ids) domain_parameters->max_token_ids = min_domain_parameters->max_token_ids; else if (domain_parameters->max_token_ids > max_domain_parameters->max_token_ids) domain_parameters->max_token_ids = max_domain_parameters->max_token_ids; /* * Adjust the number of priorities to fall within the range. */ if (domain_parameters->number_priorities < min_domain_parameters->number_priorities) domain_parameters->number_priorities = min_domain_parameters->number_priorities; else if (domain_parameters->number_priorities > max_domain_parameters->number_priorities) domain_parameters->number_priorities = max_domain_parameters->number_priorities; /* * Adjust the minimum throughput to fall within the range. */ if (domain_parameters->min_throughput < min_domain_parameters->min_throughput) domain_parameters->min_throughput = min_domain_parameters->min_throughput; else if (domain_parameters->min_throughput > max_domain_parameters->min_throughput) domain_parameters->min_throughput = max_domain_parameters->min_throughput; /* * Adjust the maximum domain height to fall within the range. */ if (domain_parameters->max_height < min_domain_parameters->max_height) domain_parameters->max_height = min_domain_parameters->max_height; else if (domain_parameters->max_height > max_domain_parameters->max_height) domain_parameters->max_height = max_domain_parameters->max_height; /* * Adjust the maximum PDU size to fall within the range. */ if (domain_parameters->max_mcspdu_size < min_domain_parameters->max_mcspdu_size) domain_parameters->max_mcspdu_size = min_domain_parameters->max_mcspdu_size; else if (domain_parameters->max_mcspdu_size > max_domain_parameters->max_mcspdu_size) domain_parameters->max_mcspdu_size = max_domain_parameters->max_mcspdu_size; /* * Adjust the protocol version to fall within the range. */ if (domain_parameters->protocol_version < min_domain_parameters->protocol_version) domain_parameters->protocol_version = min_domain_parameters->protocol_version; else if (domain_parameters->protocol_version > max_domain_parameters->protocol_version) domain_parameters->protocol_version = max_domain_parameters->protocol_version; } /* * BOOL MergeDomainParameters () * * Private * * Functional Description: * This routine is called in order to calculate the optimum overlap * between the local and remote domain parameters. If there is no overlap, * this routine will return a value causing this connection to be * destroyed. * * Caveats: * None. */ BOOL Connection::MergeDomainParameters ( PDomainParameters min_domain_parameters1, PDomainParameters max_domain_parameters1, PDomainParameters min_domain_parameters2, PDomainParameters max_domain_parameters2) { BOOL valid=TRUE; /* * Determine the overlap for maximum number of channels. If there is no * overlap, set the valid flag to FALSE. */ if (min_domain_parameters2->max_channel_ids < min_domain_parameters1->max_channel_ids) min_domain_parameters2->max_channel_ids = min_domain_parameters1->max_channel_ids; if (max_domain_parameters2->max_channel_ids > max_domain_parameters1->max_channel_ids) max_domain_parameters2->max_channel_ids = max_domain_parameters1->max_channel_ids; if (min_domain_parameters2->max_channel_ids > max_domain_parameters2->max_channel_ids) valid = FALSE; /* * Determine the overlap for maximum number of users. If there is no * overlap, set the valid flag to FALSE. */ if (min_domain_parameters2->max_user_ids < min_domain_parameters1->max_user_ids) min_domain_parameters2->max_user_ids = min_domain_parameters1->max_user_ids; if (max_domain_parameters2->max_user_ids > max_domain_parameters1->max_user_ids) max_domain_parameters2->max_user_ids = max_domain_parameters1->max_user_ids; if (min_domain_parameters2->max_user_ids > max_domain_parameters2->max_user_ids) valid = FALSE; /* * Determine the overlap for maximum number of tokens. If there is no * overlap, set the valid flag to FALSE. */ if (min_domain_parameters2->max_token_ids < min_domain_parameters1->max_token_ids) min_domain_parameters2->max_token_ids = min_domain_parameters1->max_token_ids; if (max_domain_parameters2->max_token_ids > max_domain_parameters1->max_token_ids) max_domain_parameters2->max_token_ids = max_domain_parameters1->max_token_ids; if (min_domain_parameters2->max_token_ids > max_domain_parameters2->max_token_ids) valid = FALSE; /* * Determine the overlap for number of priorities. If there is no * overlap, set the valid flag to FALSE. */ if (min_domain_parameters2->number_priorities < min_domain_parameters1->number_priorities) min_domain_parameters2->number_priorities = min_domain_parameters1->number_priorities; if (max_domain_parameters2->number_priorities > max_domain_parameters1->number_priorities) max_domain_parameters2->number_priorities = max_domain_parameters1->number_priorities; if (min_domain_parameters2->number_priorities > max_domain_parameters2->number_priorities) valid = FALSE; /* * Determine the overlap for minimum throughput. If there is no * overlap, set the valid flag to FALSE. */ if (min_domain_parameters2->min_throughput < min_domain_parameters1->min_throughput) min_domain_parameters2->min_throughput = min_domain_parameters1->min_throughput; if (max_domain_parameters2->min_throughput > max_domain_parameters1->min_throughput) max_domain_parameters2->min_throughput = max_domain_parameters1->min_throughput; if (min_domain_parameters2->min_throughput > max_domain_parameters2->min_throughput) valid = FALSE; /* * Determine the overlap for maximum domain height. If there is no * overlap, set the valid flag to FALSE. */ if (min_domain_parameters2->max_height < min_domain_parameters1->max_height) min_domain_parameters2->max_height = min_domain_parameters1->max_height; if (max_domain_parameters2->max_height > max_domain_parameters1->max_height) max_domain_parameters2->max_height = max_domain_parameters1->max_height; if (min_domain_parameters2->max_height > max_domain_parameters2->max_height) valid = FALSE; /* * Determine the overlap for maximum PDU size. If there is no * overlap, set the valid flag to FALSE. */ if (min_domain_parameters2->max_mcspdu_size < min_domain_parameters1->max_mcspdu_size) min_domain_parameters2->max_mcspdu_size = min_domain_parameters1->max_mcspdu_size; if (max_domain_parameters2->max_mcspdu_size > max_domain_parameters1->max_mcspdu_size) max_domain_parameters2->max_mcspdu_size = max_domain_parameters1->max_mcspdu_size; if (min_domain_parameters2->max_mcspdu_size > max_domain_parameters2->max_mcspdu_size) valid = FALSE; /* * Determine the overlap for protocol version. If there is no * overlap, set the valid flag to FALSE. */ if (min_domain_parameters2->protocol_version < min_domain_parameters1->protocol_version) min_domain_parameters2->protocol_version = min_domain_parameters1->protocol_version; if (max_domain_parameters2->protocol_version > max_domain_parameters1->protocol_version) max_domain_parameters2->protocol_version = max_domain_parameters1->protocol_version; if (min_domain_parameters2->protocol_version > max_domain_parameters2->protocol_version) valid = FALSE; return (valid); } /* * Void PrintDomainParameters () * * Private * * Functional Description: * This routine is used for debug purposes in order to print out the * current set of domain parameters. * * Caveats: * None. */ #ifdef DEBUG Void Connection::PrintDomainParameters ( PDomainParameters domain_parameters) { TRACE_OUT ((" Maximum Channels = %ld", (ULong) domain_parameters->max_channel_ids)); TRACE_OUT ((" Maximum Users = %ld", (ULong) domain_parameters->max_user_ids)); TRACE_OUT ((" Maximum Tokens = %ld", (ULong) domain_parameters->max_token_ids)); TRACE_OUT ((" Number of Priorities = %ld", (ULong) domain_parameters->number_priorities)); TRACE_OUT ((" Minimum Throughput = %ld", (ULong) domain_parameters->min_throughput)); TRACE_OUT ((" Maximum Domain Height = %ld", (ULong) domain_parameters->max_height)); TRACE_OUT ((" Maximum PDU Size = %ld", (ULong) domain_parameters->max_mcspdu_size)); TRACE_OUT ((" Protocol Version = %ld", (ULong) domain_parameters->protocol_version)); } #endif // DEBUG /* * Void PlumbDomainIndication () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "PlumbDomainIndication" PDU through the transport interface. * * Caveats: * None. */ Void Connection::PlumbDomainIndication ( ULong height_limit) { DomainMCSPDU plumb_domain_indication_pdu; /* * Fill in the PDU structure to be encoded. */ plumb_domain_indication_pdu.choice = PLUMB_DOMAIN_INDICATION_CHOSEN; plumb_domain_indication_pdu.u.plumb_domain_indication.height_limit = height_limit; /* * Send the packet to the remote provider. */ SendPacket ((PVoid) &plumb_domain_indication_pdu, DOMAIN_MCS_PDU, TOP_PRIORITY); } /* * Void ErectDomainRequest () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "ErectDomainRequest" PDU through the transport interface. * * Caveats: * None. */ Void Connection::ErectDomainRequest ( ULong height_in_domain, ULong throughput_interval) { DomainMCSPDU erect_domain_request_pdu; /* * Fill in the PDU structure to be encoded. */ erect_domain_request_pdu.choice = ERECT_DOMAIN_REQUEST_CHOSEN; erect_domain_request_pdu.u.erect_domain_request.sub_height = height_in_domain; erect_domain_request_pdu.u.erect_domain_request.sub_interval = throughput_interval; /* * Send the packet to the remote provider. */ SendPacket ((PVoid) &erect_domain_request_pdu, DOMAIN_MCS_PDU, TOP_PRIORITY); } /* * Void RejectUltimatum () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "RejectUltimatum" PDU through the transport interface. * * Caveats: * None. */ Void Connection::RejectUltimatum ( Diagnostic diagnostic, PUChar octet_string_address, ULong octet_string_length) { DomainMCSPDU reject_ultimatum_pdu; /* * Fill in the PDU structure to be encoded. */ reject_ultimatum_pdu.choice = REJECT_ULTIMATUM_CHOSEN; reject_ultimatum_pdu.u.reject_user_ultimatum.diagnostic = diagnostic; reject_ultimatum_pdu.u.reject_user_ultimatum.initial_octets.length = (UShort) octet_string_length; reject_ultimatum_pdu.u.reject_user_ultimatum.initial_octets.value = octet_string_address; /* * Send the packet to the remote provider. */ SendPacket ((PVoid) &reject_ultimatum_pdu, DOMAIN_MCS_PDU, TOP_PRIORITY); } /* * Void MergeChannelsRequest () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "MergeChannelsRequest" PDU through the transport interface. * * Caveats: * None. */ Void Connection::MergeChannelsRequest ( CChannelAttributesList *merge_channel_list, CChannelIDList *purge_channel_list) { MergeChannelsRC (MERGE_CHANNELS_REQUEST_CHOSEN, merge_channel_list, purge_channel_list); } /* * Void MergeChannelsConfirm () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "MergeChannelsConfirm" PDU through the transport interface. * * Caveats: * None. */ Void Connection::MergeChannelsConfirm ( CChannelAttributesList *merge_channel_list, CChannelIDList *purge_channel_list) { MergeChannelsRC (MERGE_CHANNELS_CONFIRM_CHOSEN, merge_channel_list, purge_channel_list); } /* * Void MergeChannelsRC () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "MergeChannelsRequest" or a "MergeChannelsConfirm" PDU * through the transport interface. * * IMPORTANT: * Since the code is used for both PDUs the DomainMCSPDU's * merge_channels_request and merge_channels_confirm fields should * be identical structures. * * Caveats: * None. */ Void Connection::MergeChannelsRC ( ASN1choice_t choice, CChannelAttributesList *merge_channel_list, CChannelIDList *purge_channel_list) { BOOL memory_error = FALSE; DomainMCSPDU merge_channels_pdu; DWORD channel_attributes_count; PSetOfPDUChannelAttributes setof_channel_attributes; PChannelAttributes channel_attributes; PSetOfUserIDs user_ids_pointer; DWORD purge_channel_count; PSetOfChannelIDs channel_ids_pointer; DWORD dwMemoryToAlloc; CUidList *user_admit_list; /* * Set the type of PDU to be encoded. */ merge_channels_pdu.choice = choice; /* * Determine how many channel attributes entries there are in the lists. * If there are any entries, allocate memory to hold the associated * structures. */ channel_attributes_count = merge_channel_list->GetCount(); purge_channel_count = purge_channel_list->GetCount(); if ((channel_attributes_count != 0) || (purge_channel_count != 0)) { // Determine how much memory we need to allocate dwMemoryToAlloc = channel_attributes_count * sizeof (SetOfPDUChannelAttributes) + purge_channel_count * sizeof (SetOfChannelIDs); merge_channel_list->Reset(); while (NULL != (channel_attributes = merge_channel_list->Iterate())) { if (PRIVATE_CHANNEL == channel_attributes->channel_type) { dwMemoryToAlloc += sizeof (SetOfUserIDs) * (channel_attributes->u. private_channel_attributes.admitted_list)->GetCount(); } } // Allocate the needed amount of memory. DBG_SAVE_FILE_LINE setof_channel_attributes = (PSetOfPDUChannelAttributes) Allocate (dwMemoryToAlloc); if (setof_channel_attributes == NULL) { memory_error = TRUE; } } else { setof_channel_attributes = NULL; } if (setof_channel_attributes == NULL) { merge_channels_pdu.u.merge_channels_request.purge_channel_ids = NULL; merge_channels_pdu.u.merge_channels_request.merge_channels = NULL; } else { /* * Get the base address of the array of SetOfChannelIDs structures. */ channel_ids_pointer = (PSetOfChannelIDs) (((PUChar) setof_channel_attributes) + channel_attributes_count * sizeof (SetOfPDUChannelAttributes)); if (channel_attributes_count != 0) { /* * Get the base address of the array of SetOfPDUChannelAttributes * structures. Put it into the PDU structure. */ merge_channels_pdu.u.merge_channels_request.merge_channels = setof_channel_attributes; /* * Get the base address of the array of SetOfUserIDs structures. */ user_ids_pointer = (PSetOfUserIDs) (((PUChar) channel_ids_pointer) + purge_channel_count * sizeof (SetOfChannelIDs)); /* * Set up an iterator for the list of channel attributes. Retrieve * the channel attributes structures from the list and construct the * PDU structure. */ merge_channel_list->Reset(); while (NULL != (channel_attributes = merge_channel_list->Iterate())) { /* * Use the channel type to determine what information to include in * the PDU structure. */ switch (channel_attributes->channel_type) { case STATIC_CHANNEL: setof_channel_attributes->value.choice = CHANNEL_ATTRIBUTES_STATIC_CHOSEN; setof_channel_attributes->value.u. channel_attributes_static.channel_id = channel_attributes->u. static_channel_attributes.channel_id; break; case USER_CHANNEL: setof_channel_attributes->value.choice = CHANNEL_ATTRIBUTES_USER_ID_CHOSEN; setof_channel_attributes->value.u. channel_attributes_user_id.joined = (ASN1bool_t)channel_attributes->u. user_channel_attributes.joined; setof_channel_attributes->value.u. channel_attributes_user_id.user_id = channel_attributes->u. user_channel_attributes.user_id; break; case PRIVATE_CHANNEL: setof_channel_attributes->value.choice = CHANNEL_ATTRIBUTES_PRIVATE_CHOSEN; setof_channel_attributes->value.u. channel_attributes_private.joined = (ASN1bool_t)channel_attributes->u. private_channel_attributes.joined; setof_channel_attributes->value.u. channel_attributes_private.channel_id = channel_attributes->u. private_channel_attributes.channel_id; setof_channel_attributes->value.u. channel_attributes_private.manager = channel_attributes->u. private_channel_attributes.channel_manager; /* * Get the number of the User IDs in the list of user ID's */ if ((channel_attributes->u.private_channel_attributes. admitted_list)->GetCount() > 0) { /* * Get the base address of the array of SetOfUserIDs * structures. Put it into the channel attributes * structure. */ setof_channel_attributes->value.u.channel_attributes_private.admitted = user_ids_pointer; /* * Iterate through the set of user ids, filling in the * PDU structure. */ user_admit_list = channel_attributes->u.private_channel_attributes.admitted_list; user_admit_list->BuildExternalList(&user_ids_pointer); } else { /* * There are either no users admitted to this channel, * or a memory allocation error occurred above. * Either way, we need to set the admitted array * address to NULL. */ setof_channel_attributes->value.u. channel_attributes_private.admitted = NULL; } break; case ASSIGNED_CHANNEL: setof_channel_attributes->value.choice = CHANNEL_ATTRIBUTES_ASSIGNED_CHOSEN; setof_channel_attributes->value.u. channel_attributes_assigned.channel_id = channel_attributes->u. assigned_channel_attributes.channel_id; break; default: WARNING_OUT(("Connection::MergeChannelsRC: " "ERROR - bad channel type")); break; } /* * Set the next pointer to point to the next element of the * PDU channel attributes structure array. Then increment the * pointer. */ setof_channel_attributes->next = setof_channel_attributes + 1; setof_channel_attributes++; } /* * Decrement the pointer in order to set the last "next" pointer to * NULL. */ (setof_channel_attributes - 1)->next = NULL; } else { /* There are no channels to merge. We need to set the structure * array address to NULL. */ merge_channels_pdu.u.merge_channels_request.merge_channels = NULL; } // Work on the purged channels. if (purge_channel_count != 0) { /* * Get the base address of the array of SetOfChannelIDs structures. * Put it into the PDU structure. */ merge_channels_pdu.u.merge_channels_request.purge_channel_ids = channel_ids_pointer; purge_channel_list->BuildExternalList(&channel_ids_pointer); } else { /* * There are either no channels to purge or a memory allocation * failure occurred above. Either way, we need to set the structure * array address to NULL. */ merge_channels_pdu.u.merge_channels_request.purge_channel_ids = NULL; } } /* * Send the packet to the remote provider. */ if (memory_error == FALSE) SendPacket ((PVoid) &merge_channels_pdu, DOMAIN_MCS_PDU, TOP_PRIORITY); else { /* * A memory allocation failure occurred somewhere above. Report the * error and destroy this faulty connection. */ ERROR_OUT (("Connection::MergeChannelsRC: memory allocation failure")); DestroyConnection (REASON_PROVIDER_INITIATED); } /* * Free up the memory block that was allocated to build this PDU * structure. */ Free(setof_channel_attributes - channel_attributes_count); } /* * Void PurgeChannelsIndication () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "PurgeChannelsIndication" PDU through the transport interface. * * Caveats: * None. */ Void Connection::PurgeChannelsIndication ( CUidList *purge_user_list, CChannelIDList *purge_channel_list) { BOOL memory_error = FALSE; DomainMCSPDU purge_channel_indication_pdu; ULong user_id_count; PSetOfUserIDs user_ids_pointer; DWORD purge_channel_count; PSetOfChannelIDs channel_ids_pointer; /* * Fill in the PDU structure to be encoded. */ purge_channel_indication_pdu.choice = PURGE_CHANNEL_INDICATION_CHOSEN; /* * Allocate memory to hold the list of user ID's and the list * of purged channels. If the allocation * fails, set the flag which will result in a callback to the * controller requesting that this connection be deleted. */ user_id_count = purge_user_list->GetCount(); purge_channel_count = purge_channel_list->GetCount(); if (user_id_count != 0 || purge_channel_count != 0) { DBG_SAVE_FILE_LINE user_ids_pointer = (PSetOfUserIDs) Allocate (user_id_count * sizeof (SetOfUserIDs) + purge_channel_count * sizeof (SetOfChannelIDs)); if (user_ids_pointer == NULL) { memory_error = TRUE; } } else user_ids_pointer = NULL; if (user_ids_pointer == NULL) { purge_channel_indication_pdu.u.purge_channel_indication.detach_user_ids = NULL; purge_channel_indication_pdu.u.purge_channel_indication.purge_channel_ids = NULL; } else { if (user_id_count != 0) { /* * Fill in the structure's pointer to the set of user ID's. */ purge_channel_indication_pdu.u.purge_channel_indication.detach_user_ids = user_ids_pointer; purge_user_list->BuildExternalList(&user_ids_pointer); } else { /* * Either there are no user IDs to purge or a memory allocation * failed above. Either way, put NULL into the PDU structure to * indicate that there is no list of IDs. */ purge_channel_indication_pdu.u.purge_channel_indication. detach_user_ids = NULL; } if (purge_channel_count != 0) { /* * Fill in the structure's pointer to the set of purge channel ID's. */ channel_ids_pointer = (PSetOfChannelIDs) user_ids_pointer; purge_channel_indication_pdu.u.purge_channel_indication.purge_channel_ids = channel_ids_pointer; purge_channel_list->BuildExternalList(&channel_ids_pointer); } else { /* * Either there are no channel IDs to purge or a memory allocation * failed above. Either way, put NULL into the PDU structure to * indicate that there is no list of IDs. */ purge_channel_indication_pdu.u.purge_channel_indication.purge_channel_ids = NULL; } } /* * Send the packet to the remote provider. */ if (memory_error == FALSE) SendPacket ((PVoid) &purge_channel_indication_pdu, DOMAIN_MCS_PDU, TOP_PRIORITY); else { /* * A memory allocation failure occurred somewhere above. Report the * error and destroy this faulty connection. */ ERROR_OUT (("Connection::PurgeChannelsIndication: " "memory allocation failure")); DestroyConnection (REASON_PROVIDER_INITIATED); } /* * Free all memory allocated above. */ Free(user_ids_pointer - user_id_count); } /* * Void MergeTokenRequest () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "MergeTokensRequest" PDU through the transport interface. * * Caveats: * None. */ Void Connection::MergeTokensRequest ( CTokenAttributesList *merge_token_list, CTokenIDList *purge_token_list) { MergeTokensRC (MERGE_TOKENS_REQUEST_CHOSEN, merge_token_list, purge_token_list); } /* * Void MergeTokenConfirm () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "MergeTokenConfirm" PDU through the transport interface. * * Caveats: * None. */ Void Connection::MergeTokensConfirm ( CTokenAttributesList *merge_token_list, CTokenIDList *purge_token_list) { MergeTokensRC (MERGE_TOKENS_CONFIRM_CHOSEN, merge_token_list, purge_token_list); } /* * Void MergeTokenRC () * * Private * * Functional Description: * This routine is called by the domain in order to send a * "MergeTokenConfirm" PDU or a "MergeTokenRequest" PDU through * the transport interface. * * IMPORTANT: * Since the code is used for both PDUs the DomainMCSPDU's * merge_tokens_request and merge_tokens_confirm fields should * be identical structures. * * Caveats: * None. */ Void Connection::MergeTokensRC ( ASN1choice_t choice, CTokenAttributesList *merge_token_list, CTokenIDList *purge_token_list) { BOOL memory_error = FALSE; DomainMCSPDU merge_tokens_pdu; DWORD token_attributes_count; PSetOfPDUTokenAttributes setof_token_attributes; PTokenAttributes token_attributes; PSetOfUserIDs user_ids_pointer; DWORD purge_token_count; PSetOfTokenIDs token_ids_pointer; DWORD dwMemoryToAlloc; CUidList *user_inhibit_list; merge_tokens_pdu.choice = choice; /* * Determine how many tokens are being merged with this PDU. This is * used to allocate a buffer for big enough for all of the needed token * attributes structures. */ token_attributes_count = merge_token_list->GetCount(); purge_token_count = purge_token_list->GetCount(); if ((token_attributes_count != 0) || (purge_token_count != 0)) { // Determine how much memory we need to allocate dwMemoryToAlloc = token_attributes_count * sizeof (SetOfPDUTokenAttributes) + purge_token_count * sizeof (SetOfTokenIDs); merge_token_list->Reset(); while (NULL != (token_attributes = merge_token_list->Iterate())) { if (TOKEN_INHIBITED == token_attributes->token_state) { dwMemoryToAlloc += sizeof (SetOfUserIDs) * token_attributes->u.inhibited_token_attributes. inhibitors->GetCount(); } } // Allocate the needed amount of memory. DBG_SAVE_FILE_LINE setof_token_attributes = (PSetOfPDUTokenAttributes) Allocate (dwMemoryToAlloc); if (setof_token_attributes == NULL) { memory_error = TRUE; } } else { setof_token_attributes = NULL; } if (setof_token_attributes == NULL) { merge_tokens_pdu.u.merge_tokens_confirm.merge_tokens = NULL; merge_tokens_pdu.u.merge_tokens_confirm.purge_token_ids = NULL; } else { /* * Compute where the set of purged token IDs will start from in the * memory previously allocated. */ token_ids_pointer = (PSetOfTokenIDs) ((PUChar) setof_token_attributes + token_attributes_count * sizeof (SetOfPDUTokenAttributes)); if (token_attributes_count != 0) { /* * Get the base address of the array of SetOfPDUTokenAttributes * structures. Put it into the PDU structure. */ merge_tokens_pdu.u.merge_tokens_confirm.merge_tokens = setof_token_attributes; /* * Compute the base address of the arrays of SetOfUserIDs structures. */ user_ids_pointer = (PSetOfUserIDs) ((PUChar) token_ids_pointer + purge_token_count * sizeof (SetOfTokenIDs)); /* * Set up an iterator for the list of token attributes. Retrieve * the token attributes structures from the list and construct the * PDU structure. */ merge_token_list->Reset(); while (NULL != (token_attributes = merge_token_list->Iterate())) { /* * Use the token state to determine what information to include in * the PDU structure. */ switch (token_attributes->token_state) { case TOKEN_GRABBED: setof_token_attributes->value.choice = GRABBED_CHOSEN; setof_token_attributes->value.u.grabbed.token_id = token_attributes->u. grabbed_token_attributes.token_id; setof_token_attributes->value.u.grabbed.grabber = token_attributes->u. grabbed_token_attributes.grabber; break; case TOKEN_INHIBITED: setof_token_attributes->value.choice = INHIBITED_CHOSEN; setof_token_attributes->value.u.inhibited.token_id = token_attributes->u. inhibited_token_attributes.token_id; if ((token_attributes->u.inhibited_token_attributes. inhibitors)->GetCount() > 0) { /* * Get the base address of the array of SetOfUserIDs * structures. Put it into the channel attributes * structure. */ setof_token_attributes->value.u.inhibited.inhibitors = user_ids_pointer; /* * Iterate through the User ID list, adding each user * to the PDU. */ user_inhibit_list = token_attributes->u.inhibited_token_attributes.inhibitors; user_inhibit_list->BuildExternalList(&user_ids_pointer); } else { /* * Either there were no inhibitors of this token, or * a memory allocation failure occurred above. Either * way, put a NULL into the PDU structure to indicate * that this field is unused. */ setof_token_attributes->value.u.inhibited.inhibitors = NULL; } break; case TOKEN_GIVING: setof_token_attributes->value.choice = GIVING_CHOSEN; /* * IMPORTANT: * The two structs involved in this memcpy should have * same-type fields. * Original code is included below. */ memcpy (&(setof_token_attributes->value.u.giving), &(token_attributes->u.giving_token_attributes), sizeof (Giving)); /* setof_token_attributes->value.u.giving.token_id = token_attributes->u. giving_token_attributes.token_id; setof_token_attributes->value.u.giving.grabber = token_attributes->u. giving_token_attributes.grabber; setof_token_attributes->value.u.giving.recipient = token_attributes->u. giving_token_attributes.recipient; */ break; case TOKEN_GIVEN: setof_token_attributes->value.choice = GIVEN_CHOSEN; setof_token_attributes->value.u.given.token_id = token_attributes->u. given_token_attributes.token_id; setof_token_attributes->value.u.given.recipient = token_attributes->u. given_token_attributes.recipient; break; default: WARNING_OUT(("Connection::MergeTokensRC: bad channel type")); break; } /* * Set the next pointer to point to the next element of the * PDU token attributes structure array. Then increment the * pointer. */ setof_token_attributes->next = setof_token_attributes + 1; setof_token_attributes++; } /* * Decrement the pointer in order to set the last "next" pointer to * NULL. */ (setof_token_attributes - 1)->next = NULL; } else { /* * Either there are no tokens to merge, or a memory allocation failure * occurred above. Either way put a NULL into the PDU structure to * indicate that this field is unused. */ merge_tokens_pdu.u.merge_tokens_confirm.merge_tokens = NULL; } if (purge_token_count != 0) { /* * Fill in the MergeTokensRequest structure's pointer to the set of * purge token ID's. */ merge_tokens_pdu.u.merge_tokens_confirm.purge_token_ids = token_ids_pointer; purge_token_list->BuildExternalList(&token_ids_pointer); } else { /* * Either there are no tokens to be purged, or a memory allocation * failure occurred above. Either way, put a NULL into the PDU * structure to indicate that this field is unused. */ merge_tokens_pdu.u.merge_tokens_confirm.purge_token_ids = NULL; } } /* * Send the packet to the remote provider. */ if (memory_error == FALSE) SendPacket ((PVoid) &merge_tokens_pdu, DOMAIN_MCS_PDU, TOP_PRIORITY); else { /* * A memory allocation failure occurred somewhere above. Report the * error and destroy this faulty connection. */ ERROR_OUT (("Connection::MergeTokensRC: memory allocation failure")); DestroyConnection (REASON_PROVIDER_INITIATED); } /* * Release all memory allocated above. */ Free(setof_token_attributes - token_attributes_count); } /* * Void PurgeTokensIndication () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "PurgeTokenIndication" PDU through the transport interface. * * Caveats: * None. */ Void Connection::PurgeTokensIndication ( PDomain, CTokenIDList *purge_token_list) { BOOL memory_error=FALSE; DomainMCSPDU purge_token_indication_pdu; DWORD purge_token_count; PSetOfTokenIDs token_ids_pointer; //TokenID tid; /* * Fill in the PDU structure to be encoded. */ purge_token_indication_pdu.choice = PURGE_TOKEN_INDICATION_CHOSEN; /* * Allocate memory to hold the list of purge tokens. If the allocation * fails, set the flag which will result in a callback to the * controller requesting that this connection be deleted. */ purge_token_count = purge_token_list->GetCount(); if (purge_token_count != 0) { DBG_SAVE_FILE_LINE token_ids_pointer = (PSetOfTokenIDs) Allocate (purge_token_count * sizeof (SetOfTokenIDs)); if (token_ids_pointer == NULL) memory_error = TRUE; } else token_ids_pointer = NULL; if (token_ids_pointer!= NULL) { /* * Fill in the structure's pointer to the set of purge token ID's. */ purge_token_indication_pdu.u.purge_token_indication.purge_token_ids = token_ids_pointer; purge_token_list->BuildExternalList(&token_ids_pointer); } else { /* * Either there are no tokens to purge or a memory allocation failure * occurred above. Either way, put a NULL into the PDU structure to * indicate that this field is unused. */ purge_token_indication_pdu.u.purge_token_indication.purge_token_ids = NULL; } /* * Send the packet to the remote provider. */ if (memory_error == FALSE) SendPacket ((PVoid) &purge_token_indication_pdu, DOMAIN_MCS_PDU, TOP_PRIORITY); else { /* * A memory allocation failure occurred somewhere above. Report the * error and destroy this faulty connection. */ ERROR_OUT (("Connection::PurgeTokensIndication: memory allocation failure")); DestroyConnection (REASON_PROVIDER_INITIATED); } /* * If memory was successfully allocated to hold the set of token ID's, * then free it here. */ Free(token_ids_pointer - purge_token_count); } /* * Void DisconnectProviderUltimatum () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "DisconnectProviderUltimatum" PDU through the transport interface. * * Caveats: * None. */ Void Connection::DisconnectProviderUltimatum ( Reason reason) { /* * Set attachment to NULL to prevent any attempt to send a command to * the attachment that just disconnected us. */ m_pDomain = NULL; /* * Issue an owner callback to ask for deletion. An attempt will be made * to send a DisconnectProviderUltimatum PDU through the transport * interface from the Connection's destructor. */ DestroyConnection (reason); } /* * Void AttachUserRequest () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "AttachUserRequest" PDU through the transport interface. * * Caveats: * None. */ Void Connection::AttachUserRequest ( void ) { DomainMCSPDU attach_user_request_pdu; /* * Fill in the PDU structure to be encoded. */ attach_user_request_pdu.choice = ATTACH_USER_REQUEST_CHOSEN; /* * Send the packet to the remote provider. */ SendPacket ((PVoid) &attach_user_request_pdu, DOMAIN_MCS_PDU, TOP_PRIORITY); } /* * Void AttachUserConfirm () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "AttachUserConfirm" PDU through the transport interface. * * Caveats: * None. */ Void Connection::AttachUserConfirm ( Result result, UserID uidInitiator) { DomainMCSPDU attach_user_confirm_pdu; /* * Fill in the PDU structure to be encoded. */ attach_user_confirm_pdu.choice = ATTACH_USER_CONFIRM_CHOSEN; if (result == RESULT_SUCCESSFUL) attach_user_confirm_pdu.u.attach_user_confirm.bit_mask = INITIATOR_PRESENT; else attach_user_confirm_pdu.u.attach_user_confirm.bit_mask = 0x00; attach_user_confirm_pdu.u.attach_user_confirm.result = (PDUResult)result; attach_user_confirm_pdu.u.attach_user_confirm.initiator = uidInitiator; /* * Send the packet to the remote provider. */ SendPacket ((PVoid) &attach_user_confirm_pdu, DOMAIN_MCS_PDU, TOP_PRIORITY); } /* * Void DetachUserRequest () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "DetachUserRequest" PDU through the transport interface. * * Caveats: * None. */ Void Connection::DetachUserRequest ( Reason reason, CUidList *user_id_list) { UserChannelRI (DETACH_USER_REQUEST_CHOSEN, (UINT) reason, 0, user_id_list); } /* * Void UserChannelRI () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "DetachUserRequest", "DetachUserIndication", "ChannelAdmitRequest", * "ChannelAdmitIndication", "ChannelExpelRequest" or * "ChannelExpelIndication" PDU through the transport interface. * * Caveats: * None. */ Void Connection::UserChannelRI ( ASN1choice_t choice, UINT reason_userID, ChannelID channel_id, CUidList *user_id_list) { BOOL memory_error = FALSE; DomainMCSPDU domain_pdu; DWORD user_ids_count; PSetOfUserIDs user_ids_pointer; //UserID uid; /* * Allocate memory to hold the list of users. If the allocation * fails, set the flag which will result in a callback to the * controller requesting that this connection be deleted. */ user_ids_count = user_id_list->GetCount(); if (user_ids_count != 0) { DBG_SAVE_FILE_LINE user_ids_pointer = (PSetOfUserIDs) Allocate (user_ids_count * sizeof (SetOfUserIDs)); if (user_ids_pointer == NULL) memory_error = TRUE; } else user_ids_pointer = NULL; /* * Fill in the PDU structure to be encoded. Also, * get the base address of the SetOfUserIDs structure and put it into * the PDU structure. */ domain_pdu.choice = choice; switch (choice) { case DETACH_USER_REQUEST_CHOSEN: case DETACH_USER_INDICATION_CHOSEN: /* * IMPORTANT: * The detach_user_request and detach_user_indication structs * in DomainMCSPDU must be identical. */ domain_pdu.u.detach_user_request.reason = (PDUReason) reason_userID; domain_pdu.u.detach_user_request.user_ids = user_ids_pointer; break; case CHANNEL_ADMIT_REQUEST_CHOSEN: case CHANNEL_ADMIT_INDICATION_CHOSEN: case CHANNEL_EXPEL_REQUEST_CHOSEN: /* * IMPORTANT: * The channel_admit_request, channel_admit_indication * and channel_expel_request structs * in DomainMCSPDU must be identical. */ domain_pdu.u.channel_admit_request.initiator = (UserID) reason_userID; domain_pdu.u.channel_admit_request.channel_id = channel_id; domain_pdu.u.channel_admit_request.user_ids = user_ids_pointer; break; case CHANNEL_EXPEL_INDICATION_CHOSEN: domain_pdu.u.channel_expel_indication.channel_id = channel_id; domain_pdu.u.channel_expel_indication.user_ids = user_ids_pointer; break; default: ASSERT(FALSE); ERROR_OUT (("Connection::UserChannelRI: PDU should not be formed by this method.")); break; } user_id_list->BuildExternalList(&user_ids_pointer); /* * Send the packet to the remote provider. */ if (memory_error == FALSE) SendPacket ((PVoid) &domain_pdu, DOMAIN_MCS_PDU, TOP_PRIORITY); else { /* * A memory allocation failure occurred somewhere above. Report the * error and destroy this faulty connection. */ ERROR_OUT (("Connection::UserChannelRI: memory allocation failure")); DestroyConnection (REASON_PROVIDER_INITIATED); } /* * If memory was successfully allocated to hold the set of user ID's, * then free it here. */ Free(user_ids_pointer - user_ids_count); } /* * Void DetachUserIndication () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "DetachUserIndication" PDU through the transport interface. * * Caveats: * None. */ Void Connection::DetachUserIndication ( Reason reason, CUidList *user_id_list) { UserChannelRI (DETACH_USER_INDICATION_CHOSEN, (UINT) reason, 0, user_id_list); } /* * Void ChannelJoinRequest () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "ChannelJoinRequest" PDU through the transport interface. * * Caveats: * None. */ Void Connection::ChannelJoinRequest ( UserID uidInitiator, ChannelID channel_id) { DomainMCSPDU channel_join_request_pdu; /* * Fill in the PDU structure to be encoded. */ channel_join_request_pdu.choice = CHANNEL_JOIN_REQUEST_CHOSEN; channel_join_request_pdu.u.channel_join_request.initiator = uidInitiator; channel_join_request_pdu.u.channel_join_request.channel_id = channel_id; /* * Send the packet to the remote provider. */ SendPacket ((PVoid) &channel_join_request_pdu, DOMAIN_MCS_PDU, TOP_PRIORITY); } /* * Void ChannelJoinConfirm () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "ChannelJoinConfirm" PDU through the transport interface. * * Caveats: * None. */ Void Connection::ChannelJoinConfirm ( Result result, UserID uidInitiator, ChannelID requested_id, ChannelID channel_id) { DomainMCSPDU channel_join_confirm_pdu; /* * Fill in the PDU structure to be encoded. */ channel_join_confirm_pdu.choice = CHANNEL_JOIN_CONFIRM_CHOSEN; if (result == RESULT_SUCCESSFUL) channel_join_confirm_pdu.u.channel_join_confirm.bit_mask = JOIN_CHANNEL_ID_PRESENT; else channel_join_confirm_pdu.u.channel_join_confirm.bit_mask = 0x00; channel_join_confirm_pdu.u.channel_join_confirm.result = (PDUResult)result; channel_join_confirm_pdu.u.channel_join_confirm.initiator = uidInitiator; channel_join_confirm_pdu.u.channel_join_confirm.requested = requested_id; channel_join_confirm_pdu.u.channel_join_confirm.join_channel_id = channel_id; /* * Send the packet to the remote provider. */ SendPacket ((PVoid) &channel_join_confirm_pdu, DOMAIN_MCS_PDU, TOP_PRIORITY); } /* * Void ChannelLeaveRequest () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "ChannelLeaveRequest" PDU through the transport interface. * * Caveats: * None. */ Void Connection::ChannelLeaveRequest ( CChannelIDList *channel_id_list) { BOOL memory_error=FALSE; DomainMCSPDU channel_leave_request_pdu; DWORD channel_ids_count; PSetOfChannelIDs channel_ids_pointer; PSetOfChannelIDs pToFree; //ChannelID chid; /* * Fill in the elements of the PDU structure. */ channel_leave_request_pdu.choice = CHANNEL_LEAVE_REQUEST_CHOSEN; /* * Allocate memory to hold the list of channels. If the allocation * fails, set the flag which will result in a callback to the * controller requesting that this connection be deleted. */ channel_ids_count = channel_id_list->GetCount(); if (channel_ids_count != 0) { DBG_SAVE_FILE_LINE channel_ids_pointer = (PSetOfChannelIDs) Allocate (channel_ids_count * sizeof (SetOfChannelIDs)); if (channel_ids_pointer == NULL) memory_error = TRUE; } else channel_ids_pointer = NULL; pToFree = channel_ids_pointer; /* * Get the base address of the array fo SetOfChannelIDs structure and * put it into the PDU structure. */ channel_leave_request_pdu.u.channel_leave_request.channel_ids = channel_ids_pointer; channel_id_list->BuildExternalList(&channel_ids_pointer); /* * Send the packet to the remote provider. */ if (memory_error == FALSE) SendPacket ((PVoid) &channel_leave_request_pdu, DOMAIN_MCS_PDU, TOP_PRIORITY); else { /* * A memory allocation failure occurred somewhere above. Report the * error and destroy this faulty connection. */ ERROR_OUT (("Connection::ChannelLeaveRequest: memory allocation failure")); DestroyConnection (REASON_PROVIDER_INITIATED); } /* * If memory was successfully allocated to hold the set of channel ID's, * then free it here. */ Free(pToFree); } /* * Void ChannelConveneRequest () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "ChannelConveneRequest" PDU through the transport interface. * * Caveats: * None. */ Void Connection::ChannelConveneRequest ( UserID uidInitiator) { DomainMCSPDU channel_convene_request_pdu; /* * Fill in the PDU structure to be encoded. */ channel_convene_request_pdu.choice = CHANNEL_CONVENE_REQUEST_CHOSEN; channel_convene_request_pdu.u.channel_convene_request.initiator = uidInitiator; /* * Send the packet to the remote provider. */ SendPacket ((PVoid) &channel_convene_request_pdu, DOMAIN_MCS_PDU, TOP_PRIORITY); } /* * Void ChannelConveneConfirm () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "ChannelConveneConfirm" PDU through the transport interface. * * Caveats: * None. */ Void Connection::ChannelConveneConfirm ( Result result, UserID uidInitiator, ChannelID channel_id) { DomainMCSPDU channel_convene_confirm_pdu; /* * Fill in the PDU structure to be encoded. */ channel_convene_confirm_pdu.choice = CHANNEL_CONVENE_CONFIRM_CHOSEN; if (result == RESULT_SUCCESSFUL) channel_convene_confirm_pdu.u.channel_convene_confirm.bit_mask = CONVENE_CHANNEL_ID_PRESENT; else channel_convene_confirm_pdu.u.channel_convene_confirm.bit_mask = 0x00; channel_convene_confirm_pdu.u.channel_convene_confirm.result = (PDUResult)result; channel_convene_confirm_pdu.u.channel_convene_confirm.initiator = uidInitiator; channel_convene_confirm_pdu.u.channel_convene_confirm.convene_channel_id = channel_id; /* * Send the packet to the remote provider. */ SendPacket ((PVoid) &channel_convene_confirm_pdu, DOMAIN_MCS_PDU, TOP_PRIORITY); } /* * Void ChannelDisbandRequest () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "ChannelDisbandRequest" PDU through the transport interface. * * Caveats: * None. */ Void Connection::ChannelDisbandRequest ( UserID uidInitiator, ChannelID channel_id) { DomainMCSPDU channel_disband_request_pdu; /* * Fill in the PDU structure to be encoded. */ channel_disband_request_pdu.choice = CHANNEL_DISBAND_REQUEST_CHOSEN; channel_disband_request_pdu.u.channel_disband_request.initiator = uidInitiator; channel_disband_request_pdu.u.channel_disband_request.channel_id = channel_id; /* * Send the packet to the remote provider. */ SendPacket ((PVoid) &channel_disband_request_pdu, DOMAIN_MCS_PDU, TOP_PRIORITY); } /* * Void ChannelDisbandIndication () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "ChannelDisbandIndication" PDU through the transport interface. * * Caveats: * None. */ Void Connection::ChannelDisbandIndication ( ChannelID channel_id) { DomainMCSPDU channel_disband_indication_pdu; /* * Fill in the PDU structure to be encoded. */ channel_disband_indication_pdu.choice = CHANNEL_DISBAND_INDICATION_CHOSEN; channel_disband_indication_pdu.u.channel_disband_indication.channel_id = channel_id; /* * Send the packet to the remote provider. */ SendPacket ((PVoid) &channel_disband_indication_pdu, DOMAIN_MCS_PDU, TOP_PRIORITY); } /* * Void ChannelAdmitRequest () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "ChannelAdmitRequest" PDU through the transport interface. * * Caveats: * None. */ Void Connection::ChannelAdmitRequest ( UserID uidInitiator, ChannelID channel_id, CUidList *user_id_list) { UserChannelRI (CHANNEL_ADMIT_REQUEST_CHOSEN, (UINT) uidInitiator, channel_id, user_id_list); } /* * Void ChannelAdmitIndication () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "ChannelAdmitIndication" PDU through the transport interface. * * Caveats: * None. */ Void Connection::ChannelAdmitIndication ( UserID uidInitiator, ChannelID channel_id, CUidList *user_id_list) { UserChannelRI (CHANNEL_ADMIT_INDICATION_CHOSEN, (UINT) uidInitiator, channel_id, user_id_list); } /* * Void ChannelExpelRequest () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "ChannelExpelRequest" PDU through the transport interface. * * Caveats: * None. */ Void Connection::ChannelExpelRequest ( UserID uidInitiator, ChannelID channel_id, CUidList *user_id_list) { UserChannelRI (CHANNEL_EXPEL_REQUEST_CHOSEN, (UINT) uidInitiator, channel_id, user_id_list); } /* * Void ChannelExpelIndication () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "ChannelExpelIndication" PDU through the transport interface. * * Caveats: * None. */ Void Connection::ChannelExpelIndication ( ChannelID channel_id, CUidList *user_id_list) { UserChannelRI (CHANNEL_EXPEL_INDICATION_CHOSEN, 0, channel_id, user_id_list); } /* * Void TokenGrabRequest () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "TokenGrabRequest" PDU through the transport interface. * * Caveats: * None. */ Void Connection::TokenGrabRequest ( UserID uidInitiator, TokenID token_id) { DomainMCSPDU token_grab_request_pdu; /* * Fill in the PDU structure to be encoded. */ token_grab_request_pdu.choice = TOKEN_GRAB_REQUEST_CHOSEN; token_grab_request_pdu.u.token_grab_request.initiator = uidInitiator; token_grab_request_pdu.u.token_grab_request.token_id = token_id; /* * Send the packet to the remote provider. */ SendPacket ((PVoid) &token_grab_request_pdu, DOMAIN_MCS_PDU, TOP_PRIORITY); } /* * Void TokenGrabConfirm () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "TokenGrabConfirm" PDU through the transport interface. * * Caveats: * None. */ Void Connection::TokenGrabConfirm ( Result result, UserID uidInitiator, TokenID token_id, TokenStatus token_status) { DomainMCSPDU token_grab_confirm_pdu; /* * Fill in the PDU structure to be encoded. */ token_grab_confirm_pdu.choice = TOKEN_GRAB_CONFIRM_CHOSEN; token_grab_confirm_pdu.u.token_grab_confirm.result = (PDUResult)result; token_grab_confirm_pdu.u.token_grab_confirm.initiator = uidInitiator; token_grab_confirm_pdu.u.token_grab_confirm.token_id = token_id; token_grab_confirm_pdu.u.token_grab_confirm.token_status = (PDUTokenStatus)token_status; /* * Send the packet to the remote provider. */ SendPacket ((PVoid) &token_grab_confirm_pdu, DOMAIN_MCS_PDU, TOP_PRIORITY); } /* * Void TokenInhibitRequest () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "TokenInhibitRequest" PDU through the transport interface. * * Caveats: * None. */ Void Connection::TokenInhibitRequest ( UserID uidInitiator, TokenID token_id) { DomainMCSPDU token_inhibit_request_pdu; /* * Fill in the PDU structure to be encoded. */ token_inhibit_request_pdu.choice = TOKEN_INHIBIT_REQUEST_CHOSEN; token_inhibit_request_pdu.u.token_inhibit_request.initiator = uidInitiator; token_inhibit_request_pdu.u.token_inhibit_request.token_id = token_id; /* * Send the packet to the remote provider. */ SendPacket ((PVoid) &token_inhibit_request_pdu, DOMAIN_MCS_PDU, TOP_PRIORITY); } /* * Void TokenInhibitConfirm () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "TokenInhibitConfirm" PDU through the transport interface. * * Caveats: * None. */ Void Connection::TokenInhibitConfirm ( Result result, UserID uidInitiator, TokenID token_id, TokenStatus token_status) { DomainMCSPDU token_inhibit_confirm_pdu; /* * Fill in the PDU structure to be encoded. */ token_inhibit_confirm_pdu.choice = TOKEN_INHIBIT_CONFIRM_CHOSEN; token_inhibit_confirm_pdu.u.token_inhibit_confirm.result = (PDUResult)result; token_inhibit_confirm_pdu.u.token_inhibit_confirm.initiator = uidInitiator; token_inhibit_confirm_pdu.u.token_inhibit_confirm.token_id = token_id; token_inhibit_confirm_pdu.u.token_inhibit_confirm.token_status = (PDUTokenStatus)token_status; /* * Send the packet to the remote provider. */ SendPacket ((PVoid) &token_inhibit_confirm_pdu, DOMAIN_MCS_PDU, TOP_PRIORITY); } /* * Void TokenGiveRequest () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "TokenGiveRequest" PDU through the transport interface. * * Caveats: * None. */ Void Connection::TokenGiveRequest ( PTokenGiveRecord pTokenGiveRec) { DomainMCSPDU token_give_request_pdu; /* * Fill in the PDU structure to be encoded. */ token_give_request_pdu.choice = TOKEN_GIVE_REQUEST_CHOSEN; token_give_request_pdu.u.token_give_request.initiator = pTokenGiveRec->uidInitiator; token_give_request_pdu.u.token_give_request.token_id = pTokenGiveRec->token_id; token_give_request_pdu.u.token_give_request.recipient = pTokenGiveRec->receiver_id; /* * Send the packet to the remote provider. */ SendPacket ((PVoid) &token_give_request_pdu, DOMAIN_MCS_PDU, TOP_PRIORITY); } /* * Void TokenGiveIndication () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "TokenGiveIndication" PDU through the transport interface. * * Caveats: * None. */ Void Connection::TokenGiveIndication ( PTokenGiveRecord pTokenGiveRec) { DomainMCSPDU token_give_indication_pdu; /* * Fill in the PDU structure to be encoded. */ token_give_indication_pdu.choice = TOKEN_GIVE_INDICATION_CHOSEN; token_give_indication_pdu.u.token_give_indication.initiator = pTokenGiveRec->uidInitiator; token_give_indication_pdu.u.token_give_indication.token_id = pTokenGiveRec->token_id; token_give_indication_pdu.u.token_give_indication.recipient = pTokenGiveRec->receiver_id; /* * Send the packet to the remote provider. */ SendPacket ((PVoid) &token_give_indication_pdu, DOMAIN_MCS_PDU, TOP_PRIORITY); } /* * Void TokenGiveResponse () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "TokenGiveResponse" PDU through the transport interface. * * Caveats: * None. */ Void Connection::TokenGiveResponse ( Result result, UserID receiver_id, TokenID token_id) { DomainMCSPDU token_give_response_pdu; /* * Fill in the PDU structure to be encoded. */ token_give_response_pdu.choice = TOKEN_GIVE_RESPONSE_CHOSEN; token_give_response_pdu.u.token_give_response.result = (PDUResult)result; token_give_response_pdu.u.token_give_response.recipient = receiver_id; token_give_response_pdu.u.token_give_response.token_id = token_id; /* * Send the packet to the remote provider. */ SendPacket ((PVoid) &token_give_response_pdu, DOMAIN_MCS_PDU, TOP_PRIORITY); } /* * Void TokenGiveConfirm () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "TokenGiveConfirm" PDU through the transport interface. * * Caveats: * None. */ Void Connection::TokenGiveConfirm ( Result result, UserID uidInitiator, TokenID token_id, TokenStatus token_status) { DomainMCSPDU token_give_confirm_pdu; /* * Fill in the PDU structure to be encoded. */ token_give_confirm_pdu.choice = TOKEN_GIVE_CONFIRM_CHOSEN; token_give_confirm_pdu.u.token_give_confirm.result = (PDUResult)result; token_give_confirm_pdu.u.token_give_confirm.initiator = uidInitiator; token_give_confirm_pdu.u.token_give_confirm.token_id = token_id; token_give_confirm_pdu.u.token_give_confirm.token_status = (PDUTokenStatus)token_status; /* * Send the packet to the remote provider. */ SendPacket ((PVoid) &token_give_confirm_pdu, DOMAIN_MCS_PDU, TOP_PRIORITY); } /* * Void TokenPleaseRequest () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "TokenPleaseRequest" PDU through the transport interface. * * Caveats: * None. */ Void Connection::TokenPleaseRequest ( UserID uidInitiator, TokenID token_id) { DomainMCSPDU token_please_request_pdu; /* * Fill in the PDU structure to be encoded. */ token_please_request_pdu.choice = TOKEN_PLEASE_REQUEST_CHOSEN; token_please_request_pdu.u.token_please_request.initiator = uidInitiator; token_please_request_pdu.u.token_please_request.token_id = token_id; /* * Send the packet to the remote provider. */ SendPacket ((PVoid) &token_please_request_pdu, DOMAIN_MCS_PDU, TOP_PRIORITY); } /* * Void TokenPleaseIndication () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "TokenPleaseIndication" PDU through the transport interface. * * Caveats: * None. */ Void Connection::TokenPleaseIndication ( UserID uidInitiator, TokenID token_id) { DomainMCSPDU token_please_indication_pdu; /* * Fill in the PDU structure to be encoded. */ token_please_indication_pdu.choice = TOKEN_PLEASE_INDICATION_CHOSEN; token_please_indication_pdu.u.token_please_request.initiator = uidInitiator; token_please_indication_pdu.u.token_please_request.token_id = token_id; /* * Send the packet to the remote provider. */ SendPacket ((PVoid) &token_please_indication_pdu, DOMAIN_MCS_PDU, TOP_PRIORITY); } /* * Void TokenReleaseRequest () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "TokenReleaseRequest" PDU through the transport interface. * * Caveats: * None. */ Void Connection::TokenReleaseRequest ( UserID uidInitiator, TokenID token_id) { DomainMCSPDU token_release_request_pdu; /* * Fill in the PDU structure to be encoded. */ token_release_request_pdu.choice = TOKEN_RELEASE_REQUEST_CHOSEN; token_release_request_pdu.u.token_release_request.initiator = uidInitiator; token_release_request_pdu.u.token_release_request.token_id = token_id; /* * Send the packet to the remote provider. */ SendPacket ((PVoid) &token_release_request_pdu, DOMAIN_MCS_PDU, TOP_PRIORITY); } /* * Void TokenReleaseConfirm () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "TokenReleaseConfirm" PDU through the transport interface. * * Caveats: * None. */ Void Connection::TokenReleaseConfirm ( Result result, UserID uidInitiator, TokenID token_id, TokenStatus token_status) { DomainMCSPDU token_release_confirm_pdu; /* * Fill in the PDU structure to be encoded. */ token_release_confirm_pdu.choice = TOKEN_RELEASE_CONFIRM_CHOSEN; token_release_confirm_pdu.u.token_release_confirm.result = (PDUResult)result; token_release_confirm_pdu.u.token_release_confirm.initiator = uidInitiator; token_release_confirm_pdu.u.token_release_confirm.token_id = token_id; token_release_confirm_pdu.u.token_release_confirm.token_status = (PDUTokenStatus)token_status; /* * Send the packet to the remote provider. */ SendPacket ((PVoid) &token_release_confirm_pdu, DOMAIN_MCS_PDU, TOP_PRIORITY); } /* * Void TokenTestRequest () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "TokenTestRequest" PDU through the transport interface. * * Caveats: * None. */ Void Connection::TokenTestRequest ( UserID uidInitiator, TokenID token_id) { DomainMCSPDU token_test_request_pdu; /* * Fill in the PDU structure to be encoded. */ token_test_request_pdu.choice = TOKEN_TEST_REQUEST_CHOSEN; token_test_request_pdu.u.token_test_request.initiator = uidInitiator; token_test_request_pdu.u.token_test_request.token_id = token_id; /* * Send the packet to the remote provider. */ SendPacket ((PVoid) &token_test_request_pdu, DOMAIN_MCS_PDU, TOP_PRIORITY); } /* * Void TokenTestConfirm () * * Public * * Functional Description: * This routine is called by the domain in order to send a * "TokenTestConfirm" PDU through the transport interface. * * Caveats: * None. */ Void Connection::TokenTestConfirm ( UserID uidInitiator, TokenID token_id, TokenStatus token_status) { DomainMCSPDU token_test_confirm_pdu; /* * Fill in the PDU structure to be encoded. */ token_test_confirm_pdu.choice = TOKEN_TEST_CONFIRM_CHOSEN; token_test_confirm_pdu.u.token_test_confirm.initiator = uidInitiator; token_test_confirm_pdu.u.token_test_confirm.token_id = token_id; token_test_confirm_pdu.u.token_test_confirm.token_status = (PDUTokenStatus)token_status; /* * Send the packet to the remote provider. */ SendPacket ((PVoid) &token_test_confirm_pdu, DOMAIN_MCS_PDU, TOP_PRIORITY); } /* * Void MergeDomainIndication () * * Public * * Functional Description: * This function is called when the attached domain enters or leaves the * merge state. */ Void Connection::MergeDomainIndication ( MergeStatus merge_status) { /* * If this indication shows that a domain merger is in progress, set the * boolean flag that prevents the sending of MCS commands to the domain. * Otherwise, reset it. */ if (merge_status == MERGE_DOMAIN_IN_PROGRESS) { TRACE_OUT (("Connection::MergeDomainIndication: entering merge state")); Merge_In_Progress = TRUE; } else { TRACE_OUT (("Connection::MergeDomainIndication: leaving merge state")); Merge_In_Progress = FALSE; } } /* * Void SendPacket () * * Private * * Functional Description: * This routine is called in order to create a packet which will hold * the PDU to be sent to the remote provider. The packet will be queued * up for transmission through the transport interface. * * Caveats: * None. */ Void Connection::SendPacket ( PVoid pdu_structure, int pdu_type, Priority priority) { unsigned int encoding_rules; PPacket packet; PacketError packet_error; BOOL bFlush; /* * Set the appropriate encoding rules for this PDU according to what type * it is. */ if (pdu_type == CONNECT_MCS_PDU) { encoding_rules = BASIC_ENCODING_RULES; bFlush = FALSE; // TRACE_OUT(("Connect SendPacket: PDU type: %d", (UINT) ((ConnectMCSPDU *) pdu_structure)->choice)); } else { encoding_rules = Encoding_Rules; bFlush = TRUE; // TRACE_OUT(("Domain SendPacket: PDU type: %d", (UINT) ((DomainMCSPDU *) pdu_structure)->choice)); } /* * Create a packet which will be used to hold the data to be sent * through the transport interface. Check to make sure the packet is * successfully created. Issue a callback to the controller requesting * deletion of this connection if the packet is not successfully created. */ DBG_SAVE_FILE_LINE packet = new Packet ( (PPacketCoder) g_MCSCoder, encoding_rules, pdu_structure, (int) pdu_type, Upward_Connection, &packet_error); if (packet != NULL) { if (packet_error == PACKET_NO_ERROR) { /* * Lock the encoded PDU data and queue the packet up for * transmission through the transport interface. */ QueueForTransmission ((PSimplePacket) packet, priority, bFlush); } else { /* * The packet creation has failed due to an internal error so * issue an owner callback to ask for deletion. */ DestroyConnection (REASON_PROVIDER_INITIATED); } /* * The packet is freed here so that it will be deleted when it's lock * count reaches zero. */ packet->Unlock (); } else { /* * The packet creation has failed so issue an owner callback * to ask for deletion. */ DestroyConnection (REASON_PROVIDER_INITIATED); } } /* * Void QueueForTransmission() * * Private * * Functional Description: * This routine encodes a PDU and places data units into the transmission queue so * they can be transmitted through the transport interface when possible. * An attempt is made to flush the queue and the transmitter is polled * in order to go ahead and send the data immediately, if possible, instead * of waiting for a timer event to occur. * * Caveats: * None. */ Void Connection::QueueForTransmission ( PSimplePacket packet, Priority priority, BOOL bFlush) { int p; ASSERT (g_Transport != NULL); packet->Lock(); /* * Attempt to set the packet directly to the transport without queueing it. * If this is done, it can eliminate queueing time and a thread switch. * For this to be possible, all higher priorities must have no pending * packets and the bFlush parameter should be TRUE. */ if (bFlush) { for (p = (int) TOP_PRIORITY; p <= (int) priority; p++) { if (m_OutPktQueue[p].GetCount() > 0) break; } if (p > priority) { /* * There are no packets queued up for higher priorities. We can attempt * to send the packet directly, by-passing the queue. */ if (FlushAMessage (packet, priority)) { return; } } } /* * Place the data unit in the proper queue. Increment the counter for that * queue and increment the transmission counter. */ m_OutPktQueue[priority].Append(packet); /* * If this is the first packet queued up for the specified priority, * then we must send a DataRequestReady to the transport interface * object. Note that if other packets are already queued up, then it * is not necessary to inform the transport interface object, since it * already knows it has at least one). */ if (m_OutPktQueue[priority].GetCount() == 1) g_Transport->DataRequestReady (); } /* * BOOL FlushAMessage() * * Private * * Functional Description: * This routine will only flush one MCS PDU to the transport layer. * * Parameters: * packet: the packet to send. * priority: the packet's priority * * Return value: * TRUE, if the message was successfully sent. FALSE, otherwise. * */ BOOL Connection::FlushAMessage (PSimplePacket packet, Priority priority) { if (Domain_Traffic_Allowed == FALSE && packet->GetPDUType () == DOMAIN_MCS_PDU) { return FALSE; } if (packet->IsDataPacket()) ((PDataPacket) packet)->SetDirection (Upward_Connection); /* * Send the PDU to the transport interface. */ if (DataRequest (Transport_Connection[priority], packet) != TRANSPORT_WRITE_QUEUE_FULL) { packet->Unlock(); return TRUE; } return FALSE; } /* * Void FlushMessageQueue() * * Private * * Functional Description: * This routine flushes the transmit queue by copying the data unit * into the output buffer and calling into the transport interface to * give it a chance to accept the data. * * Return value: * TRUE, if there remain un-processed msgs in the connection message queue * FALSE, if all the msgs in the connection msg queue were processed. * * Caveats: * None. */ BOOL Connection::FlushMessageQueue() { int priority; BOOL return_value = FALSE; ASSERT (g_Transport != NULL); /* * Loop through all four priority levels of transmission queues. */ for (priority = 0; priority < MAXIMUM_PRIORITIES; priority++) { if (m_OutPktQueue[priority].GetCount() > 0) { return_value |= FlushPriority ((Priority) priority); } } return (return_value); } /* * BOOL FlushPriority () * * Private * * Functional Description: * * Return value: * TRUE, if there remain un-processed msgs in the connection message queue * FALSE, if all the msgs in the connection msg queue were processed. * * Caveats: * None. */ BOOL Connection::FlushPriority ( Priority priority) { PSimplePacket packet; BOOL return_value = FALSE; /* * Check to see if the transport connection for this priority is * ready. If not, skip it for now. */ if (Transport_Connection_State[priority] == TRANSPORT_CONNECTION_READY) { /* * If there is no packet in the queue, we may be here to send the * remainder of a packet that has been accepted by transport earlier. * We need to flush this remainder of the packet. */ if (m_OutPktQueue[priority].IsEmpty()) { if (DataRequest (Transport_Connection[priority], NULL) == TRANSPORT_WRITE_QUEUE_FULL) { return_value = TRUE; } } else { /* * While data exists in this queue and the transport interface is * able to accept it, retrieve the next packet from the queue and * send the data to the transport interface. */ while (NULL != (packet = m_OutPktQueue[priority].Get())) { if (! FlushAMessage (packet, priority)) { /* * If the transport layer has rejected the PDU, then it is * necessary to leave it in the queue (at the front). * Then break out of the loop to prevent additional * attempts to transmit data at this priority. */ return_value = TRUE; if (packet != NULL) { m_OutPktQueue[priority].Prepend(packet); } break; } } } } else return_value = TRUE; return (return_value); } /* * ULong OwnerCallback() * * Private * * Functional Description: * This routine allows the transport interface to call into the connection * in order to notify the connection of data reception. This routine * decodes the incoming data, notifies the controller if necessary and/or * makes the necessary calls into the domain. * * Caveats: * None. */ TransportError Connection::HandleDataIndication ( PTransportData pTransport_data, TransportConnection transport_connection ) { int priority; TransportError rc = TRANSPORT_NO_ERROR; /* * Data is being received through the transport interface. Determine * what priority this data is arriving at. This will be used to see * what type of PDU this is supposed to be (CONNECT or DOMAIN). */ for (priority = 0; priority < MAXIMUM_PRIORITIES; priority++) { if (IS_SAME_TRANSPORT_CONNECTION(Transport_Connection[priority], transport_connection)) { break; } } /* * Make sure that this transport connection was somewhere in the the * transport connection list before processing the PDU. If it was not, * then report an error and ignore the PDU. */ if (priority < MAXIMUM_PRIORITIES) { int pdu_type; unsigned int encoding_rules; PSimplePacket packet; PacketError packet_error; PVoid pdu_structure; /* * Determine what type of PDU this should be. */ pdu_type = Transport_Connection_PDU_Type[priority]; /* * Set the appropriate encoding rules for this PDU according to * what type it is. */ encoding_rules = (pdu_type == CONNECT_MCS_PDU) ? BASIC_ENCODING_RULES : Encoding_Rules; /* * Get the pointer to the data indication structure from the the * parameter list. Then construct a packet object to represent * this inbound data. */ /* * Crete a Packet or a DataPacket, depending on whether this * is an MCS data packet. */ if (g_MCSCoder->IsMCSDataPacket ( pTransport_data->user_data + PROTOCOL_OVERHEAD_X224, encoding_rules)) { ASSERT (encoding_rules == PACKED_ENCODING_RULES); DBG_SAVE_FILE_LINE packet = (PSimplePacket) new DataPacket (pTransport_data, ! Upward_Connection); packet_error = PACKET_NO_ERROR; } else { DBG_SAVE_FILE_LINE packet = (PSimplePacket) new Packet ( (PPacketCoder) g_MCSCoder, encoding_rules, pTransport_data->user_data + PROTOCOL_OVERHEAD_X224, pTransport_data->user_data_length - PROTOCOL_OVERHEAD_X224, pdu_type, ! Upward_Connection, &packet_error); } if (packet != NULL) { if (packet_error == PACKET_NO_ERROR) { /* * Retrieve a pointer to the decoded data */ pdu_structure = packet->GetDecodedData (); /* * Process the PDU according to what type it is. */ if (pdu_type == CONNECT_MCS_PDU) { switch (((PConnectMCSPDU) pdu_structure)->choice) { case CONNECT_RESPONSE_CHOSEN: rc = ProcessConnectResponse ( &((PConnectMCSPDU) pdu_structure)-> u.connect_response); /* * Now that we have received and processed a * connect PDU over this transport connection, * we must indicate that the next PDU received * must be a domain PDU. */ Transport_Connection_PDU_Type[priority] = DOMAIN_MCS_PDU; break; case CONNECT_RESULT_CHOSEN: ProcessConnectResult ( &((PConnectMCSPDU) pdu_structure)-> u.connect_result); /* * Now that we have received and processed a * connect PDU over this transport connection, * we must indicate that the next PDU received * must be a domain PDU. */ Transport_Connection_PDU_Type[priority] = DOMAIN_MCS_PDU; break; default: /* * We have received a PDU that should not have * been received. Ignore it. */ ERROR_OUT (("Connection::HandleDataIndication: Unknown ConnectMCSPDU Rxd")); break; } } else { /* * Verify that current conditions are appropriate for a request to be * accepted from a transport connection. */ rc = ValidateConnectionRequest (); if (rc == TRANSPORT_NO_ERROR) { switch (((PDomainMCSPDU) pdu_structure)->choice) { case SEND_DATA_REQUEST_CHOSEN: ProcessSendDataRequest ( &((PDomainMCSPDU) pdu_structure)->u. send_data_request, (PDataPacket) packet); break; case SEND_DATA_INDICATION_CHOSEN: ProcessSendDataIndication ( &((PDomainMCSPDU) pdu_structure)->u. send_data_indication, (PDataPacket) packet); break; case UNIFORM_SEND_DATA_REQUEST_CHOSEN: ProcessUniformSendDataRequest ( &((PDomainMCSPDU) pdu_structure)->u. uniform_send_data_request, (PDataPacket) packet); break; case UNIFORM_SEND_DATA_INDICATION_CHOSEN: ProcessUniformSendDataIndication ( &((PDomainMCSPDU) pdu_structure)->u. uniform_send_data_indication, (PDataPacket) packet); break; case PLUMB_DOMAIN_INDICATION_CHOSEN: ProcessPlumbDomainIndication ( &((PDomainMCSPDU) pdu_structure)->u. plumb_domain_indication); break; case ERECT_DOMAIN_REQUEST_CHOSEN: ProcessErectDomainRequest ( &((PDomainMCSPDU) pdu_structure)->u. erect_domain_request); break; case MERGE_CHANNELS_REQUEST_CHOSEN: rc = ProcessMergeChannelsRequest ( &((PDomainMCSPDU) pdu_structure)->u. merge_channels_request); break; case MERGE_CHANNELS_CONFIRM_CHOSEN: rc = ProcessMergeChannelsConfirm ( &((PDomainMCSPDU) pdu_structure)->u. merge_channels_confirm); break; case PURGE_CHANNEL_INDICATION_CHOSEN: ProcessPurgeChannelIndication ( &((PDomainMCSPDU) pdu_structure)->u. purge_channel_indication); break; case MERGE_TOKENS_REQUEST_CHOSEN: rc = ProcessMergeTokensRequest ( &((PDomainMCSPDU) pdu_structure)->u. merge_tokens_request); break; case MERGE_TOKENS_CONFIRM_CHOSEN: rc = ProcessMergeTokensConfirm ( &((PDomainMCSPDU) pdu_structure)->u. merge_tokens_confirm); break; case PURGE_TOKEN_INDICATION_CHOSEN: ProcessPurgeTokenIndication ( &((PDomainMCSPDU) pdu_structure)->u. purge_token_indication); break; case DISCONNECT_PROVIDER_ULTIMATUM_CHOSEN: ProcessDisconnectProviderUltimatum ( &((PDomainMCSPDU) pdu_structure)->u. disconnect_provider_ultimatum); break; case REJECT_ULTIMATUM_CHOSEN: ProcessRejectUltimatum ( &((PDomainMCSPDU) pdu_structure)->u. reject_user_ultimatum); break; case ATTACH_USER_REQUEST_CHOSEN: ProcessAttachUserRequest ( &((PDomainMCSPDU) pdu_structure)->u. attach_user_request); break; case ATTACH_USER_CONFIRM_CHOSEN: ProcessAttachUserConfirm ( &((PDomainMCSPDU) pdu_structure)->u. attach_user_confirm); break; case DETACH_USER_REQUEST_CHOSEN: ProcessDetachUserRequest ( &((PDomainMCSPDU) pdu_structure)->u. detach_user_request); break; case DETACH_USER_INDICATION_CHOSEN: ProcessDetachUserIndication ( &((PDomainMCSPDU) pdu_structure)->u. detach_user_indication); break; case CHANNEL_JOIN_REQUEST_CHOSEN: ProcessChannelJoinRequest ( &((PDomainMCSPDU) pdu_structure)->u. channel_join_request); break; case CHANNEL_JOIN_CONFIRM_CHOSEN: ProcessChannelJoinConfirm ( &((PDomainMCSPDU) pdu_structure)->u. channel_join_confirm); break; case CHANNEL_LEAVE_REQUEST_CHOSEN: ProcessChannelLeaveRequest ( &((PDomainMCSPDU) pdu_structure)->u. channel_leave_request); break; case CHANNEL_CONVENE_REQUEST_CHOSEN: ProcessChannelConveneRequest ( &((PDomainMCSPDU) pdu_structure)->u. channel_convene_request); break; case CHANNEL_CONVENE_CONFIRM_CHOSEN: ProcessChannelConveneConfirm ( &((PDomainMCSPDU) pdu_structure)->u. channel_convene_confirm); break; case CHANNEL_DISBAND_REQUEST_CHOSEN: ProcessChannelDisbandRequest ( &((PDomainMCSPDU) pdu_structure)->u. channel_disband_request); break; case CHANNEL_DISBAND_INDICATION_CHOSEN: ProcessChannelDisbandIndication ( &((PDomainMCSPDU) pdu_structure)->u. channel_disband_indication); break; case CHANNEL_ADMIT_REQUEST_CHOSEN: ProcessChannelAdmitRequest ( &((PDomainMCSPDU) pdu_structure)->u. channel_admit_request); break; case CHANNEL_ADMIT_INDICATION_CHOSEN: ProcessChannelAdmitIndication ( &((PDomainMCSPDU) pdu_structure)->u. channel_admit_indication); break; case CHANNEL_EXPEL_REQUEST_CHOSEN: ProcessChannelExpelRequest ( &((PDomainMCSPDU) pdu_structure)->u. channel_expel_request); break; case CHANNEL_EXPEL_INDICATION_CHOSEN: ProcessChannelExpelIndication ( &((PDomainMCSPDU) pdu_structure)->u. channel_expel_indication); break; case TOKEN_GRAB_REQUEST_CHOSEN: ProcessTokenGrabRequest ( &((PDomainMCSPDU) pdu_structure)->u. token_grab_request); break; case TOKEN_GRAB_CONFIRM_CHOSEN: ProcessTokenGrabConfirm ( &((PDomainMCSPDU) pdu_structure)->u. token_grab_confirm); break; case TOKEN_INHIBIT_REQUEST_CHOSEN: ProcessTokenInhibitRequest ( &((PDomainMCSPDU) pdu_structure)->u. token_inhibit_request); break; case TOKEN_INHIBIT_CONFIRM_CHOSEN: ProcessTokenInhibitConfirm ( &((PDomainMCSPDU) pdu_structure)->u. token_inhibit_confirm); break; case TOKEN_GIVE_REQUEST_CHOSEN: ProcessTokenGiveRequest ( &((PDomainMCSPDU) pdu_structure)->u. token_give_request); break; case TOKEN_GIVE_INDICATION_CHOSEN: ProcessTokenGiveIndication ( &((PDomainMCSPDU) pdu_structure)->u. token_give_indication); break; case TOKEN_GIVE_RESPONSE_CHOSEN: ProcessTokenGiveResponse ( &((PDomainMCSPDU) pdu_structure)->u. token_give_response); break; case TOKEN_GIVE_CONFIRM_CHOSEN: ProcessTokenGiveConfirm ( &((PDomainMCSPDU) pdu_structure)->u. token_give_confirm); break; case TOKEN_PLEASE_REQUEST_CHOSEN: ProcessTokenPleaseRequest ( &((PDomainMCSPDU) pdu_structure)->u. token_please_request); break; case TOKEN_PLEASE_INDICATION_CHOSEN: ProcessTokenPleaseIndication ( &((PDomainMCSPDU) pdu_structure)->u. token_please_indication); break; case TOKEN_RELEASE_REQUEST_CHOSEN: ProcessTokenReleaseRequest ( &((PDomainMCSPDU) pdu_structure)->u. token_release_request); break; case TOKEN_RELEASE_CONFIRM_CHOSEN: ProcessTokenReleaseConfirm ( &((PDomainMCSPDU) pdu_structure)->u. token_release_confirm); break; case TOKEN_TEST_REQUEST_CHOSEN: ProcessTokenTestRequest ( &((PDomainMCSPDU) pdu_structure)->u. token_test_request); break; case TOKEN_TEST_CONFIRM_CHOSEN: ProcessTokenTestConfirm ( &((PDomainMCSPDU) pdu_structure)->u. token_test_confirm); break; default: ERROR_OUT (("Connection::HandleDataIndication: Unknown DomainMCSPDU Rxd")); break; } } else { ASSERT (TRANSPORT_READ_QUEUE_FULL == rc); if (packet->IsDataPacket()) { /* * We are returning TRANSPORT_READ_QUEUE_FULL to the transport. * The transport will attempt to deliver the data again later. * However, we have to delete the DataPacket we created here, which * will attempt to free the buffer that will be delivered again * later. So, let's lock it now. */ LockMemory (pTransport_data->memory); } } } /* If this was a non-data PDU, we need to free up the transport * buffer with the original data. */ if ((! packet->IsDataPacket()) && (rc == TRANSPORT_NO_ERROR)) FreeMemory (pTransport_data->memory); /* * Free the packet. This will result in the destruction of the * packet unless it is a "Send Data" packet which has been * locked by someone else. */ packet->Unlock (); } else { /* * Although the construction of the packet object itself * was successful, an error was generated in its * constructor. We must therefore reject the packet. */ WARNING_OUT (("Connection::HandleDataIndication: packet constructor failure")); delete packet; rc = TRANSPORT_READ_QUEUE_FULL; } } else { /* * We were not able to construct a packet object to represent * the inbound data. It is therefore necessary to reject the * data from the transport layer, so that it can be retried * later. */ WARNING_OUT (("Connection::HandleDataIndication: packet allocation failure")); rc = TRANSPORT_READ_QUEUE_FULL; } } else { /* * This transport connection is not listed as one of the ones being * used by this MCS connection. It is therefore necessary to * ignore the PDU. */ WARNING_OUT (("Connection::HandleDataIndication: unknown transport connection")); } return rc; } void Connection::HandleBufferEmptyIndication ( TransportConnection transport_connection ) { /* * Determine what priority this indication is associated with. */ for (int priority = 0; priority < MAXIMUM_PRIORITIES; priority++) { if (IS_SAME_TRANSPORT_CONNECTION(Transport_Connection[priority], transport_connection)) /* * Try to flush existing data downward. */ FlushPriority ((Priority) priority); } } void Connection::HandleConnectConfirm ( TransportConnection transport_connection ) { /* * A confirm has been received as the result of an outbound connect * request. This tells us that the request was successful. */ TRACE_OUT (("Connection::HandleConnectConfirm: received CONNECT_CONFIRM")); for (int priority = 0; priority < MAXIMUM_PRIORITIES; priority++) { if (IS_SAME_TRANSPORT_CONNECTION(Transport_Connection[priority], transport_connection) && (Transport_Connection_State[priority] == TRANSPORT_CONNECTION_PENDING)) { Transport_Connection_State[priority] = TRANSPORT_CONNECTION_READY; } } } void Connection::HandleDisconnectIndication ( TransportConnection transport_connection, ULONG *pnNotify ) { Reason reason; /* * A disconnection indication has been received through the transport * interface. Notify the controller and the domain and set the flag * indicating a connection deletion is pending. */ TRACE_OUT (("Connection::HandleDisconnectIndication: received DISCONNECT_INDICATION")); /* * For each priority level that is using that disconnected * transport connection, mark it as unassigned. This serves two * purposes. First, it prevents any attempt to send data on the * transport connection that is no longer valid. Second, it * prevents the destructor of this object from sending a * disconnect request. */ for (int priority = 0; priority < MAXIMUM_PRIORITIES; priority++) { if (IS_SAME_TRANSPORT_CONNECTION(Transport_Connection[priority], transport_connection)) { Transport_Connection_State[priority] = TRANSPORT_CONNECTION_UNASSIGNED; } } /* * Losing ANY of its transport connections is fatal to an MCS * connection. Therefore, this connection object must delete * itself. */ ASSERT(pnNotify); switch (*pnNotify) { case TPRT_NOTIFY_REMOTE_NO_SECURITY : reason = REASON_REMOTE_NO_SECURITY; break; case TPRT_NOTIFY_REMOTE_DOWNLEVEL_SECURITY : reason = REASON_REMOTE_DOWNLEVEL_SECURITY; break; case TPRT_NOTIFY_REMOTE_REQUIRE_SECURITY : reason = REASON_REMOTE_REQUIRE_SECURITY; break; case TPRT_NOTIFY_AUTHENTICATION_FAILED: reason = REASON_AUTHENTICATION_FAILED; break; default : reason = REASON_DOMAIN_DISCONNECTED; break; } DestroyConnection (reason); } void CChannelIDList::BuildExternalList(PSetOfChannelIDs *ppChannelIDs) { PSetOfChannelIDs p = *ppChannelIDs; ChannelID chid; if (p != NULL) { /* * Iterate through the set of channel ids, filling in the PDU * structure. */ for (Reset(); NULL != (chid = Iterate()); p++) { p->value = chid; p->next = p + 1; } /* * Decrement the pointer in order to set the last "next" * pointer to NULL. */ (p - 1)->next = NULL; *ppChannelIDs = p; } } void CTokenIDList::BuildExternalList(PSetOfTokenIDs *ppTokenIDs) { PSetOfTokenIDs p = *ppTokenIDs; TokenID tid; if (p != NULL) { /* * Iterate through the set of token ids, filling in the PDU * structure. */ for (Reset(); NULL != (tid = Iterate()); p++) { p->value = tid; p->next = p + 1; } /* * Decrement the pointer in order to set the last "next" * pointer to NULL. */ (p - 1)->next = NULL; *ppTokenIDs = p; } } void CUidList::BuildExternalList(PSetOfUserIDs *ppUserIDs) { PSetOfUserIDs p = *ppUserIDs; UserID uid; if (p != NULL) { /* * Iterate through the set of user ids, filling in the PDU * structure. */ for (Reset(); NULL != (uid = Iterate()); p++) { p->value = uid; p->next = p + 1; } /* * Decrement the pointer in order to set the last "next" * pointer to NULL. */ (p - 1)->next = NULL; *ppUserIDs = p; } }