/*++ Copyright (C) Microsoft Corporation, 2001 Module Name: HttpRTS.cxx Abstract: HTTP2 RTS packets support functions. Author: KamenM 09-07-01 Created Revision History: --*/ #include #include const int TunnelSettingsCommandTypeSizes[LAST_RTS_COMMAND + 1] = { sizeof(ULONG), // tsctReceiveWindowSize sizeof(FlowControlAck), // tsctFlowControlAck sizeof(ULONG), // tsctConnectionTimeout sizeof(ChannelSettingCookie), // tsctCookie sizeof(ULONG), // tsctChannelLifetime sizeof(ULONG), // tsctClientKeepalive sizeof(ULONG), // tsctVersion 0, // tsctEmpty sizeof(ULONG), // tsctPadding - size is variable. This is only for the conformance count 0, // tsctNANCE - no operands 0, // tsctANCE - no operands sizeof(ChannelSettingClientAddress), // tsctClientAddress sizeof(ChannelSettingCookie), // tsctAssociationGroupId sizeof(ULONG), // tsctDestination sizeof(ULONG) // tsctPingTrafficSentNotify }; const int ClientAddressSizes[] = { FIELD_OFFSET(ChannelSettingClientAddress, u) + sizeof(SOCKADDR_IN), FIELD_OFFSET(ChannelSettingClientAddress, u) + sizeof(SOCKADDR_IN6) }; BYTE *ValidateRTSPacketCommon ( IN BYTE *Packet, IN ULONG PacketLength ) /*++ Routine Description: Validates the common portions of an RTS packet. Arguments: Packet - the packet to be validated. PacketLength - the length of the packet. Return Value: A pointer to the location after the common part if successful. NULL is validation failed. --*/ { rpcconn_tunnel_settings *RTS = (rpcconn_tunnel_settings *)Packet; if (PacketLength < BaseRTSSizeAndPadding) { CORRUPTION_ASSERT(0); return NULL; } if (RTS->common.frag_length != (unsigned short) PacketLength) { CORRUPTION_ASSERT(0); return NULL; } if ( (RTS->common.rpc_vers != OSF_RPC_V20_VERS) || (RTS->common.rpc_vers_minor > OSF_RPC_V20_VERS_MINOR)) { CORRUPTION_ASSERT(0); return NULL; } if (RTS->common.pfc_flags != (PFC_FIRST_FRAG | PFC_LAST_FRAG)) { CORRUPTION_ASSERT(0); return NULL; } if (RTS->common.drep[0] != NDR_LITTLE_ENDIAN) { CORRUPTION_ASSERT(0); return NULL; } if ((RTS->common.auth_length != 0) || (RTS->common.call_id != 0)) { CORRUPTION_ASSERT(0); return NULL; } return (Packet + BaseRTSSizeAndPadding); } RPC_STATUS CheckPacketForForwarding ( IN BYTE *Packet, IN ULONG PacketLength, IN ForwardDestinations CurrentLocation ) /*++ Routine Description: Checks whether a packet needs forwarding, and if yes, patches up the protocol version if it is present. Arguments: Packet - the packet to be validated. PacketLength - the length of the packet. CurrentLocation - the current location we're in. This is how this routine knows whether to forward. Return Value: RPC_S_OK for success (means the packet is for us) RPC_P_PACKET_NEEDS_FORWARDING - success, but packet is not for us RPC_S_PROTOCOL_ERROR - packet is garbled and cannot be processed --*/ { BYTE *CurrentPosition; ULONG CurrentLength; rpcconn_tunnel_settings *RTS = (rpcconn_tunnel_settings *)Packet; TunnelSettingsCommand *CurrentCommand; int i; BOOL ForwardingNeeded; CurrentPosition = ValidateRTSPacketCommon(Packet, PacketLength); if (CurrentPosition == NULL) return RPC_S_PROTOCOL_ERROR; ForwardingNeeded = FALSE; CurrentLength = CurrentPosition - Packet; CurrentCommand = (TunnelSettingsCommand *)CurrentPosition; for (i = 0; i < RTS->NumberOfSettingCommands; i ++) { // check if there is enough to read the command after this CurrentLength += BaseRTSCommandSize; if (CurrentLength > PacketLength) return RPC_S_PROTOCOL_ERROR; if (CurrentCommand->CommandType == tsctDestination) { CurrentLength += SIZE_OF_RTS_CMD_AND_PADDING(tsctDestination); if (CurrentLength > PacketLength) return RPC_S_PROTOCOL_ERROR; if (CurrentCommand->u.Destination == CurrentLocation) return RPC_S_OK; ForwardingNeeded = TRUE; } else { if (CurrentCommand->CommandType > LAST_RTS_COMMAND) return RPC_S_PROTOCOL_ERROR; CurrentLength += SIZE_OF_RTS_CMD_AND_PADDING(CurrentCommand->CommandType); } CurrentCommand = (TunnelSettingsCommand *)(Packet + CurrentLength); } if (ForwardingNeeded) { return RPC_P_PACKET_NEEDS_FORWARDING; } return RPC_S_OK; } BOOL UntrustedIsPingPacket ( IN BYTE *Packet, IN ULONG PacketLength ) /*++ Routine Description: Checks if a packet coming from an untrusted source is a ping packet. Arguments: Packet - the packet to be validated. PacketLength - the length of the packet. Return Value: non-zero if it is a valid ping packet. zero if it is a valid non-ping packet or if it is an invalid packet. --*/ { BYTE *CurrentPosition; rpcconn_tunnel_settings *RTS; CurrentPosition = ValidateRTSPacketCommon(Packet, PacketLength); if (CurrentPosition == NULL) return FALSE; RTS = (rpcconn_tunnel_settings *)Packet; return (RTS->Flags & RTS_FLAG_PING); } BOOL IsEchoPacket ( IN BYTE *Packet, IN ULONG PacketLength ) /*++ Routine Description: Checks if a packet is an echo packet. Arguments: Packet - the packet to be validated. PacketLength - the length of the packet. Return Value: non-zero if it is a valid echo packet. zero if it is a valid non-echo packet or if it is an invalid packet. --*/ { BYTE *CurrentPosition; rpcconn_tunnel_settings *RTS; CurrentPosition = ValidateRTSPacketCommon(Packet, PacketLength); if (CurrentPosition == NULL) return FALSE; RTS = (rpcconn_tunnel_settings *)Packet; return (RTS->Flags & RTS_FLAG_ECHO); } BOOL IsOtherCmdPacket ( IN BYTE *Packet, IN ULONG PacketLength ) /*++ Routine Description: Checks if a packet coming from an untrusted source is a other cmd packet. Arguments: Packet - the packet to be validated. PacketLength - the length of the packet. Return Value: non-zero if it is a valid other cmd packet. zero if it is not a valid other cmd packet. --*/ { BYTE *CurrentPosition; rpcconn_tunnel_settings *RTS; CurrentPosition = ValidateRTSPacketCommon(Packet, PacketLength); if (CurrentPosition == NULL) return FALSE; RTS = (rpcconn_tunnel_settings *)Packet; return (RTS->Flags & RTS_FLAG_OTHER_CMD); } HTTP2SendContext *AllocateAndInitializePingPacket ( void ) /*++ Routine Description: Allocates and initializes an RTS ping packet Arguments: Return Value: The allocated send context or NULL for out-of-memory --*/ { HTTP2SendContext *SendContext; TunnelSettingsCommand *CurrentCommand; rpcconn_tunnel_settings *RTS; SendContext = AllocateAndInitializeRTSPacket( 0 ); if (SendContext) { RTS = GetRTSPacketFromSendContext(SendContext); RTS->Flags = RTS_FLAG_PING; RTS->NumberOfSettingCommands = 0; } return SendContext; } HTTP2SendContext *AllocateAndInitializePingPacketWithSize ( IN ULONG TotalPacketSize ) /*++ Routine Description: Allocates and initializes an RTS ping packet padding the packet until a certain size. Arguments: TotalPacketSize - the total desired size of the packet. Return Value: The allocated send context or NULL for out-of-memory --*/ { HTTP2SendContext *SendContext; TunnelSettingsCommand *CurrentCommand; rpcconn_tunnel_settings *RTS; BOOL UseEmpty; ULONG ExtraSize; // the size of empty must be 0 for the calculation below to work ASSERT(SIZE_OF_RTS_CMD_AND_PADDING(tsctEmpty) == 0); ASSERT(TotalPacketSize >= BaseRTSSizeAndPadding + BaseRTSCommandSize * 1 + SIZE_OF_RTS_CMD_AND_PADDING(tsctEmpty)); // reduce the TotalPacketSize to the size of the actual padding // We subtract the base packet size + the padding command itself TotalPacketSize -= BaseRTSCommandSize * 1 + BaseRTSSizeAndPadding; SendContext = AllocateAndInitializeRTSPacket( BaseRTSCommandSize * 1 + TotalPacketSize ); if (SendContext) { // if we were required to use larger size, we'll use the padding. // if it was smaller, we'll use the empty command if (TotalPacketSize >= SIZE_OF_RTS_CMD_AND_PADDING(tsctPadding)) { TotalPacketSize -= SIZE_OF_RTS_CMD_AND_PADDING(tsctPadding); UseEmpty = FALSE; } else { TotalPacketSize -= SIZE_OF_RTS_CMD_AND_PADDING(tsctEmpty); UseEmpty = TRUE; } RTS = GetRTSPacketFromSendContext(SendContext); RTS->Flags = RTS_FLAG_PING; RTS->NumberOfSettingCommands = 1; CurrentCommand = RTS->Cmd; if (UseEmpty) { // set empty command CurrentCommand->CommandType = tsctEmpty; } else { // set padding command CurrentCommand->CommandType = tsctPadding; CurrentCommand->u.ConformanceCount = TotalPacketSize; CurrentCommand = SkipCommand(CurrentCommand, tsctPadding); // clean out the padding bytes RpcpMemorySet(CurrentCommand, 0, TotalPacketSize); } } return SendContext; } RPC_STATUS ParseAndFreePingPacket ( IN BYTE *Packet, IN ULONG PacketLength ) /*++ Routine Description: Parses and frees a ping packet. N.B.: UntrustedIsPingPacket must have already been called and returned non-zero for this function to be used. Arguments: Packet - the packet to be validated. PacketLength - the length of the packet. Return Value: RPC_S_OK for success RPC_S_PROTOCOL_ERROR for garbled packet --*/ { rpcconn_tunnel_settings *RTS = (rpcconn_tunnel_settings *)Packet; RPC_STATUS RpcStatus; if (RTS->NumberOfSettingCommands != 0) goto AbortAndExit; if (RTS->Flags != RTS_FLAG_PING) goto AbortAndExit; RpcStatus = RPC_S_OK; goto CleanupAndExit; AbortAndExit: RpcStatus = RPC_S_PROTOCOL_ERROR; CleanupAndExit: RpcFreeBuffer(Packet); return RpcStatus; } ULONG GetD1_A1TotalLength ( void ) /*++ Routine Description: Calculates the length of a D1/A1 RTS packet Arguments: Return Value: The length of the D1/A1 RTS packet. --*/ { return (BaseRTSSizeAndPadding + BaseRTSCommandSize * 4 + SIZE_OF_RTS_CMD_AND_PADDING(tsctVersion) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctReceiveWindowSize) ); } HTTP2SendContext *AllocateAndInitializeEmptyRTS ( void ) /*++ Routine Description: Allocates and initializes an empty RTS packet Arguments: Return Value: The allocated send context or NULL for out-of-memory --*/ { HTTP2SendContext *SendContext; TunnelSettingsCommand *CurrentCommand; rpcconn_tunnel_settings *RTS; SendContext = AllocateAndInitializeRTSPacket( BaseRTSCommandSize * 1 ); if (SendContext) { RTS = GetRTSPacketFromSendContext(SendContext); RTS->Flags = 0; RTS->NumberOfSettingCommands = 1; CurrentCommand = RTS->Cmd; // set empty command CurrentCommand->CommandType = tsctEmpty; } return SendContext; } RPC_STATUS ParseEmptyRTS ( IN BYTE *Packet, IN ULONG PacketLength ) /*++ Routine Description: Parses an empty RTS packet Arguments: Packet - the packet received. PacketLength - the length of the packet Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { ULONG MemorySize; rpcconn_tunnel_settings *RTS = (rpcconn_tunnel_settings *)Packet; BYTE *CurrentPosition; TunnelSettingsCommand *CurrentCommand; RPC_STATUS RpcStatus; MemorySize = BaseRTSSizeAndPadding + BaseRTSCommandSize * 1 ; if (PacketLength < MemorySize) goto AbortAndExit; CurrentPosition = ValidateRTSPacketCommon(Packet, PacketLength); if (CurrentPosition == NULL) goto AbortAndExit; if (RTS->NumberOfSettingCommands != 1) goto AbortAndExit; if (RTS->Flags != 0) goto AbortAndExit; CurrentCommand = (TunnelSettingsCommand *)CurrentPosition; // verify empty if (CurrentCommand->CommandType != tsctEmpty) goto AbortAndExit; RpcStatus = RPC_S_OK; goto CleanupAndExit; AbortAndExit: RpcStatus = RPC_S_PROTOCOL_ERROR; CleanupAndExit: return RpcStatus; } RPC_STATUS ParseAndFreeEmptyRTS ( IN BYTE *Packet, IN ULONG PacketLength ) /*++ Routine Description: Parses and frees an empty RTS packet Arguments: Packet - the packet received. PacketLength - the length of the packet Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { RPC_STATUS RpcStatus; RpcStatus = ParseEmptyRTS(Packet, PacketLength ); RpcFreeBuffer(Packet); return RpcStatus; } HTTP2SendContext *AllocateAndInitializeEmptyRTSWithDestination ( IN ForwardDestinations Destination ) /*++ Routine Description: Allocates and initializes an empty RTS packet Arguments: Destination - where to forward this to. Return Value: The allocated send context or NULL for out-of-memory --*/ { HTTP2SendContext *SendContext; TunnelSettingsCommand *CurrentCommand; rpcconn_tunnel_settings *RTS; SendContext = AllocateAndInitializeRTSPacket( BaseRTSCommandSize * 1 + SIZE_OF_RTS_CMD_AND_PADDING(tsctDestination) ); if (SendContext) { RTS = GetRTSPacketFromSendContext(SendContext); RTS->Flags = 0; RTS->NumberOfSettingCommands = 1; CurrentCommand = RTS->Cmd; // set destination CurrentCommand->CommandType = tsctDestination; CurrentCommand->u.Destination = Destination; } return SendContext; } RPC_STATUS ParseEmptyRTSWithDestination ( IN BYTE *Packet, IN ULONG PacketLength, IN ForwardDestinations ExpectedDestination ) /*++ Routine Description: Parses an empty RTS packet with destination Arguments: Packet - the packet received. PacketLength - the length of the packet ExpectedDestination - the destination code for this location (client) Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { ULONG MemorySize; rpcconn_tunnel_settings *RTS = (rpcconn_tunnel_settings *)Packet; BYTE *CurrentPosition; TunnelSettingsCommand *CurrentCommand; RPC_STATUS RpcStatus; MemorySize = BaseRTSSizeAndPadding + BaseRTSCommandSize * 1 + SIZE_OF_RTS_CMD_AND_PADDING(tsctDestination) ; if (PacketLength < MemorySize) goto AbortAndExit; CurrentPosition = ValidateRTSPacketCommon(Packet, PacketLength); if (CurrentPosition == NULL) goto AbortAndExit; if (RTS->NumberOfSettingCommands != 1) goto AbortAndExit; if (RTS->Flags != 0) goto AbortAndExit; CurrentCommand = (TunnelSettingsCommand *)CurrentPosition; // verify destination if (CurrentCommand->CommandType != tsctDestination) goto AbortAndExit; if (ExpectedDestination != CurrentCommand->u.Destination) goto AbortAndExit; RpcStatus = RPC_S_OK; goto CleanupAndExit; AbortAndExit: RpcStatus = RPC_S_PROTOCOL_ERROR; CleanupAndExit: return RpcStatus; } RPC_STATUS ParseAndFreeEmptyRTSWithDestination ( IN BYTE *Packet, IN ULONG PacketLength, IN ForwardDestinations ExpectedDestination ) /*++ Routine Description: Parses and frees an empty RTS packet with destination Arguments: Packet - the packet received. PacketLength - the length of the packet ExpectedDestination - the destination code for this location (client) Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { RPC_STATUS RpcStatus; RpcStatus = ParseEmptyRTSWithDestination (Packet, PacketLength, ExpectedDestination ); RpcFreeBuffer(Packet); return RpcStatus; } HTTP2SendContext *AllocateAndInitializeD1_A1 ( IN ULONG ProtocolVersion, IN HTTP2Cookie *ConnectionCookie, IN HTTP2Cookie *ChannelCookie, IN ULONG ClientReceiveWindow ) /*++ Routine Description: Allocates and initializes a D1/A1 RTS packet Arguments: ProtocolVersion - the version of the HTTP tunnelling protocol ConnectionCookie - the connection cookie ChannelCookie - the channel cookie ClientReceiveWindow - the client receive window Return Value: The allocated send context or NULL for out-of-memory --*/ { HTTP2SendContext *SendContext; TunnelSettingsCommand *CurrentCommand; rpcconn_tunnel_settings *RTS; SendContext = AllocateAndInitializeRTSPacket( BaseRTSCommandSize * 4 + SIZE_OF_RTS_CMD_AND_PADDING(tsctVersion) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctReceiveWindowSize) ); if (SendContext) { RTS = GetRTSPacketFromSendContext(SendContext); RTS->Flags = 0; RTS->NumberOfSettingCommands = 4; CurrentCommand = RTS->Cmd; // set version CurrentCommand->CommandType = tsctVersion; CurrentCommand->u.Version = ProtocolVersion; CurrentCommand = SkipCommand(CurrentCommand, tsctVersion); // set connection cookie CurrentCommand->CommandType = tsctCookie; RpcpMemoryCopy(CurrentCommand->u.Cookie.Cookie, ConnectionCookie->GetCookie(), COOKIE_SIZE_IN_BYTES); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // set channel cookie CurrentCommand->CommandType = tsctCookie; RpcpMemoryCopy(CurrentCommand->u.Cookie.Cookie, ChannelCookie->GetCookie(), COOKIE_SIZE_IN_BYTES); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // set client receive window CurrentCommand->CommandType = tsctReceiveWindowSize; CurrentCommand->u.ReceiveWindowSize = ClientReceiveWindow; } return SendContext; } RPC_STATUS ParseAndFreeD1_A1 ( IN BYTE *Packet, IN ULONG PacketLength, OUT ULONG *ProtocolVersion, OUT HTTP2Cookie *ConnectionCookie, OUT HTTP2Cookie *ChannelCookie, OUT ULONG *ClientReceiveWindow ) /*++ Routine Description: Parses and frees a D1/A1 RTS packet Arguments: Packet - the packet received. PacketLength - the length of the packet ProtocolVersion - the version of the HTTP tunnelling protocol ConnectionCookie - the connection cookie ChannelCookie - the channel cookie ClientReceiveWindow - the client receive window Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { ULONG MemorySize; rpcconn_tunnel_settings *RTS = (rpcconn_tunnel_settings *)Packet; BYTE *CurrentPosition; TunnelSettingsCommand *CurrentCommand; RPC_STATUS RpcStatus; MemorySize = BaseRTSSizeAndPadding + BaseRTSCommandSize * 4 + SIZE_OF_RTS_CMD_AND_PADDING(tsctVersion) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctReceiveWindowSize); if (PacketLength < MemorySize) goto AbortAndExit; CurrentPosition = ValidateRTSPacketCommon(Packet, PacketLength); if (CurrentPosition == NULL) goto AbortAndExit; if (RTS->NumberOfSettingCommands != 4) goto AbortAndExit; if (RTS->Flags != 0) goto AbortAndExit; CurrentCommand = (TunnelSettingsCommand *)CurrentPosition; // get version if (CurrentCommand->CommandType != tsctVersion) goto AbortAndExit; *ProtocolVersion = CurrentCommand->u.Version; CurrentCommand = SkipCommand(CurrentCommand, tsctVersion); // get connection cookie if (CurrentCommand->CommandType != tsctCookie) goto AbortAndExit; ConnectionCookie->SetCookie((BYTE *)CurrentCommand->u.Cookie.Cookie); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // get channel cookie if (CurrentCommand->CommandType != tsctCookie) goto AbortAndExit; ChannelCookie->SetCookie((BYTE *)CurrentCommand->u.Cookie.Cookie); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // get client receive window if (CurrentCommand->CommandType != tsctReceiveWindowSize) goto AbortAndExit; *ClientReceiveWindow = CurrentCommand->u.ReceiveWindowSize; RpcStatus = RPC_S_OK; goto CleanupAndExit; AbortAndExit: RpcStatus = RPC_S_PROTOCOL_ERROR; CleanupAndExit: RpcFreeBuffer(Packet); return RpcStatus; } HTTP2SendContext *AllocateAndInitializeD1_A2 ( IN ULONG ProtocolVersion, IN HTTP2Cookie *ConnectionCookie, IN HTTP2Cookie *ChannelCookie, IN ULONG ChannelLifetime, IN ULONG ProxyReceiveWindow ) /*++ Routine Description: Allocates and initializes a D1/A2 RTS packet Arguments: ProtocolVersion - the version of the HTTP tunnelling protocol ConnectionCookie - the connection cookie ChannelCookie - the channel cookie ChannelLifetime - the lifetime of the channel ProxyReceiveWindow - the proxy receive window Return Value: The allocated send context or NULL for out-of-memory --*/ { HTTP2SendContext *SendContext; TunnelSettingsCommand *CurrentCommand; rpcconn_tunnel_settings *RTS; SendContext = AllocateAndInitializeRTSPacket( BaseRTSCommandSize * 5 + SIZE_OF_RTS_CMD_AND_PADDING(tsctVersion) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctChannelLifetime) + SIZE_OF_RTS_CMD_AND_PADDING(tsctReceiveWindowSize) ); if (SendContext) { RTS = GetRTSPacketFromSendContext(SendContext); RTS->Flags = RTS_FLAG_OUT_CHANNEL; RTS->NumberOfSettingCommands = 5; CurrentCommand = RTS->Cmd; // set version CurrentCommand->CommandType = tsctVersion; CurrentCommand->u.Version = ProtocolVersion; CurrentCommand = SkipCommand(CurrentCommand, tsctVersion); // set connection cookie CurrentCommand->CommandType = tsctCookie; RpcpMemoryCopy(CurrentCommand->u.Cookie.Cookie, ConnectionCookie->GetCookie(), COOKIE_SIZE_IN_BYTES); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // set channel cookie CurrentCommand->CommandType = tsctCookie; RpcpMemoryCopy(CurrentCommand->u.Cookie.Cookie, ChannelCookie->GetCookie(), COOKIE_SIZE_IN_BYTES); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // set channel lifetime CurrentCommand->CommandType = tsctChannelLifetime; CurrentCommand->u.ChannelLifetime = ChannelLifetime; CurrentCommand = SkipCommand(CurrentCommand, tsctChannelLifetime); // set proxy receive window CurrentCommand->CommandType = tsctReceiveWindowSize; CurrentCommand->u.ReceiveWindowSize = ProxyReceiveWindow; } return SendContext; } RPC_STATUS ParseD1_A2 ( IN BYTE *Packet, IN ULONG PacketLength, OUT ULONG *ProtocolVersion, OUT HTTP2Cookie *ConnectionCookie, OUT HTTP2Cookie *ChannelCookie, OUT ULONG *ChannelLifetime, OUT ULONG *ProxyReceiveWindow ) /*++ Routine Description: Parses D1/A2 RTS packet Arguments: Packet - the packet received. PacketLength - the length of the packet ProtocolVersion - the version of the HTTP tunnelling protocol ConnectionCookie - the connection cookie ChannelCookie - the channel cookie ChannelLifetime - the lifetime of the channel ProxyReceiveWindow - the proxy receive window Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { ULONG MemorySize; rpcconn_tunnel_settings *RTS = (rpcconn_tunnel_settings *)Packet; BYTE *CurrentPosition; TunnelSettingsCommand *CurrentCommand; RPC_STATUS RpcStatus; MemorySize = BaseRTSSizeAndPadding + BaseRTSCommandSize * 5 + SIZE_OF_RTS_CMD_AND_PADDING(tsctVersion) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctChannelLifetime) + SIZE_OF_RTS_CMD_AND_PADDING(tsctReceiveWindowSize); if (PacketLength < MemorySize) goto AbortAndExit; CurrentPosition = ValidateRTSPacketCommon(Packet, PacketLength); if (CurrentPosition == NULL) goto AbortAndExit; if (RTS->NumberOfSettingCommands != 5) goto AbortAndExit; if (RTS->Flags != RTS_FLAG_OUT_CHANNEL) goto AbortAndExit; CurrentCommand = (TunnelSettingsCommand *)CurrentPosition; // get version if (CurrentCommand->CommandType != tsctVersion) goto AbortAndExit; *ProtocolVersion = CurrentCommand->u.Version; CurrentCommand = SkipCommand(CurrentCommand, tsctVersion); // get connection cookie if (CurrentCommand->CommandType != tsctCookie) goto AbortAndExit; ConnectionCookie->SetCookie((BYTE *)CurrentCommand->u.Cookie.Cookie); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // get channel cookie if (CurrentCommand->CommandType != tsctCookie) goto AbortAndExit; ChannelCookie->SetCookie((BYTE *)CurrentCommand->u.Cookie.Cookie); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // get channel lifetime if (CurrentCommand->CommandType != tsctChannelLifetime) goto AbortAndExit; *ChannelLifetime = CurrentCommand->u.ChannelLifetime; CurrentCommand = SkipCommand(CurrentCommand, tsctChannelLifetime); // get proxy receive window if (CurrentCommand->CommandType != tsctReceiveWindowSize) goto AbortAndExit; *ProxyReceiveWindow = CurrentCommand->u.ReceiveWindowSize; RpcStatus = RPC_S_OK; goto CleanupAndExit; AbortAndExit: RpcStatus = RPC_S_PROTOCOL_ERROR; CleanupAndExit: return RpcStatus; } HTTP2SendContext *AllocateAndInitializeD1_B1 ( IN ULONG ProtocolVersion, IN HTTP2Cookie *ConnectionCookie, IN HTTP2Cookie *ChannelCookie, IN ULONG ChannelLifetime, IN ULONG ClientKeepAliveInterval, IN HTTP2Cookie *AssociationGroupId ) /*++ Routine Description: Allocates and initializes a D1/B1 RTS packet Arguments: ProtocolVersion - the version of the HTTP tunnelling protocol ConnectionCookie - the connection cookie ChannelCookie - the channel cookie ChannelLifetime - the lifetime of the channel ClientKeepAliveInterval - the client receive window AssociationGroupId - the association group id Return Value: The allocated send context or NULL for out-of-memory --*/ { HTTP2SendContext *SendContext; TunnelSettingsCommand *CurrentCommand; rpcconn_tunnel_settings *RTS; SendContext = AllocateAndInitializeRTSPacket( BaseRTSCommandSize * 6 + SIZE_OF_RTS_CMD_AND_PADDING(tsctVersion) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctChannelLifetime) + SIZE_OF_RTS_CMD_AND_PADDING(tsctClientKeepalive) + SIZE_OF_RTS_CMD_AND_PADDING(tsctAssociationGroupId) ); if (SendContext) { RTS = GetRTSPacketFromSendContext(SendContext); RTS->Flags = 0; RTS->NumberOfSettingCommands = 6; CurrentCommand = RTS->Cmd; // set version CurrentCommand->CommandType = tsctVersion; CurrentCommand->u.Version = ProtocolVersion; CurrentCommand = SkipCommand(CurrentCommand, tsctVersion); // set connection cookie CurrentCommand->CommandType = tsctCookie; RpcpMemoryCopy(CurrentCommand->u.Cookie.Cookie, ConnectionCookie->GetCookie(), COOKIE_SIZE_IN_BYTES); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // set channel cookie CurrentCommand->CommandType = tsctCookie; RpcpMemoryCopy(CurrentCommand->u.Cookie.Cookie, ChannelCookie->GetCookie(), COOKIE_SIZE_IN_BYTES); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // set channel lifetime CurrentCommand->CommandType = tsctChannelLifetime; CurrentCommand->u.ChannelLifetime = ChannelLifetime; CurrentCommand = SkipCommand(CurrentCommand, tsctChannelLifetime); // set client receive window CurrentCommand->CommandType = tsctClientKeepalive; CurrentCommand->u.ClientKeepalive = ClientKeepAliveInterval; CurrentCommand = SkipCommand(CurrentCommand, tsctClientKeepalive); // set association group id CurrentCommand->CommandType = tsctAssociationGroupId; RpcpMemoryCopy(CurrentCommand->u.AssociationGroupId.Cookie, AssociationGroupId->GetCookie(), COOKIE_SIZE_IN_BYTES); } return SendContext; } RPC_STATUS ParseAndFreeD1_B1 ( IN BYTE *Packet, IN ULONG PacketLength, OUT ULONG *ProtocolVersion, OUT HTTP2Cookie *ConnectionCookie, OUT HTTP2Cookie *ChannelCookie, OUT ULONG *ChannelLifetime, OUT HTTP2Cookie *AssociationGroupId, OUT ULONG *ClientKeepAliveInterval ) /*++ Routine Description: Parses and frees a D1/B1 RTS packet Arguments: Packet - the packet received. PacketLength - the length of the packet ProtocolVersion - on output, the version of the HTTP tunnelling protocol Success only. ConnectionCookie - on output, the connection cookie. Success only. ChannelCookie - on output, the channel cookie. Success only. ChannelLifetime - on output, the lifetime of the channel. Success only. AssociationGroupId - on output, the client association group id. Success only. ClientKeepAliveInterval - on output, the client receive window. Success only. Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { ULONG MemorySize; rpcconn_tunnel_settings *RTS = (rpcconn_tunnel_settings *)Packet; BYTE *CurrentPosition; TunnelSettingsCommand *CurrentCommand; RPC_STATUS RpcStatus; MemorySize = BaseRTSSizeAndPadding + BaseRTSCommandSize * 6 + SIZE_OF_RTS_CMD_AND_PADDING(tsctVersion) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctChannelLifetime) + SIZE_OF_RTS_CMD_AND_PADDING(tsctClientKeepalive) + SIZE_OF_RTS_CMD_AND_PADDING(tsctAssociationGroupId) ; if (PacketLength < MemorySize) goto AbortAndExit; CurrentPosition = ValidateRTSPacketCommon(Packet, PacketLength); if (CurrentPosition == NULL) goto AbortAndExit; if (RTS->NumberOfSettingCommands != 6) goto AbortAndExit; if (RTS->Flags != 0) goto AbortAndExit; CurrentCommand = (TunnelSettingsCommand *)CurrentPosition; // get version if (CurrentCommand->CommandType != tsctVersion) goto AbortAndExit; *ProtocolVersion = CurrentCommand->u.Version; CurrentCommand = SkipCommand(CurrentCommand, tsctVersion); // get connection cookie if (CurrentCommand->CommandType != tsctCookie) goto AbortAndExit; ConnectionCookie->SetCookie((BYTE *)CurrentCommand->u.Cookie.Cookie); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // get channel cookie if (CurrentCommand->CommandType != tsctCookie) goto AbortAndExit; ChannelCookie->SetCookie((BYTE *)CurrentCommand->u.Cookie.Cookie); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // get channel lifetime if (CurrentCommand->CommandType != tsctChannelLifetime) goto AbortAndExit; *ChannelLifetime = CurrentCommand->u.ChannelLifetime; CurrentCommand = SkipCommand(CurrentCommand, tsctChannelLifetime); // get client keep alive if (CurrentCommand->CommandType != tsctClientKeepalive) goto AbortAndExit; *ClientKeepAliveInterval = CurrentCommand->u.ClientKeepalive; CurrentCommand = SkipCommand(CurrentCommand, tsctClientKeepalive); // get association group id if (CurrentCommand->CommandType != tsctAssociationGroupId) goto AbortAndExit; AssociationGroupId->SetCookie((BYTE *)CurrentCommand->u.AssociationGroupId.Cookie); RpcStatus = RPC_S_OK; goto CleanupAndExit; AbortAndExit: RpcStatus = RPC_S_PROTOCOL_ERROR; CleanupAndExit: RpcFreeBuffer(Packet); return RpcStatus; } HTTP2SendContext *AllocateAndInitializeD1_B2 ( IN ULONG ProtocolVersion, IN HTTP2Cookie *ConnectionCookie, IN HTTP2Cookie *ChannelCookie, IN ULONG ReceiveWindowSize, IN ULONG ConnectionTimeout, IN HTTP2Cookie *AssociationGroupId, IN ChannelSettingClientAddress *ClientAddress ) /*++ Routine Description: Allocates and initializes a D1/B2 RTS packet Arguments: ProtocolVersion - the version of the HTTP tunnelling protocol ConnectionCookie - the connection cookie ChannelCookie - the channel cookie ReceiveWindowSize - the receive window size of the in proxy ConnectionTimeout - connection timeout of the in proxy ClientAddress - client address of the client as seen by the in proxy AssociationGroupId - the association group id Return Value: The allocated send context or NULL for out-of-memory --*/ { HTTP2SendContext *SendContext; TunnelSettingsCommand *CurrentCommand; rpcconn_tunnel_settings *RTS; SendContext = AllocateAndInitializeRTSPacket( BaseRTSCommandSize * 7 + SIZE_OF_RTS_CMD_AND_PADDING(tsctVersion) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctReceiveWindowSize) + SIZE_OF_RTS_CMD_AND_PADDING(tsctConnectionTimeout) + SIZE_OF_RTS_CMD_AND_PADDING(tsctAssociationGroupId) + ClientAddressSizes[ClientAddress->AddressType] ); if (SendContext) { RTS = GetRTSPacketFromSendContext(SendContext); RTS->Flags = RTS_FLAG_IN_CHANNEL; RTS->NumberOfSettingCommands = 7; CurrentCommand = RTS->Cmd; // set version CurrentCommand->CommandType = tsctVersion; CurrentCommand->u.Version = ProtocolVersion; CurrentCommand = SkipCommand(CurrentCommand, tsctVersion); // set connection cookie CurrentCommand->CommandType = tsctCookie; RpcpMemoryCopy(CurrentCommand->u.Cookie.Cookie, ConnectionCookie->GetCookie(), COOKIE_SIZE_IN_BYTES); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // set channel cookie CurrentCommand->CommandType = tsctCookie; RpcpMemoryCopy(CurrentCommand->u.Cookie.Cookie, ChannelCookie->GetCookie(), COOKIE_SIZE_IN_BYTES); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // set receive window size CurrentCommand->CommandType = tsctReceiveWindowSize; CurrentCommand->u.ReceiveWindowSize = ReceiveWindowSize; CurrentCommand = SkipCommand(CurrentCommand, tsctReceiveWindowSize); // set connection timeout CurrentCommand->CommandType = tsctConnectionTimeout; CurrentCommand->u.ConnectionTimeout = ConnectionTimeout; CurrentCommand = SkipCommand(CurrentCommand, tsctConnectionTimeout); // set association group id CurrentCommand->CommandType = tsctAssociationGroupId; RpcpMemoryCopy(CurrentCommand->u.AssociationGroupId.Cookie, AssociationGroupId->GetCookie(), COOKIE_SIZE_IN_BYTES); CurrentCommand = SkipCommand(CurrentCommand, tsctAssociationGroupId); // set client address. CurrentCommand->CommandType = tsctClientAddress; CurrentCommand->u.ClientAddress.AddressType = ClientAddress->AddressType; RpcpMemorySet(&CurrentCommand->u, 0, ClientAddressSizes[ClientAddress->AddressType]); if (ClientAddress->AddressType == catIPv4) { RpcpCopyIPv4Address((SOCKADDR_IN *)ClientAddress->u.IPv4Address, (SOCKADDR_IN *) CurrentCommand->u.ClientAddress.u.IPv4Address); } else { RpcpCopyIPv6Address((SOCKADDR_IN6 *)ClientAddress->u.IPv4Address, (SOCKADDR_IN6 *) CurrentCommand->u.ClientAddress.u.IPv4Address); } } return SendContext; } RPC_STATUS ParseD1_B2 ( IN BYTE *Packet, IN ULONG PacketLength, OUT ULONG *ProtocolVersion, OUT HTTP2Cookie *ConnectionCookie, OUT HTTP2Cookie *ChannelCookie, OUT ULONG *ReceiveWindowSize, OUT ULONG *ConnectionTimeout, OUT HTTP2Cookie *AssociationGroupId, OUT ChannelSettingClientAddress *ClientAddress ) /*++ Routine Description: Parses a D1/B2 RTS packet Arguments: Packet - the packet received. PacketLength - the length of the packet ProtocolVersion - the version of the HTTP tunnelling protocol ConnectionCookie - the connection cookie ChannelCookie - the channel cookie ReceiveWindowSize - the receive window size of the in proxy ConnectionTimeout - connection timeout of the in proxy AssociationGroupId - the association group id ClientAddress - client address of the client as seen by the in proxy Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { ULONG MemorySize; rpcconn_tunnel_settings *RTS = (rpcconn_tunnel_settings *)Packet; BYTE *CurrentPosition; TunnelSettingsCommand *CurrentCommand; RPC_STATUS RpcStatus; MemorySize = BaseRTSSizeAndPadding + BaseRTSCommandSize * 7 + SIZE_OF_RTS_CMD_AND_PADDING(tsctVersion) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctReceiveWindowSize) + SIZE_OF_RTS_CMD_AND_PADDING(tsctConnectionTimeout) + FIELD_OFFSET(ChannelSettingClientAddress, u) // check for enough space to read the // address type ; if (PacketLength < MemorySize) goto AbortAndExit; CurrentPosition = ValidateRTSPacketCommon(Packet, PacketLength); if (CurrentPosition == NULL) goto AbortAndExit; if (RTS->NumberOfSettingCommands != 7) goto AbortAndExit; if (RTS->Flags != RTS_FLAG_IN_CHANNEL) goto AbortAndExit; CurrentCommand = (TunnelSettingsCommand *)CurrentPosition; // get version if (CurrentCommand->CommandType != tsctVersion) goto AbortAndExit; *ProtocolVersion = CurrentCommand->u.Version; CurrentCommand = SkipCommand(CurrentCommand, tsctVersion); // get connection cookie if (CurrentCommand->CommandType != tsctCookie) goto AbortAndExit; ConnectionCookie->SetCookie((BYTE *)CurrentCommand->u.Cookie.Cookie); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // get channel cookie if (CurrentCommand->CommandType != tsctCookie) goto AbortAndExit; ChannelCookie->SetCookie((BYTE *)CurrentCommand->u.Cookie.Cookie); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // get receive window size if (CurrentCommand->CommandType != tsctReceiveWindowSize) goto AbortAndExit; *ReceiveWindowSize = CurrentCommand->u.ReceiveWindowSize; CurrentCommand = SkipCommand(CurrentCommand, tsctReceiveWindowSize); // get connection timeout if (CurrentCommand->CommandType != tsctConnectionTimeout) goto AbortAndExit; *ConnectionTimeout = CurrentCommand->u.ConnectionTimeout; CurrentCommand = SkipCommand(CurrentCommand, tsctConnectionTimeout); if (CurrentCommand->CommandType != tsctAssociationGroupId) goto AbortAndExit; AssociationGroupId->SetCookie((BYTE *)CurrentCommand->u.AssociationGroupId.Cookie); CurrentCommand = SkipCommand(CurrentCommand, tsctAssociationGroupId); // get client address. Note that we have checked the length only up to // the address type. Everything after that must be validated separately if (CurrentCommand->CommandType != tsctClientAddress) goto AbortAndExit; ClientAddress->AddressType = CurrentCommand->u.ClientAddress.AddressType; // We have already calculated the size of the AddressType field. Add the // size for the body of the client address MemorySize += ClientAddressSizes[ClientAddress->AddressType] - FIELD_OFFSET(ChannelSettingClientAddress, u); if (PacketLength < MemorySize) goto AbortAndExit; if (ClientAddress->AddressType == catIPv4) { RpcpCopyIPv4Address((SOCKADDR_IN *)CurrentCommand->u.ClientAddress.u.IPv4Address, (SOCKADDR_IN *)ClientAddress->u.IPv4Address); } else { RpcpCopyIPv6Address((SOCKADDR_IN6 *)CurrentCommand->u.ClientAddress.u.IPv4Address, (SOCKADDR_IN6 *)ClientAddress->u.IPv4Address); } RpcStatus = RPC_S_OK; goto CleanupAndExit; AbortAndExit: RpcStatus = RPC_S_PROTOCOL_ERROR; CleanupAndExit: return RpcStatus; } RPC_STATUS GetFirstServerPacketType ( IN BYTE *Packet, IN ULONG PacketLength, OUT HTTP2FirstServerPacketType *PacketType ) /*++ Routine Description: Determines the type of the first server packet. Arguments: Packet - the packet received. PacketLength - the length of the packet PacketType - one of the members of the enumeration Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { rpcconn_tunnel_settings *RTS; if (PacketLength < BaseRTSSizeAndPadding) return RPC_S_PROTOCOL_ERROR; RTS = (rpcconn_tunnel_settings *)Packet; if (RTS->Flags & RTS_FLAG_OUT_CHANNEL) { if (RTS->Flags & RTS_FLAG_RECYCLE_CHANNEL) *PacketType = http2fsptD4_A4; else *PacketType = http2fsptD1_A2; return RPC_S_OK; } else if (RTS->Flags & RTS_FLAG_IN_CHANNEL) { if (RTS->Flags & RTS_FLAG_RECYCLE_CHANNEL) *PacketType = http2fsptD2_A2; else *PacketType = http2fsptD1_B2; return RPC_S_OK; } else return RPC_S_PROTOCOL_ERROR; } RPC_STATUS GetClientOpenedPacketType ( IN BYTE *Packet, IN ULONG PacketLength, OUT HTTP2ClientOpenedPacketType *PacketType ) /*++ Routine Description: Determines the type of the packet in client opened (or one of the opened states) Arguments: Packet - the packet received. PacketLength - the length of the packet PacketType - one of the members of the enumeration Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { rpcconn_tunnel_settings *RTS; if (PacketLength < BaseRTSSizeAndPadding) return RPC_S_PROTOCOL_ERROR; RTS = (rpcconn_tunnel_settings *)Packet; // here we expect D2/A4, D3/A4, D4/A2, D4/A6, D5/A6 // and D5/B3 if (RTS->Flags & RTS_FLAG_RECYCLE_CHANNEL) { *PacketType = http2coptD4_A2; } else if (RTS->Flags & RTS_FLAG_OUT_CHANNEL) { *PacketType = http2coptD4_A6; } else if (RTS->Flags & RTS_FLAG_EOF) { // D5/B3 has the EOF flag *PacketType = http2coptD5_B3; } else if (IsD4_A10(Packet, PacketLength)) { // D4/A10 is an ANCE packet. *PacketType = http2coptD4_A10; } else if (IsD5_A6(Packet, PacketLength, fdClient)) { // D5/A6 is an ANCE packet with forward destination. *PacketType = http2coptD5_A6; } else if (IsD2_A4OrD3_A4(Packet, PacketLength)) { *PacketType = http2coptD2_A4; } else { *PacketType = http2coptD3_A4; } return RPC_S_OK; } RPC_STATUS GetServerOpenedPacketType ( IN BYTE *Packet, IN ULONG PacketLength, OUT HTTP2ServerOpenedPacketType *PacketType ) /*++ Routine Description: Determines the type of the packet in server opened (or one of the opened states) Arguments: Packet - the packet received. PacketLength - the length of the packet PacketType - one of the members of the enumeration Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { rpcconn_tunnel_settings *RTS; if (PacketLength < BaseRTSSizeAndPadding) return RPC_S_PROTOCOL_ERROR; RTS = (rpcconn_tunnel_settings *)Packet; // here we expect D2/A6, D2/B1, D3/A2, D4/A8 and D5/A8 if (RTS->Flags & RTS_FLAG_OUT_CHANNEL) { // D4/A8 and D5/A8 are differentiated by state only *PacketType = http2soptD4_A8orD5_A8; } else if (IsEmptyRTS (Packet, PacketLength)) { *PacketType = http2soptD2_B1; } else { *PacketType = http2soptD2_A6orD3_A2; } return RPC_S_OK; } RPC_STATUS GetOtherCmdPacketType ( IN BYTE *Packet, IN ULONG PacketLength, OUT HTTP2OtherCmdPacketType *PacketType ) /*++ Routine Description: Determines the type of a packet containing other cmd flag Arguments: Packet - the packet received. PacketLength - the length of the packet PacketType - one of the members of the enumeration Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { rpcconn_tunnel_settings *RTS; if (PacketLength < BaseRTSSizeAndPadding) return RPC_S_PROTOCOL_ERROR; RTS = (rpcconn_tunnel_settings *)Packet; // right now we only expect KeepAliveChange *PacketType = http2ocptKeepAliveChange; return RPC_S_OK; } RPC_STATUS GetServerOutChannelOtherCmdPacketType ( IN BYTE *Packet, IN ULONG PacketLength, OUT HTTP2ServerOutChannelOtherCmdPacketType *PacketType ) /*++ Routine Description: Determines the type of a packet containing other cmd flag Arguments: Packet - the packet received. PacketLength - the length of the packet PacketType - one of the members of the enumeration Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { ULONG MemorySize; // tsctPingTrafficSentNotify is shorter than tsctFlowControlAck // This is how we differentiate them ASSERT(SIZE_OF_RTS_CMD_AND_PADDING(tsctFlowControlAck) > SIZE_OF_RTS_CMD_AND_PADDING(tsctPingTrafficSentNotify)); MemorySize = BaseRTSSizeAndPadding + BaseRTSCommandSize * 1 + SIZE_OF_RTS_CMD_AND_PADDING(tsctFlowControlAck) ; if (PacketLength < MemorySize) *PacketType = http2sococptPingTrafficSentNotify; else *PacketType = http2sococptFlowControl; return RPC_S_OK; } const char *ResponseHeaderFragment1 = "HTTP/1.1 200 Success\r\nContent-Type:application/rpc\r\nContent-Length:"; const int ResponseHeaderFragment1Length = 67; // length of "HTTP/1.1 200 Success\r\nContent-Type:application/rpc\r\nContent-Length:" const char *ResponseHeaderFragment2 = "\r\n\r\n"; const int ResponseHeaderFragment2Length = 4; // length of "\r\n\r\n" HTTP2SendContext *AllocateAndInitializeResponseHeader ( void ) /*++ Routine Description: Allocates and initializes the out channel response header. Arguments: Return Value: The allocated and initialized send context on success. NULL on failure. --*/ { ULONG MemorySize; char *Buffer; char *OriginalBuffer; HTTP2SendContext *SendContext; MemorySize = ResponseHeaderFragment1Length + DefaultChannelLifetimeStringLength + ResponseHeaderFragment2Length ; Buffer = (char *)RpcAllocateBuffer(HTTPSendContextSizeAndPadding + MemorySize); if (Buffer == NULL) return NULL; OriginalBuffer = Buffer; SendContext = (HTTP2SendContext *)Buffer; Buffer += HTTPSendContextSizeAndPadding; #if DBG SendContext->ListEntryUsed = FALSE; #endif SendContext->maxWriteBuffer = MemorySize; SendContext->pWriteBuffer = (BUFFER)Buffer; SendContext->TrafficType = http2ttRaw; SendContext->u.SyncEvent = NULL; SendContext->Flags = 0; SendContext->UserData = 0; RpcpMemoryCopy(Buffer, ResponseHeaderFragment1, ResponseHeaderFragment1Length); Buffer += ResponseHeaderFragment1Length; RpcpMemoryCopy(Buffer, DefaultChannelLifetimeString, DefaultChannelLifetimeStringLength); Buffer += DefaultChannelLifetimeStringLength; RpcpMemoryCopy(Buffer, ResponseHeaderFragment2, ResponseHeaderFragment2Length); return (HTTP2SendContext *)OriginalBuffer; } HTTP2SendContext *AllocateAndInitializeD1_A3 ( IN ULONG ProxyConnectionTimeout ) /*++ Routine Description: Allocates and initializes an D1_A3 packet. Arguments: ProxyConnectionTimeout - the proxy connection timeout. Return Value: The allocated and initialized send context on success. NULL on failure. --*/ { HTTP2SendContext *SendContext; TunnelSettingsCommand *CurrentCommand; rpcconn_tunnel_settings *RTS; SendContext = AllocateAndInitializeRTSPacket( BaseRTSCommandSize * 1 + SIZE_OF_RTS_CMD_AND_PADDING(tsctReceiveWindowSize) ); if (SendContext) { RTS = GetRTSPacketFromSendContext(SendContext); RTS->NumberOfSettingCommands = 1; CurrentCommand = RTS->Cmd; // set connection timeout CurrentCommand->CommandType = tsctConnectionTimeout; CurrentCommand->u.ConnectionTimeout = ProxyConnectionTimeout; } return SendContext; } RPC_STATUS ParseAndFreeD1_A3 ( IN BYTE *Packet, IN ULONG PacketLength, OUT ULONG *ProxyConnectionTimeout ) /*++ Routine Description: Parses and frees a D1/A3 RTS packet Arguments: Packet - the packet received. PacketLength - the length of the packet ProxyConnectionTimeout - the proxy connection timeout is returned here (success only). Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { ULONG MemorySize; rpcconn_tunnel_settings *RTS = (rpcconn_tunnel_settings *)Packet; BYTE *CurrentPosition; TunnelSettingsCommand *CurrentCommand; RPC_STATUS RpcStatus; MemorySize = BaseRTSSizeAndPadding + BaseRTSCommandSize * 1 + SIZE_OF_RTS_CMD_AND_PADDING(tsctConnectionTimeout); if (PacketLength < MemorySize) goto AbortAndExit; CurrentPosition = ValidateRTSPacketCommon(Packet, PacketLength); if (CurrentPosition == NULL) goto AbortAndExit; if (RTS->NumberOfSettingCommands != 1) goto AbortAndExit; if (RTS->Flags != 0) goto AbortAndExit; CurrentCommand = (TunnelSettingsCommand *)CurrentPosition; // get connection timeout if (CurrentCommand->CommandType != tsctConnectionTimeout) goto AbortAndExit; *ProxyConnectionTimeout = CurrentCommand->u.ConnectionTimeout; RpcStatus = RPC_S_OK; goto CleanupAndExit; AbortAndExit: RpcStatus = RPC_S_PROTOCOL_ERROR; CleanupAndExit: RpcFreeBuffer(Packet); return RpcStatus; } HTTP2SendContext *AllocateAndInitializeD1_B3 ( IN ULONG ReceiveWindowSize, IN ULONG UpdatedProtocolVersion ) /*++ Routine Description: Allocates and initializes an D1_B3 packet. Arguments: ReceiveWindowSize - the server receive window size. UpdatedProtocolVersion - the updated protocol version. Return Value: The allocated and initialized send context on success. NULL on failure. --*/ { HTTP2SendContext *SendContext; TunnelSettingsCommand *CurrentCommand; rpcconn_tunnel_settings *RTS; SendContext = AllocateAndInitializeRTSPacket( BaseRTSCommandSize * 2 + SIZE_OF_RTS_CMD_AND_PADDING(tsctReceiveWindowSize) + SIZE_OF_RTS_CMD_AND_PADDING(tsctVersion) ); if (SendContext) { RTS = GetRTSPacketFromSendContext(SendContext); RTS->NumberOfSettingCommands = 2; CurrentCommand = RTS->Cmd; // set receive window CurrentCommand->CommandType = tsctReceiveWindowSize; CurrentCommand->u.ConnectionTimeout = ReceiveWindowSize; CurrentCommand = SkipCommand(CurrentCommand, tsctReceiveWindowSize); // set version CurrentCommand->CommandType = tsctVersion; CurrentCommand->u.Version = UpdatedProtocolVersion; } return SendContext; } RPC_STATUS ParseAndFreeD1_B3 ( IN BYTE *Packet, IN ULONG PacketLength, OUT ULONG *ReceiveWindowSize, OUT ULONG *UpdatedProtocolVersion ) /*++ Routine Description: Parses and frees a D1/A3 RTS packet Arguments: Packet - the packet received. PacketLength - the length of the packet ReceiveWindowSize - the receive window size is returned here (success only). UpdatedProtocolVersion - the updated protocol version from the server (success only) Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { ULONG MemorySize; rpcconn_tunnel_settings *RTS = (rpcconn_tunnel_settings *)Packet; BYTE *CurrentPosition; TunnelSettingsCommand *CurrentCommand; RPC_STATUS RpcStatus; MemorySize = BaseRTSSizeAndPadding + BaseRTSCommandSize * 2 + SIZE_OF_RTS_CMD_AND_PADDING(tsctReceiveWindowSize) + SIZE_OF_RTS_CMD_AND_PADDING(tsctVersion) ; if (PacketLength < MemorySize) goto AbortAndExit; CurrentPosition = ValidateRTSPacketCommon(Packet, PacketLength); if (CurrentPosition == NULL) goto AbortAndExit; if (RTS->NumberOfSettingCommands != 2) goto AbortAndExit; if (RTS->Flags != 0) goto AbortAndExit; CurrentCommand = (TunnelSettingsCommand *)CurrentPosition; // get receive window if (CurrentCommand->CommandType != tsctReceiveWindowSize) goto AbortAndExit; *ReceiveWindowSize = CurrentCommand->u.ConnectionTimeout; CurrentCommand = SkipCommand(CurrentCommand, tsctReceiveWindowSize); // get version if (CurrentCommand->CommandType != tsctVersion) goto AbortAndExit; *UpdatedProtocolVersion = CurrentCommand->u.Version; RpcStatus = RPC_S_OK; goto CleanupAndExit; AbortAndExit: RpcStatus = RPC_S_PROTOCOL_ERROR; CleanupAndExit: RpcFreeBuffer(Packet); return RpcStatus; } HTTP2SendContext *AllocateAndInitializeD1_C1 ( IN ULONG UpdatedProtocolVersion, IN ULONG InProxyReceiveWindowSize, IN ULONG InProxyConnectionTimeout ) /*++ Routine Description: Allocates and initializes a D1_C1 packet. Arguments: UpdatedProtocolVersion - the updated protocol version. InProxyReceiveWindowSize - the in proxy receive window size. InProxyConnectionTimeout - the in proxy connection timeout Return Value: The allocated and initialized send context on success. NULL on failure. --*/ { HTTP2SendContext *SendContext; TunnelSettingsCommand *CurrentCommand; rpcconn_tunnel_settings *RTS; SendContext = AllocateAndInitializeRTSPacket( BaseRTSCommandSize * 3 + SIZE_OF_RTS_CMD_AND_PADDING(tsctVersion) + SIZE_OF_RTS_CMD_AND_PADDING(tsctReceiveWindowSize) + SIZE_OF_RTS_CMD_AND_PADDING(tsctConnectionTimeout) ); if (SendContext) { RTS = GetRTSPacketFromSendContext(SendContext); RTS->NumberOfSettingCommands = 3; CurrentCommand = RTS->Cmd; // set version CurrentCommand->CommandType = tsctVersion; CurrentCommand->u.Version = UpdatedProtocolVersion; CurrentCommand = SkipCommand(CurrentCommand, tsctVersion); // set receive window CurrentCommand->CommandType = tsctReceiveWindowSize; CurrentCommand->u.ReceiveWindowSize = InProxyReceiveWindowSize; CurrentCommand = SkipCommand(CurrentCommand, tsctReceiveWindowSize); // set connection timeout CurrentCommand->CommandType = tsctConnectionTimeout; CurrentCommand->u.ConnectionTimeout = InProxyConnectionTimeout; } return SendContext; } RPC_STATUS ParseD1_C1 ( IN BYTE *Packet, IN ULONG PacketLength, OUT ULONG *UpdatedProtocolVersion, OUT ULONG *InProxyReceiveWindowSize, OUT ULONG *InProxyConnectionTimeout ) /*++ Routine Description: Parses a D1_C1 packet. Arguments: Packet - the packet received. PacketLength - the length of the packet UpdatedProtocolVersion - the updated protocol version. InProxyReceiveWindowSize - the in proxy receive window size. InProxyConnectionTimeout - the in proxy connection timeout Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { ULONG MemorySize; rpcconn_tunnel_settings *RTS = (rpcconn_tunnel_settings *)Packet; BYTE *CurrentPosition; TunnelSettingsCommand *CurrentCommand; RPC_STATUS RpcStatus; MemorySize = BaseRTSSizeAndPadding + BaseRTSCommandSize * 3 + SIZE_OF_RTS_CMD_AND_PADDING(tsctVersion) + SIZE_OF_RTS_CMD_AND_PADDING(tsctReceiveWindowSize) + SIZE_OF_RTS_CMD_AND_PADDING(tsctConnectionTimeout) ; if (PacketLength < MemorySize) goto AbortAndExit; CurrentPosition = ValidateRTSPacketCommon(Packet, PacketLength); if (CurrentPosition == NULL) goto AbortAndExit; if (RTS->NumberOfSettingCommands != 3) goto AbortAndExit; if (RTS->Flags != 0) goto AbortAndExit; CurrentCommand = (TunnelSettingsCommand *)CurrentPosition; // get version if (CurrentCommand->CommandType != tsctVersion) goto AbortAndExit; *UpdatedProtocolVersion = CurrentCommand->u.Version; CurrentCommand = SkipCommand(CurrentCommand, tsctVersion); // get receive window if (CurrentCommand->CommandType != tsctReceiveWindowSize) goto AbortAndExit; *InProxyReceiveWindowSize = CurrentCommand->u.ReceiveWindowSize; CurrentCommand = SkipCommand(CurrentCommand, tsctReceiveWindowSize); // get connection timeout if (CurrentCommand->CommandType != tsctConnectionTimeout) goto AbortAndExit; *InProxyConnectionTimeout = CurrentCommand->u.ConnectionTimeout; RpcStatus = RPC_S_OK; goto CleanupAndExit; AbortAndExit: RpcStatus = RPC_S_PROTOCOL_ERROR; CleanupAndExit: return RpcStatus; } RPC_STATUS ParseAndFreeD1_C2 ( IN BYTE *Packet, IN ULONG PacketLength, OUT ULONG *UpdatedProtocolVersion, OUT ULONG *InProxyReceiveWindowSize, OUT ULONG *InProxyConnectionTimeout ) /*++ Routine Description: Parses and frees a D1_C2 packet. Arguments: Packet - the packet received. PacketLength - the length of the packet UpdatedProtocolVersion - the updated protocol version. InProxyReceiveWindowSize - the in proxy receive window size. InProxyConnectionTimeout - the in proxy connection timeout Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { RPC_STATUS RpcStatus; // D1/C1 has the same format as D1/C2 RpcStatus = ParseD1_C1(Packet, PacketLength, UpdatedProtocolVersion, InProxyReceiveWindowSize, InProxyConnectionTimeout ); RpcFreeBuffer(Packet); return RpcStatus; } HTTP2SendContext *AllocateAndInitializeD2_A1 ( IN ULONG ProtocolVersion, IN HTTP2Cookie *ConnectionCookie, IN HTTP2Cookie *OldChannelCookie, IN HTTP2Cookie *NewChannelCookie ) /*++ Routine Description: Allocates and initializes a D2/A1 RTS packet Arguments: ProtocolVersion - the version of the HTTP tunnelling protocol ConnectionCookie - the connection cookie OldChannelCookie - the old channel cookie NewChannelCookie - the new channel cookie Return Value: The allocated send context or NULL for out-of-memory --*/ { HTTP2SendContext *SendContext; TunnelSettingsCommand *CurrentCommand; rpcconn_tunnel_settings *RTS; SendContext = AllocateAndInitializeRTSPacket( BaseRTSCommandSize * 4 + SIZE_OF_RTS_CMD_AND_PADDING(tsctVersion) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) ); if (SendContext) { RTS = GetRTSPacketFromSendContext(SendContext); RTS->Flags = RTS_FLAG_RECYCLE_CHANNEL; RTS->NumberOfSettingCommands = 4; CurrentCommand = RTS->Cmd; // set version CurrentCommand->CommandType = tsctVersion; CurrentCommand->u.Version = ProtocolVersion; CurrentCommand = SkipCommand(CurrentCommand, tsctVersion); // set connection cookie CurrentCommand->CommandType = tsctCookie; RpcpMemoryCopy(CurrentCommand->u.Cookie.Cookie, ConnectionCookie->GetCookie(), COOKIE_SIZE_IN_BYTES); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // set old channel cookie CurrentCommand->CommandType = tsctCookie; RpcpMemoryCopy(CurrentCommand->u.Cookie.Cookie, OldChannelCookie->GetCookie(), COOKIE_SIZE_IN_BYTES); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // set new channel cookie CurrentCommand->CommandType = tsctCookie; RpcpMemoryCopy(CurrentCommand->u.Cookie.Cookie, NewChannelCookie->GetCookie(), COOKIE_SIZE_IN_BYTES); } return SendContext; } RPC_STATUS ParseAndFreeD2_A1 ( IN BYTE *Packet, IN ULONG PacketLength, OUT ULONG *ProtocolVersion, OUT HTTP2Cookie *ConnectionCookie, OUT HTTP2Cookie *OldChannelCookie, OUT HTTP2Cookie *NewChannelCookie ) /*++ Routine Description: Parses and frees a D2/A1 RTS packet Arguments: Packet - the packet received. PacketLength - the length of the packet ProtocolVersion - on output, the version of the HTTP tunnelling protocol Success only. ConnectionCookie - on output, the connection cookie. Success only. OldChannelCookie - on output, the old channel cookie. Success only. NewChannelCookie - on output, the new channel cookie. Success only. Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { ULONG MemorySize; rpcconn_tunnel_settings *RTS = (rpcconn_tunnel_settings *)Packet; BYTE *CurrentPosition; TunnelSettingsCommand *CurrentCommand; RPC_STATUS RpcStatus; MemorySize = BaseRTSSizeAndPadding + BaseRTSCommandSize * 4 + SIZE_OF_RTS_CMD_AND_PADDING(tsctVersion) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) ; if (PacketLength < MemorySize) goto AbortAndExit; CurrentPosition = ValidateRTSPacketCommon(Packet, PacketLength); if (CurrentPosition == NULL) goto AbortAndExit; if (RTS->NumberOfSettingCommands != 4) goto AbortAndExit; if (RTS->Flags != RTS_FLAG_RECYCLE_CHANNEL) goto AbortAndExit; CurrentCommand = (TunnelSettingsCommand *)CurrentPosition; // get version if (CurrentCommand->CommandType != tsctVersion) goto AbortAndExit; *ProtocolVersion = CurrentCommand->u.Version; CurrentCommand = SkipCommand(CurrentCommand, tsctVersion); // get connection cookie if (CurrentCommand->CommandType != tsctCookie) goto AbortAndExit; ConnectionCookie->SetCookie((BYTE *)CurrentCommand->u.Cookie.Cookie); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // get new channel cookie if (CurrentCommand->CommandType != tsctCookie) goto AbortAndExit; OldChannelCookie->SetCookie((BYTE *)CurrentCommand->u.Cookie.Cookie); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // get old channel cookie if (CurrentCommand->CommandType != tsctCookie) goto AbortAndExit; NewChannelCookie->SetCookie((BYTE *)CurrentCommand->u.Cookie.Cookie); RpcStatus = RPC_S_OK; goto CleanupAndExit; AbortAndExit: RpcStatus = RPC_S_PROTOCOL_ERROR; CleanupAndExit: RpcFreeBuffer(Packet); return RpcStatus; } HTTP2SendContext *AllocateAndInitializeD2_A2 ( IN ULONG ProtocolVersion, IN HTTP2Cookie *ConnectionCookie, IN HTTP2Cookie *OldChannelCookie, IN HTTP2Cookie *NewChannelCookie, IN ULONG ReceiveWindowSize, IN ULONG ConnectionTimeout ) /*++ Routine Description: Allocates and initializes a D2/A2 RTS packet Arguments: ProtocolVersion - the version of the HTTP tunnelling protocol ConnectionCookie - the connection cookie OldChannelCookie - the old channel cookie NewChannelCookie - the new channel cookie ReceiveWindowSize - the receive window size of the in proxy ConnectionTimeout - connection timeout of the in proxy Return Value: The allocated send context or NULL for out-of-memory --*/ { HTTP2SendContext *SendContext; TunnelSettingsCommand *CurrentCommand; rpcconn_tunnel_settings *RTS; SendContext = AllocateAndInitializeRTSPacket( BaseRTSCommandSize * 6 + SIZE_OF_RTS_CMD_AND_PADDING(tsctVersion) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctReceiveWindowSize) + SIZE_OF_RTS_CMD_AND_PADDING(tsctConnectionTimeout) ); if (SendContext) { RTS = GetRTSPacketFromSendContext(SendContext); RTS->Flags = RTS_FLAG_IN_CHANNEL | RTS_FLAG_RECYCLE_CHANNEL; RTS->NumberOfSettingCommands = 6; CurrentCommand = RTS->Cmd; // set version CurrentCommand->CommandType = tsctVersion; CurrentCommand->u.Version = ProtocolVersion; CurrentCommand = SkipCommand(CurrentCommand, tsctVersion); // set connection cookie CurrentCommand->CommandType = tsctCookie; RpcpMemoryCopy(CurrentCommand->u.Cookie.Cookie, ConnectionCookie->GetCookie(), COOKIE_SIZE_IN_BYTES); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // set old channel cookie CurrentCommand->CommandType = tsctCookie; RpcpMemoryCopy(CurrentCommand->u.Cookie.Cookie, OldChannelCookie->GetCookie(), COOKIE_SIZE_IN_BYTES); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // set new channel cookie CurrentCommand->CommandType = tsctCookie; RpcpMemoryCopy(CurrentCommand->u.Cookie.Cookie, NewChannelCookie->GetCookie(), COOKIE_SIZE_IN_BYTES); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // set receive window size CurrentCommand->CommandType = tsctReceiveWindowSize; CurrentCommand->u.ReceiveWindowSize = ReceiveWindowSize; CurrentCommand = SkipCommand(CurrentCommand, tsctReceiveWindowSize); // set connection timeout CurrentCommand->CommandType = tsctConnectionTimeout; CurrentCommand->u.ConnectionTimeout = ConnectionTimeout; } return SendContext; } RPC_STATUS ParseD2_A2 ( IN BYTE *Packet, IN ULONG PacketLength, OUT ULONG *ProtocolVersion, OUT HTTP2Cookie *ConnectionCookie, OUT HTTP2Cookie *OldChannelCookie, OUT HTTP2Cookie *NewChannelCookie, OUT ULONG *ReceiveWindowSize, OUT ULONG *ConnectionTimeout ) /*++ Routine Description: Parses a D1/B2 RTS packet Arguments: Packet - the packet received. PacketLength - the length of the packet ProtocolVersion - the version of the HTTP tunnelling protocol ConnectionCookie - the connection cookie OldChannelCookie - the old channel cookie NewChannelCookie - the new channel cookie ReceiveWindowSize - the receive window size of the in proxy ConnectionTimeout - connection timeout of the in proxy Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { ULONG MemorySize; rpcconn_tunnel_settings *RTS = (rpcconn_tunnel_settings *)Packet; BYTE *CurrentPosition; TunnelSettingsCommand *CurrentCommand; RPC_STATUS RpcStatus; MemorySize = BaseRTSSizeAndPadding + BaseRTSCommandSize * 6 + SIZE_OF_RTS_CMD_AND_PADDING(tsctVersion) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctReceiveWindowSize) + SIZE_OF_RTS_CMD_AND_PADDING(tsctConnectionTimeout) ; if (PacketLength < MemorySize) goto AbortAndExit; CurrentPosition = ValidateRTSPacketCommon(Packet, PacketLength); if (CurrentPosition == NULL) goto AbortAndExit; if (RTS->NumberOfSettingCommands != 6) goto AbortAndExit; if (RTS->Flags != (RTS_FLAG_IN_CHANNEL | RTS_FLAG_RECYCLE_CHANNEL)) goto AbortAndExit; CurrentCommand = (TunnelSettingsCommand *)CurrentPosition; // get version if (CurrentCommand->CommandType != tsctVersion) goto AbortAndExit; *ProtocolVersion = CurrentCommand->u.Version; CurrentCommand = SkipCommand(CurrentCommand, tsctVersion); // get connection cookie if (CurrentCommand->CommandType != tsctCookie) goto AbortAndExit; ConnectionCookie->SetCookie((BYTE *)CurrentCommand->u.Cookie.Cookie); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // get old channel cookie if (CurrentCommand->CommandType != tsctCookie) goto AbortAndExit; OldChannelCookie->SetCookie((BYTE *)CurrentCommand->u.Cookie.Cookie); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // get new channel cookie if (CurrentCommand->CommandType != tsctCookie) goto AbortAndExit; NewChannelCookie->SetCookie((BYTE *)CurrentCommand->u.Cookie.Cookie); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // get receive window size if (CurrentCommand->CommandType != tsctReceiveWindowSize) goto AbortAndExit; *ReceiveWindowSize = CurrentCommand->u.ReceiveWindowSize; CurrentCommand = SkipCommand(CurrentCommand, tsctReceiveWindowSize); // get connection timeout if (CurrentCommand->CommandType != tsctConnectionTimeout) goto AbortAndExit; *ConnectionTimeout = CurrentCommand->u.ConnectionTimeout; CurrentCommand = SkipCommand(CurrentCommand, tsctConnectionTimeout); RpcStatus = RPC_S_OK; goto CleanupAndExit; AbortAndExit: RpcStatus = RPC_S_PROTOCOL_ERROR; CleanupAndExit: return RpcStatus; } HTTP2SendContext *AllocateAndInitializeD2_A3 ( IN ForwardDestinations Destination, IN ULONG ProtocolVersion, IN ULONG ReceiveWindowSize, IN ULONG ConnectionTimeout ) /*++ Routine Description: Allocates and initializes a D2/A3 RTS packet Arguments: Destination - where to forward this to. ProtocolVersion - the version of the HTTP tunnelling protocol ReceiveWindowSize - the receive window size of the in proxy ConnectionTimeout - connection timeout of the in proxy Return Value: The allocated send context or NULL for out-of-memory --*/ { HTTP2SendContext *SendContext; TunnelSettingsCommand *CurrentCommand; rpcconn_tunnel_settings *RTS; SendContext = AllocateAndInitializeRTSPacket( BaseRTSCommandSize * 4 + SIZE_OF_RTS_CMD_AND_PADDING(tsctDestination) + SIZE_OF_RTS_CMD_AND_PADDING(tsctVersion) + SIZE_OF_RTS_CMD_AND_PADDING(tsctReceiveWindowSize) + SIZE_OF_RTS_CMD_AND_PADDING(tsctConnectionTimeout) ); if (SendContext) { RTS = GetRTSPacketFromSendContext(SendContext); RTS->Flags = 0; RTS->NumberOfSettingCommands = 4; CurrentCommand = RTS->Cmd; // set destination CurrentCommand->CommandType = tsctDestination; CurrentCommand->u.Destination = Destination; CurrentCommand = SkipCommand(CurrentCommand, tsctDestination); // set version CurrentCommand->CommandType = tsctVersion; CurrentCommand->u.Version = ProtocolVersion; CurrentCommand = SkipCommand(CurrentCommand, tsctVersion); // set receive window size CurrentCommand->CommandType = tsctReceiveWindowSize; CurrentCommand->u.ReceiveWindowSize = ReceiveWindowSize; CurrentCommand = SkipCommand(CurrentCommand, tsctReceiveWindowSize); // set connection timeout CurrentCommand->CommandType = tsctConnectionTimeout; CurrentCommand->u.ConnectionTimeout = ConnectionTimeout; } return SendContext; } RPC_STATUS ParseD2_A3orD2_A4 ( IN BYTE *Packet, IN ULONG PacketLength, IN ForwardDestinations ExpectedDestination, OUT ULONG *ProtocolVersion, OUT ULONG *ReceiveWindowSize, OUT ULONG *ConnectionTimeout ) /*++ Routine Description: Parses a D2/A3 or D2/A4 RTS packet Arguments: Packet - the packet received. PacketLength - the length of the packet ExpectedDestination - the destination code for this location (client) ProtocolVersion - the version of the HTTP tunnelling protocol ReceiveWindowSize - the receive window size of the in proxy ConnectionTimeout - connection timeout of the in proxy Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { ULONG MemorySize; rpcconn_tunnel_settings *RTS = (rpcconn_tunnel_settings *)Packet; BYTE *CurrentPosition; TunnelSettingsCommand *CurrentCommand; RPC_STATUS RpcStatus; MemorySize = BaseRTSSizeAndPadding + BaseRTSCommandSize * 4 + SIZE_OF_RTS_CMD_AND_PADDING(tsctDestination) + SIZE_OF_RTS_CMD_AND_PADDING(tsctVersion) + SIZE_OF_RTS_CMD_AND_PADDING(tsctReceiveWindowSize) + SIZE_OF_RTS_CMD_AND_PADDING(tsctConnectionTimeout) ; if (PacketLength < MemorySize) goto AbortAndExit; CurrentPosition = ValidateRTSPacketCommon(Packet, PacketLength); if (CurrentPosition == NULL) goto AbortAndExit; if (RTS->NumberOfSettingCommands != 4) goto AbortAndExit; if (RTS->Flags != 0) goto AbortAndExit; CurrentCommand = (TunnelSettingsCommand *)CurrentPosition; // verify destination if (CurrentCommand->CommandType != tsctDestination) goto AbortAndExit; if (ExpectedDestination != CurrentCommand->u.Destination) goto AbortAndExit; CurrentCommand = SkipCommand(CurrentCommand, tsctDestination); // get version if (CurrentCommand->CommandType != tsctVersion) goto AbortAndExit; *ProtocolVersion = CurrentCommand->u.Version; CurrentCommand = SkipCommand(CurrentCommand, tsctVersion); // get receive window size if (CurrentCommand->CommandType != tsctReceiveWindowSize) goto AbortAndExit; *ReceiveWindowSize = CurrentCommand->u.ReceiveWindowSize; CurrentCommand = SkipCommand(CurrentCommand, tsctReceiveWindowSize); // get connection timeout if (CurrentCommand->CommandType != tsctConnectionTimeout) goto AbortAndExit; *ConnectionTimeout = CurrentCommand->u.ConnectionTimeout; CurrentCommand = SkipCommand(CurrentCommand, tsctConnectionTimeout); RpcStatus = RPC_S_OK; goto CleanupAndExit; AbortAndExit: RpcStatus = RPC_S_PROTOCOL_ERROR; CleanupAndExit: return RpcStatus; } BOOL IsD2_A3Packet ( IN BYTE *Packet, IN ULONG PacketLength, OUT ULONG *ProtocolVersion ) /*++ Routine Description: Determines if a packet is a D2/A3 packet and if so, retrieves the ProtocolVersion contained in the packet. Arguments: Packet - the packet received. PacketLength - the length of the packet ProtocolVersion - if this function returns TRUE, the version of the HTTP tunnelling protocol. Undefined otherwise. Return Value: Non-zero if this is a D2_A3 packet. Zero if it is not or it cannot be parsed. --*/ { RPC_STATUS RpcStatus; ULONG ReceiveWindowSize; ULONG ConnectionTimeout; // we ignore the results for ReceiveWindowSize and // ConnectionTimeout RpcStatus = ParseD2_A3orD2_A4 (Packet, PacketLength, fdClient, ProtocolVersion, &ReceiveWindowSize, &ConnectionTimeout ); return (RpcStatus == RPC_S_OK); } RPC_STATUS ParseAndFreeD2_A4 ( IN BYTE *Packet, IN ULONG PacketLength, IN ForwardDestinations ExpectedDestination, OUT ULONG *ProtocolVersion, OUT ULONG *ReceiveWindowSize, OUT ULONG *ConnectionTimeout ) /*++ Routine Description: Parses and frees a D2/A4 RTS packet Arguments: Packet - the packet received. PacketLength - the length of the packet ExpectedDestination - the destination code for this location (client) ProtocolVersion - the version of the HTTP tunnelling protocol ReceiveWindowSize - the receive window size of the in proxy ConnectionTimeout - connection timeout of the in proxy Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { RPC_STATUS RpcStatus; RpcStatus = ParseD2_A3orD2_A4 (Packet, PacketLength, ExpectedDestination, ProtocolVersion, ReceiveWindowSize, ConnectionTimeout ); RpcFreeBuffer(Packet); return RpcStatus; } HTTP2SendContext *AllocateAndInitializeD2_A5 ( IN HTTP2Cookie *NewChannelCookie ) /*++ Routine Description: Allocates and initializes a D2/A5 RTS packet Arguments: NewChannelCookie - the new channel cookie Return Value: The allocated send context or NULL for out-of-memory --*/ { HTTP2SendContext *SendContext; TunnelSettingsCommand *CurrentCommand; rpcconn_tunnel_settings *RTS; SendContext = AllocateAndInitializeRTSPacket( BaseRTSCommandSize * 1 + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) ); if (SendContext) { RTS = GetRTSPacketFromSendContext(SendContext); RTS->Flags = 0; RTS->NumberOfSettingCommands = 1; CurrentCommand = RTS->Cmd; // set new channel cookie CurrentCommand->CommandType = tsctCookie; RpcpMemoryCopy(CurrentCommand->u.Cookie.Cookie, NewChannelCookie->GetCookie(), COOKIE_SIZE_IN_BYTES); } return SendContext; } RPC_STATUS ParseD2_A5 ( IN BYTE *Packet, IN ULONG PacketLength, OUT HTTP2Cookie *NewChannelCookie ) /*++ Routine Description: Parses a D2/A5 RTS packet Arguments: Packet - the packet received. PacketLength - the length of the packet NewChannelCookie - the new channel cookie Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { ULONG MemorySize; rpcconn_tunnel_settings *RTS = (rpcconn_tunnel_settings *)Packet; BYTE *CurrentPosition; TunnelSettingsCommand *CurrentCommand; RPC_STATUS RpcStatus; MemorySize = BaseRTSSizeAndPadding + BaseRTSCommandSize * 1 + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) ; if (PacketLength < MemorySize) goto AbortAndExit; CurrentPosition = ValidateRTSPacketCommon(Packet, PacketLength); if (CurrentPosition == NULL) goto AbortAndExit; if (RTS->NumberOfSettingCommands != 1) goto AbortAndExit; if (RTS->Flags != 0) goto AbortAndExit; CurrentCommand = (TunnelSettingsCommand *)CurrentPosition; // get new channel cookie if (CurrentCommand->CommandType != tsctCookie) goto AbortAndExit; NewChannelCookie->SetCookie((BYTE *)CurrentCommand->u.Cookie.Cookie); RpcStatus = RPC_S_OK; goto CleanupAndExit; AbortAndExit: RpcStatus = RPC_S_PROTOCOL_ERROR; CleanupAndExit: return RpcStatus; } RPC_STATUS ParseAndFreeD2_A6 ( IN BYTE *Packet, IN ULONG PacketLength, OUT HTTP2Cookie *NewChannelCookie ) /*++ Routine Description: Parses and frees a D2/A6 RTS packet Arguments: Packet - the packet received. PacketLength - the length of the packet NewChannelCookie - the new channel cookie Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { RPC_STATUS RpcStatus; // D2/A6 is the same as D2/A5 RpcStatus = ParseD2_A5(Packet, PacketLength, NewChannelCookie); RpcFreeBuffer(Packet); return RpcStatus; } HTTP2SendContext *AllocateAndInitializeD2_B2 ( IN ULONG ServerReceiveWindow ) /*++ Routine Description: Allocates and initializes a D2/B2 RTS packet Arguments: ServerReceiveWindow - the server receive window Return Value: The allocated send context or NULL for out-of-memory --*/ { HTTP2SendContext *SendContext; TunnelSettingsCommand *CurrentCommand; rpcconn_tunnel_settings *RTS; SendContext = AllocateAndInitializeRTSPacket( BaseRTSCommandSize * 1 + SIZE_OF_RTS_CMD_AND_PADDING(tsctReceiveWindowSize) ); if (SendContext) { RTS = GetRTSPacketFromSendContext(SendContext); RTS->Flags = 0; RTS->NumberOfSettingCommands = 1; CurrentCommand = RTS->Cmd; // set server receive window CurrentCommand->CommandType = tsctReceiveWindowSize; CurrentCommand->u.ReceiveWindowSize = ServerReceiveWindow; } return SendContext; } RPC_STATUS ParseAndFreeD2_B2 ( IN BYTE *Packet, IN ULONG PacketLength, OUT ULONG *ServerReceiveWindow ) /*++ Routine Description: Parses and frees a D2/B2 RTS packet Arguments: Packet - the packet received. PacketLength - the length of the packet ServerReceiveWindow - the server receive window Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { ULONG MemorySize; rpcconn_tunnel_settings *RTS = (rpcconn_tunnel_settings *)Packet; BYTE *CurrentPosition; TunnelSettingsCommand *CurrentCommand; RPC_STATUS RpcStatus; MemorySize = BaseRTSSizeAndPadding + BaseRTSCommandSize * 1 + SIZE_OF_RTS_CMD_AND_PADDING(tsctReceiveWindowSize); if (PacketLength < MemorySize) goto AbortAndExit; CurrentPosition = ValidateRTSPacketCommon(Packet, PacketLength); if (CurrentPosition == NULL) goto AbortAndExit; if (RTS->NumberOfSettingCommands != 1) goto AbortAndExit; if (RTS->Flags != 0) goto AbortAndExit; CurrentCommand = (TunnelSettingsCommand *)CurrentPosition; // get server receive window if (CurrentCommand->CommandType != tsctReceiveWindowSize) goto AbortAndExit; *ServerReceiveWindow = CurrentCommand->u.ReceiveWindowSize; RpcStatus = RPC_S_OK; goto CleanupAndExit; AbortAndExit: RpcStatus = RPC_S_PROTOCOL_ERROR; CleanupAndExit: RpcFreeBuffer(Packet); return RpcStatus; } HTTP2SendContext *AllocateAndInitializeD4_A3 ( IN ULONG ProtocolVersion, IN HTTP2Cookie *ConnectionCookie, IN HTTP2Cookie *OldChannelCookie, IN HTTP2Cookie *NewChannelCookie, IN ULONG ClientReceiveWindow ) /*++ Routine Description: Allocates and initializes a D4/A3 RTS packet Arguments: ProtocolVersion - the version of the HTTP tunnelling protocol ConnectionCookie - the connection cookie OldChannelCookie - the old channel cookie NewChannelCookie - the new channel cookie ClientReceiveWindow - the client receive window Return Value: The allocated send context or NULL for out-of-memory --*/ { HTTP2SendContext *SendContext; TunnelSettingsCommand *CurrentCommand; rpcconn_tunnel_settings *RTS; SendContext = AllocateAndInitializeRTSPacket( BaseRTSCommandSize * 5 + SIZE_OF_RTS_CMD_AND_PADDING(tsctVersion) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctReceiveWindowSize) ); if (SendContext) { RTS = GetRTSPacketFromSendContext(SendContext); RTS->Flags = RTS_FLAG_RECYCLE_CHANNEL; RTS->NumberOfSettingCommands = 5; CurrentCommand = RTS->Cmd; // set version CurrentCommand->CommandType = tsctVersion; CurrentCommand->u.Version = ProtocolVersion; CurrentCommand = SkipCommand(CurrentCommand, tsctVersion); // set connection cookie CurrentCommand->CommandType = tsctCookie; RpcpMemoryCopy(CurrentCommand->u.Cookie.Cookie, ConnectionCookie->GetCookie(), COOKIE_SIZE_IN_BYTES); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // set old channel cookie CurrentCommand->CommandType = tsctCookie; RpcpMemoryCopy(CurrentCommand->u.Cookie.Cookie, OldChannelCookie->GetCookie(), COOKIE_SIZE_IN_BYTES); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // set new channel cookie CurrentCommand->CommandType = tsctCookie; RpcpMemoryCopy(CurrentCommand->u.Cookie.Cookie, NewChannelCookie->GetCookie(), COOKIE_SIZE_IN_BYTES); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // set client receive window CurrentCommand->CommandType = tsctReceiveWindowSize; CurrentCommand->u.ReceiveWindowSize = ClientReceiveWindow; } return SendContext; } RPC_STATUS ParseAndFreeD4_A2 ( IN BYTE *Packet, IN ULONG PacketLength ) /*++ Routine Description: Parses and frees a D4/A2 packet Arguments: Packet - the packet received. PacketLength - the length of the packet Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { ULONG MemorySize; rpcconn_tunnel_settings *RTS = (rpcconn_tunnel_settings *)Packet; BYTE *CurrentPosition; TunnelSettingsCommand *CurrentCommand; RPC_STATUS RpcStatus; MemorySize = BaseRTSSizeAndPadding + BaseRTSCommandSize * 1 + SIZE_OF_RTS_CMD_AND_PADDING(tsctDestination) ; if (PacketLength < MemorySize) goto AbortAndExit; CurrentPosition = ValidateRTSPacketCommon(Packet, PacketLength); if (CurrentPosition == NULL) goto AbortAndExit; if (RTS->NumberOfSettingCommands != 1) goto AbortAndExit; if (RTS->Flags != RTS_FLAG_RECYCLE_CHANNEL) goto AbortAndExit; CurrentCommand = (TunnelSettingsCommand *)CurrentPosition; // verify destination if (CurrentCommand->CommandType != tsctDestination) goto AbortAndExit; if (fdClient != CurrentCommand->u.Destination) goto AbortAndExit; RpcStatus = RPC_S_OK; goto CleanupAndExit; AbortAndExit: RpcStatus = RPC_S_PROTOCOL_ERROR; CleanupAndExit: RpcFreeBuffer(Packet); return RpcStatus; } ULONG GetD4_A3TotalLength ( void ) /*++ Routine Description: Calculates the length of a D1/A1 RTS packet Arguments: Return Value: The length of the D1/A1 RTS packet. --*/ { return (BaseRTSSizeAndPadding + BaseRTSCommandSize * 5 + SIZE_OF_RTS_CMD_AND_PADDING(tsctVersion) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctReceiveWindowSize) ); } ULONG GetD4_A11TotalLength ( void ) /*++ Routine Description: Calculates the length of a D4/A11 RTS packet Arguments: Return Value: The length of the D4/A11 RTS packet. --*/ { return (BaseRTSSizeAndPadding + BaseRTSCommandSize * 1 + SIZE_OF_RTS_CMD_AND_PADDING(tsctANCE) ); } RPC_STATUS ParseD4_A3 ( IN BYTE *Packet, IN ULONG PacketLength, OUT ULONG *ProtocolVersion, OUT HTTP2Cookie *ConnectionCookie, OUT HTTP2Cookie *OldChannelCookie, OUT HTTP2Cookie *NewChannelCookie, OUT ULONG *ClientReceiveWindow ) /*++ Routine Description: Parses and frees a D1/A1 RTS packet Arguments: Packet - the packet received. PacketLength - the length of the packet ProtocolVersion - the version of the HTTP tunnelling protocol ConnectionCookie - the connection cookie OldChannelCookie - the old channel cookie NewChannelCookie - the new channel cookie ClientReceiveWindow - the client receive window Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { ULONG MemorySize; rpcconn_tunnel_settings *RTS = (rpcconn_tunnel_settings *)Packet; BYTE *CurrentPosition; TunnelSettingsCommand *CurrentCommand; RPC_STATUS RpcStatus; MemorySize = BaseRTSSizeAndPadding + BaseRTSCommandSize * 5 + SIZE_OF_RTS_CMD_AND_PADDING(tsctVersion) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctReceiveWindowSize); if (PacketLength < MemorySize) goto AbortAndExit; CurrentPosition = ValidateRTSPacketCommon(Packet, PacketLength); if (CurrentPosition == NULL) goto AbortAndExit; if (RTS->NumberOfSettingCommands != 5) goto AbortAndExit; if (RTS->Flags != RTS_FLAG_RECYCLE_CHANNEL) goto AbortAndExit; CurrentCommand = (TunnelSettingsCommand *)CurrentPosition; // get version if (CurrentCommand->CommandType != tsctVersion) goto AbortAndExit; *ProtocolVersion = CurrentCommand->u.Version; CurrentCommand = SkipCommand(CurrentCommand, tsctVersion); // get connection cookie if (CurrentCommand->CommandType != tsctCookie) goto AbortAndExit; ConnectionCookie->SetCookie((BYTE *)CurrentCommand->u.Cookie.Cookie); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // get old channel cookie if (CurrentCommand->CommandType != tsctCookie) goto AbortAndExit; OldChannelCookie->SetCookie((BYTE *)CurrentCommand->u.Cookie.Cookie); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // get new channel cookie if (CurrentCommand->CommandType != tsctCookie) goto AbortAndExit; NewChannelCookie->SetCookie((BYTE *)CurrentCommand->u.Cookie.Cookie); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // get client receive window if (CurrentCommand->CommandType != tsctReceiveWindowSize) goto AbortAndExit; *ClientReceiveWindow = CurrentCommand->u.ReceiveWindowSize; RpcStatus = RPC_S_OK; goto CleanupAndExit; AbortAndExit: RpcStatus = RPC_S_PROTOCOL_ERROR; CleanupAndExit: return RpcStatus; } RPC_STATUS ParseAndFreeD4_A3 ( IN BYTE *Packet, IN ULONG PacketLength, OUT ULONG *ProtocolVersion, OUT HTTP2Cookie *ConnectionCookie, OUT HTTP2Cookie *OldChannelCookie, OUT HTTP2Cookie *NewChannelCookie, OUT ULONG *ClientReceiveWindow ) /*++ Routine Description: Parses and frees a D1/A1 RTS packet Arguments: Packet - the packet received. PacketLength - the length of the packet ProtocolVersion - the version of the HTTP tunnelling protocol ConnectionCookie - the connection cookie OldChannelCookie - the old channel cookie NewChannelCookie - the new channel cookie ClientReceiveWindow - the client receive window Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { RPC_STATUS RpcStatus; RpcStatus = ParseD4_A3 (Packet, PacketLength, ProtocolVersion, ConnectionCookie, OldChannelCookie, NewChannelCookie, ClientReceiveWindow ); RpcFreeBuffer(Packet); return RpcStatus; } HTTP2SendContext *AllocateAndInitializeD4_A4 ( IN ULONG ProtocolVersion, IN HTTP2Cookie *ConnectionCookie, IN HTTP2Cookie *OldChannelCookie, IN HTTP2Cookie *NewChannelCookie, IN ULONG ChannelLifetime, IN ULONG ProxyReceiveWindow, IN ULONG ProxyConnectionTimeout ) /*++ Routine Description: Allocates and initializes a D4/A4 RTS packet Arguments: ProtocolVersion - the version of the HTTP tunnelling protocol ConnectionCookie - the connection cookie OldChannelCookie - the old channel cookie NewChannelCookie - the new channel cookie ChannelLifetime - the lifetime of the channel ProxyReceiveWindow - the proxy receive window ProxyConnectionTimeout - the proxy connection timeout Return Value: The allocated send context or NULL for out-of-memory --*/ { HTTP2SendContext *SendContext; TunnelSettingsCommand *CurrentCommand; rpcconn_tunnel_settings *RTS; SendContext = AllocateAndInitializeRTSPacket( BaseRTSCommandSize * 7 + SIZE_OF_RTS_CMD_AND_PADDING(tsctVersion) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctChannelLifetime) + SIZE_OF_RTS_CMD_AND_PADDING(tsctReceiveWindowSize) + SIZE_OF_RTS_CMD_AND_PADDING(tsctConnectionTimeout) ); if (SendContext) { RTS = GetRTSPacketFromSendContext(SendContext); RTS->Flags = RTS_FLAG_RECYCLE_CHANNEL | RTS_FLAG_OUT_CHANNEL; RTS->NumberOfSettingCommands = 7; CurrentCommand = RTS->Cmd; // set version CurrentCommand->CommandType = tsctVersion; CurrentCommand->u.Version = ProtocolVersion; CurrentCommand = SkipCommand(CurrentCommand, tsctVersion); // set connection cookie CurrentCommand->CommandType = tsctCookie; RpcpMemoryCopy(CurrentCommand->u.Cookie.Cookie, ConnectionCookie->GetCookie(), COOKIE_SIZE_IN_BYTES); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // set old channel cookie CurrentCommand->CommandType = tsctCookie; RpcpMemoryCopy(CurrentCommand->u.Cookie.Cookie, OldChannelCookie->GetCookie(), COOKIE_SIZE_IN_BYTES); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // set new channel cookie CurrentCommand->CommandType = tsctCookie; RpcpMemoryCopy(CurrentCommand->u.Cookie.Cookie, NewChannelCookie->GetCookie(), COOKIE_SIZE_IN_BYTES); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // set channel lifetime CurrentCommand->CommandType = tsctChannelLifetime; CurrentCommand->u.ChannelLifetime = ChannelLifetime; CurrentCommand = SkipCommand(CurrentCommand, tsctChannelLifetime); // set proxy receive window CurrentCommand->CommandType = tsctReceiveWindowSize; CurrentCommand->u.ReceiveWindowSize = ProxyReceiveWindow; CurrentCommand = SkipCommand(CurrentCommand, tsctReceiveWindowSize); // set proxy connection timeout CurrentCommand->CommandType = tsctConnectionTimeout; CurrentCommand->u.ConnectionTimeout = ProxyConnectionTimeout; } return SendContext; } RPC_STATUS ParseD4_A4 ( IN BYTE *Packet, IN ULONG PacketLength, OUT ULONG *ProtocolVersion, OUT HTTP2Cookie *ConnectionCookie, OUT HTTP2Cookie *OldChannelCookie, OUT HTTP2Cookie *NewChannelCookie, OUT ULONG *ChannelLifetime, OUT ULONG *ProxyReceiveWindow, OUT ULONG *ProxyConnectionTimeout ) /*++ Routine Description: Parses and frees a D1/A1 RTS packet Arguments: Packet - the packet received. PacketLength - the length of the packet ProtocolVersion - the version of the HTTP tunnelling protocol ConnectionCookie - the connection cookie OldChannelCookie - the old channel cookie NewChannelCookie - the new channel cookie ChannelLifetime - the lifetime of the channel ProxyReceiveWindow - the proxy receive window ProxyConnectionTimeout - the proxy connection timeout Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { ULONG MemorySize; rpcconn_tunnel_settings *RTS = (rpcconn_tunnel_settings *)Packet; BYTE *CurrentPosition; TunnelSettingsCommand *CurrentCommand; RPC_STATUS RpcStatus; MemorySize = BaseRTSSizeAndPadding + BaseRTSCommandSize * 7 + SIZE_OF_RTS_CMD_AND_PADDING(tsctVersion) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctChannelLifetime) + SIZE_OF_RTS_CMD_AND_PADDING(tsctReceiveWindowSize) + SIZE_OF_RTS_CMD_AND_PADDING(tsctConnectionTimeout) ; if (PacketLength < MemorySize) goto AbortAndExit; CurrentPosition = ValidateRTSPacketCommon(Packet, PacketLength); if (CurrentPosition == NULL) goto AbortAndExit; if (RTS->NumberOfSettingCommands != 7) goto AbortAndExit; if (RTS->Flags != (RTS_FLAG_RECYCLE_CHANNEL | RTS_FLAG_OUT_CHANNEL)) goto AbortAndExit; CurrentCommand = (TunnelSettingsCommand *)CurrentPosition; // get version if (CurrentCommand->CommandType != tsctVersion) goto AbortAndExit; *ProtocolVersion = CurrentCommand->u.Version; CurrentCommand = SkipCommand(CurrentCommand, tsctVersion); // get connection cookie if (CurrentCommand->CommandType != tsctCookie) goto AbortAndExit; ConnectionCookie->SetCookie((BYTE *)CurrentCommand->u.Cookie.Cookie); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // get old channel cookie if (CurrentCommand->CommandType != tsctCookie) goto AbortAndExit; OldChannelCookie->SetCookie((BYTE *)CurrentCommand->u.Cookie.Cookie); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // get new channel cookie if (CurrentCommand->CommandType != tsctCookie) goto AbortAndExit; NewChannelCookie->SetCookie((BYTE *)CurrentCommand->u.Cookie.Cookie); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // get channel lifetime if (CurrentCommand->CommandType != tsctChannelLifetime) goto AbortAndExit; *ChannelLifetime = CurrentCommand->u.ChannelLifetime; CurrentCommand = SkipCommand(CurrentCommand, tsctChannelLifetime); // get proxy receive window if (CurrentCommand->CommandType != tsctReceiveWindowSize) goto AbortAndExit; *ProxyReceiveWindow = CurrentCommand->u.ReceiveWindowSize; CurrentCommand = SkipCommand(CurrentCommand, tsctReceiveWindowSize); // get proxy connection timeout if (CurrentCommand->CommandType != tsctConnectionTimeout) goto AbortAndExit; *ProxyConnectionTimeout = CurrentCommand->u.ConnectionTimeout; RpcStatus = RPC_S_OK; goto CleanupAndExit; AbortAndExit: RpcStatus = RPC_S_PROTOCOL_ERROR; CleanupAndExit: return RpcStatus; } HTTP2SendContext *AllocateAndInitializeD4_A5 ( IN ForwardDestinations Destination, IN ULONG ProtocolVersion, IN ULONG ConnectionTimeout ) /*++ Routine Description: Allocates and initializes a D4/A5 RTS packet Arguments: Destination - where to forward this to. ProtocolVersion - the version of the HTTP tunnelling protocol ConnectionTimeout - connection timeout of the out proxy Return Value: The allocated send context or NULL for out-of-memory --*/ { HTTP2SendContext *SendContext; TunnelSettingsCommand *CurrentCommand; rpcconn_tunnel_settings *RTS; SendContext = AllocateAndInitializeRTSPacket( BaseRTSCommandSize * 3 + SIZE_OF_RTS_CMD_AND_PADDING(tsctDestination) + SIZE_OF_RTS_CMD_AND_PADDING(tsctVersion) + SIZE_OF_RTS_CMD_AND_PADDING(tsctConnectionTimeout) ); if (SendContext) { RTS = GetRTSPacketFromSendContext(SendContext); RTS->Flags = RTS_FLAG_OUT_CHANNEL; RTS->NumberOfSettingCommands = 3; CurrentCommand = RTS->Cmd; // set destination CurrentCommand->CommandType = tsctDestination; CurrentCommand->u.Destination = Destination; CurrentCommand = SkipCommand(CurrentCommand, tsctDestination); // set version CurrentCommand->CommandType = tsctVersion; CurrentCommand->u.Version = ProtocolVersion; CurrentCommand = SkipCommand(CurrentCommand, tsctVersion); // set connection timeout CurrentCommand->CommandType = tsctConnectionTimeout; CurrentCommand->u.ConnectionTimeout = ConnectionTimeout; } return SendContext; } RPC_STATUS ParseAndFreeD4_A6 ( IN BYTE *Packet, IN ULONG PacketLength, IN ForwardDestinations ExpectedDestination, OUT ULONG *ProtocolVersion, OUT ULONG *ConnectionTimeout ) /*++ Routine Description: Parses and frees a D4/A6 RTS packet Arguments: Packet - the packet received. PacketLength - the length of the packet ExpectedDestination - the destination code for this location (client) ProtocolVersion - the version of the HTTP tunnelling protocol ConnectionTimeout - connection timeout of the out proxy Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { ULONG MemorySize; rpcconn_tunnel_settings *RTS = (rpcconn_tunnel_settings *)Packet; BYTE *CurrentPosition; TunnelSettingsCommand *CurrentCommand; RPC_STATUS RpcStatus; MemorySize = BaseRTSSizeAndPadding + BaseRTSCommandSize * 3 + SIZE_OF_RTS_CMD_AND_PADDING(tsctDestination) + SIZE_OF_RTS_CMD_AND_PADDING(tsctVersion) + SIZE_OF_RTS_CMD_AND_PADDING(tsctConnectionTimeout) ; if (PacketLength < MemorySize) goto AbortAndExit; CurrentPosition = ValidateRTSPacketCommon(Packet, PacketLength); if (CurrentPosition == NULL) goto AbortAndExit; if (RTS->NumberOfSettingCommands != 3) goto AbortAndExit; if (RTS->Flags != RTS_FLAG_OUT_CHANNEL) goto AbortAndExit; CurrentCommand = (TunnelSettingsCommand *)CurrentPosition; // verify destination if (CurrentCommand->CommandType != tsctDestination) goto AbortAndExit; if (ExpectedDestination != CurrentCommand->u.Destination) goto AbortAndExit; CurrentCommand = SkipCommand(CurrentCommand, tsctVersion); // get version if (CurrentCommand->CommandType != tsctVersion) goto AbortAndExit; *ProtocolVersion = CurrentCommand->u.Version; CurrentCommand = SkipCommand(CurrentCommand, tsctVersion); // get connection timeout if (CurrentCommand->CommandType != tsctConnectionTimeout) goto AbortAndExit; *ConnectionTimeout = CurrentCommand->u.ConnectionTimeout; CurrentCommand = SkipCommand(CurrentCommand, tsctConnectionTimeout); RpcStatus = RPC_S_OK; goto CleanupAndExit; AbortAndExit: RpcStatus = RPC_S_PROTOCOL_ERROR; CleanupAndExit: RpcFreeBuffer(Packet); return RpcStatus; } HTTP2SendContext *AllocateAndInitializeD4_A7 ( IN ForwardDestinations Destination, IN HTTP2Cookie *NewChannelCookie, IN ULONG ProtocolVersion ) /*++ Routine Description: Allocates and initializes a D4/A7 RTS packet Arguments: Destination - the destination for the packet. NewChannelCookie - the new channel cookie ProtocolVersion - the new version negotiated with the new out proxy. Return Value: The allocated send context or NULL for out-of-memory --*/ { HTTP2SendContext *SendContext; TunnelSettingsCommand *CurrentCommand; rpcconn_tunnel_settings *RTS; SendContext = AllocateAndInitializeRTSPacket( BaseRTSCommandSize * 3 + SIZE_OF_RTS_CMD_AND_PADDING(tsctDestination) + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctVersion) ); if (SendContext) { RTS = GetRTSPacketFromSendContext(SendContext); RTS->Flags = RTS_FLAG_OUT_CHANNEL; RTS->NumberOfSettingCommands = 3; CurrentCommand = RTS->Cmd; // set destination CurrentCommand->CommandType = tsctDestination; CurrentCommand->u.Destination = Destination; CurrentCommand = SkipCommand(CurrentCommand, tsctDestination); // set new channel cookie CurrentCommand->CommandType = tsctCookie; RpcpMemoryCopy(CurrentCommand->u.Cookie.Cookie, NewChannelCookie->GetCookie(), COOKIE_SIZE_IN_BYTES); CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // set new verison CurrentCommand->CommandType = tsctVersion; CurrentCommand->u.Version = ProtocolVersion; } return SendContext; } RPC_STATUS ParseAndFreeD4_A8 ( IN BYTE *Packet, IN ULONG PacketLength, IN ForwardDestinations ExpectedDestination, OUT HTTP2Cookie *NewChannelCookie ) /*++ Routine Description: Parses a D2/A5 RTS packet Arguments: Packet - the packet received. PacketLength - the length of the packet ExpectedDestination - the id of the current hop that is being processed. NewChannelCookie - the new channel cookie Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { ULONG MemorySize; rpcconn_tunnel_settings *RTS = (rpcconn_tunnel_settings *)Packet; BYTE *CurrentPosition; TunnelSettingsCommand *CurrentCommand; RPC_STATUS RpcStatus; MemorySize = BaseRTSSizeAndPadding + BaseRTSCommandSize * 2 + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctDestination) ; if (PacketLength < MemorySize) goto AbortAndExit; CurrentPosition = ValidateRTSPacketCommon(Packet, PacketLength); if (CurrentPosition == NULL) goto AbortAndExit; if (RTS->NumberOfSettingCommands != 2) goto AbortAndExit; if (RTS->Flags != RTS_FLAG_OUT_CHANNEL) goto AbortAndExit; CurrentCommand = (TunnelSettingsCommand *)CurrentPosition; // verify destination if (CurrentCommand->CommandType != tsctDestination) goto AbortAndExit; if (ExpectedDestination != CurrentCommand->u.Destination) goto AbortAndExit; CurrentCommand = SkipCommand(CurrentCommand, tsctDestination); // get new channel cookie if (CurrentCommand->CommandType != tsctCookie) goto AbortAndExit; NewChannelCookie->SetCookie((BYTE *)CurrentCommand->u.Cookie.Cookie); RpcStatus = RPC_S_OK; goto CleanupAndExit; AbortAndExit: RpcStatus = RPC_S_PROTOCOL_ERROR; CleanupAndExit: RpcFreeBuffer(Packet); return RpcStatus; } BOOL IsNewD4_A7Packet ( IN BYTE *Packet, IN ULONG PacketLength, IN ForwardDestinations ExpectedDestination, OUT ULONG *ProtocolVersion ) /*++ Routine Description: Intermediate versions of .NET Server 2003 and all versions of Windows XPSP1 send D4/A7 without version information (old D4/A7). This routine detects if the passed in packet is the new style D4/A7 and if yes, retrieves the new protocol version. Arguments: Packet - the packet received. PacketLength - the length of the packet ExpectedDestination - the id of the destination we expect to find in the packet. ProtocolVersion - if the function returns non-zero, this is the protocol version indicated by D4/A7. If the function returns FALSE, the contents of this parameter is undefined. Return Value: non-zero if this is a new-style D4/A7 packet. Zero if it is not (including all cases of parsing failure) --*/ { ULONG MemorySize; rpcconn_tunnel_settings *RTS = (rpcconn_tunnel_settings *)Packet; BYTE *CurrentPosition; TunnelSettingsCommand *CurrentCommand; RPC_STATUS RpcStatus; MemorySize = BaseRTSSizeAndPadding + BaseRTSCommandSize * 3 + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctDestination) + SIZE_OF_RTS_CMD_AND_PADDING(tsctVersion) ; if (PacketLength < MemorySize) return FALSE; CurrentPosition = ValidateRTSPacketCommon(Packet, PacketLength); if (CurrentPosition == NULL) return FALSE; if (RTS->NumberOfSettingCommands != 3) return FALSE; if (RTS->Flags != RTS_FLAG_OUT_CHANNEL) return FALSE; CurrentCommand = (TunnelSettingsCommand *)CurrentPosition; // check for destination if (CurrentCommand->CommandType != tsctDestination) return FALSE; if (ExpectedDestination != CurrentCommand->u.Destination) return FALSE; CurrentCommand = SkipCommand(CurrentCommand, tsctDestination); // check for channel cookie if (CurrentCommand->CommandType != tsctCookie) return FALSE; CurrentCommand = SkipCommand(CurrentCommand, tsctCookie); // check for version if (CurrentCommand->CommandType != tsctVersion) return FALSE; *ProtocolVersion = CurrentCommand->u.Version; return TRUE; } void ConvertNewD4_A7ToD4_A8 ( IN OUT BYTE *Packet, IN OUT ULONG *PacketLength ) /*++ Routine Description: Takes a parsed a valid new style D4/A7 and converts it in-place to D4/A8 packet. Arguments: Packet - on input, the D4/A7 packet. On output, a D4/A8 packet. PacketLength - on input, the length of the D4/A7 packet. On output, the length of the D4/A8 packet. Return Value: --*/ { rpcconn_tunnel_settings *RTS = (rpcconn_tunnel_settings *)Packet; #if DBG ULONG MemorySize; MemorySize = BaseRTSSizeAndPadding + BaseRTSCommandSize * 3 + SIZE_OF_RTS_CMD_AND_PADDING(tsctCookie) + SIZE_OF_RTS_CMD_AND_PADDING(tsctDestination) + SIZE_OF_RTS_CMD_AND_PADDING(tsctVersion) ; ASSERT (*PacketLength == MemorySize); #endif // DBG // remove the version information from the length *PacketLength -= BaseRTSCommandSize + SIZE_OF_RTS_CMD_AND_PADDING(tsctVersion); // adjust the fragment length in the RPC header. RTS->common.frag_length -= BaseRTSCommandSize + SIZE_OF_RTS_CMD_AND_PADDING(tsctVersion); // truncate the version information at the end RTS->NumberOfSettingCommands = 2; } HTTP2SendContext *AllocateAndInitializeD4_A9 ( void ) /*++ Routine Description: Allocates and initializes a D4/A9 RTS packet Arguments: Return Value: The allocated send context or NULL for out-of-memory --*/ { HTTP2SendContext *SendContext; TunnelSettingsCommand *CurrentCommand; rpcconn_tunnel_settings *RTS; SendContext = AllocateAndInitializeRTSPacket( BaseRTSCommandSize * 1 + SIZE_OF_RTS_CMD_AND_PADDING(tsctANCE) ); if (SendContext) { RTS = GetRTSPacketFromSendContext(SendContext); RTS->Flags = 0; RTS->NumberOfSettingCommands = 1; CurrentCommand = RTS->Cmd; // set ANCE command CurrentCommand->CommandType = tsctANCE; } return SendContext; } RPC_STATUS ParseD4_A9 ( IN BYTE *Packet, IN ULONG PacketLength ) /*++ Routine Description: Parses a D4/A10 RTS packet Arguments: Packet - the packet received. PacketLength - the length of the packet Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { ULONG MemorySize; rpcconn_tunnel_settings *RTS = (rpcconn_tunnel_settings *)Packet; BYTE *CurrentPosition; TunnelSettingsCommand *CurrentCommand; RPC_STATUS RpcStatus; MemorySize = BaseRTSSizeAndPadding + BaseRTSCommandSize * 1 + SIZE_OF_RTS_CMD_AND_PADDING(tsctANCE) ; if (PacketLength < MemorySize) goto AbortAndExit; CurrentPosition = ValidateRTSPacketCommon(Packet, PacketLength); if (CurrentPosition == NULL) goto AbortAndExit; if (RTS->NumberOfSettingCommands != 1) goto AbortAndExit; if (RTS->Flags != 0) goto AbortAndExit; CurrentCommand = (TunnelSettingsCommand *)CurrentPosition; // verify ANCE if (CurrentCommand->CommandType != tsctANCE) goto AbortAndExit; RpcStatus = RPC_S_OK; goto CleanupAndExit; AbortAndExit: RpcStatus = RPC_S_PROTOCOL_ERROR; CleanupAndExit: return RpcStatus; } RPC_STATUS ParseAndFreeD4_A9 ( IN BYTE *Packet, IN ULONG PacketLength ) /*++ Routine Description: Parses and frees a D4/A10 RTS packet Arguments: Packet - the packet received. PacketLength - the length of the packet Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { RPC_STATUS RpcStatus; RpcStatus = ParseD4_A10(Packet, PacketLength ); RpcFreeBuffer(Packet); return RpcStatus; } HTTP2SendContext *AllocateAndInitializeD5_A5 ( IN ForwardDestinations Destination ) /*++ Routine Description: Allocates and initializes a D4/A9 RTS packet Arguments: Destination - destination for forwarding Return Value: The allocated send context or NULL for out-of-memory --*/ { HTTP2SendContext *SendContext; TunnelSettingsCommand *CurrentCommand; rpcconn_tunnel_settings *RTS; SendContext = AllocateAndInitializeRTSPacket( BaseRTSCommandSize * 2 + SIZE_OF_RTS_CMD_AND_PADDING(tsctDestination) + SIZE_OF_RTS_CMD_AND_PADDING(tsctANCE) ); if (SendContext) { RTS = GetRTSPacketFromSendContext(SendContext); RTS->Flags = 0; RTS->NumberOfSettingCommands = 2; CurrentCommand = RTS->Cmd; // set destination CurrentCommand->CommandType = tsctDestination; CurrentCommand->u.Destination = Destination; CurrentCommand = SkipCommand(CurrentCommand, tsctDestination); // set empty command CurrentCommand->CommandType = tsctANCE; } return SendContext; } RPC_STATUS ParseD5_A6 ( IN BYTE *Packet, IN ULONG PacketLength, IN ForwardDestinations ExpectedDestination ) /*++ Routine Description: Parses a D5/A6 RTS packet Arguments: Packet - the packet received. PacketLength - the length of the packet ExpectedDestination - the destination code for the target location (client) Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { ULONG MemorySize; rpcconn_tunnel_settings *RTS = (rpcconn_tunnel_settings *)Packet; BYTE *CurrentPosition; TunnelSettingsCommand *CurrentCommand; RPC_STATUS RpcStatus; MemorySize = BaseRTSSizeAndPadding + BaseRTSCommandSize * 2 + SIZE_OF_RTS_CMD_AND_PADDING(tsctDestination) + SIZE_OF_RTS_CMD_AND_PADDING(tsctANCE) ; if (PacketLength < MemorySize) goto AbortAndExit; CurrentPosition = ValidateRTSPacketCommon(Packet, PacketLength); if (CurrentPosition == NULL) goto AbortAndExit; if (RTS->NumberOfSettingCommands != 2) goto AbortAndExit; if (RTS->Flags != 0) goto AbortAndExit; CurrentCommand = (TunnelSettingsCommand *)CurrentPosition; // verify destination if (CurrentCommand->CommandType != tsctDestination) goto AbortAndExit; if (ExpectedDestination != CurrentCommand->u.Destination) goto AbortAndExit; CurrentCommand = SkipCommand(CurrentCommand, tsctDestination); // verify ANCE if (CurrentCommand->CommandType != tsctANCE) goto AbortAndExit; RpcStatus = RPC_S_OK; goto CleanupAndExit; AbortAndExit: RpcStatus = RPC_S_PROTOCOL_ERROR; CleanupAndExit: return RpcStatus; } RPC_STATUS ParseAndFreeD5_A6 ( IN BYTE *Packet, IN ULONG PacketLength, IN ForwardDestinations ExpectedDestination ) /*++ Routine Description: Parses and frees a D5/A5 RTS packet Arguments: Packet - the packet received. PacketLength - the length of the packet ExpectedDestination - the destination code for this location (client) Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { RPC_STATUS RpcStatus; RpcStatus = ParseD5_A6(Packet, PacketLength, ExpectedDestination ); RpcFreeBuffer(Packet); return RpcStatus; } HTTP2SendContext *AllocateAndInitializeD5_B1orB2 ( IN BOOL IsAckOrNak ) /*++ Routine Description: Allocates and initializes a D5/B1 or D5/B2 RTS packet Arguments: IsAckOrNack - non-zero if this is an ACK and D5/B1 needs to go out. If 0, this is a NACK and D5/B2 will go out. Return Value: The allocated send context or NULL for out-of-memory --*/ { HTTP2SendContext *SendContext; TunnelSettingsCommand *CurrentCommand; rpcconn_tunnel_settings *RTS; ASSERT(SIZE_OF_RTS_CMD_AND_PADDING(tsctANCE) == SIZE_OF_RTS_CMD_AND_PADDING(tsctNANCE)); SendContext = AllocateAndInitializeRTSPacket( BaseRTSCommandSize * 1 + SIZE_OF_RTS_CMD_AND_PADDING(tsctANCE) ); if (SendContext) { RTS = GetRTSPacketFromSendContext(SendContext); RTS->Flags = 0; RTS->NumberOfSettingCommands = 1; CurrentCommand = RTS->Cmd; // set ANCE or NANCE command if (IsAckOrNak) CurrentCommand->CommandType = tsctANCE; else CurrentCommand->CommandType = tsctNANCE; } return SendContext; } RPC_STATUS ParseAndFreeD5_B1orB2 ( IN BYTE *Packet, IN ULONG PacketLength, OUT BOOL *IsAckOrNak ) /*++ Routine Description: Parses and frees a D5/B1 or D2/B2 RTS packet Arguments: Packet - the packet received. PacketLength - the length of the packet IsAckOrNak - if success, on output it will contain non-zero if the packet was ACK (ANCE or D5/B1) or zero if the packet was NACK (NANCE or D5/B2) Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { ULONG MemorySize; rpcconn_tunnel_settings *RTS = (rpcconn_tunnel_settings *)Packet; BYTE *CurrentPosition; TunnelSettingsCommand *CurrentCommand; RPC_STATUS RpcStatus; MemorySize = BaseRTSSizeAndPadding + BaseRTSCommandSize * 1 + SIZE_OF_RTS_CMD_AND_PADDING(tsctANCE) ; if (PacketLength < MemorySize) goto AbortAndExit; CurrentPosition = ValidateRTSPacketCommon(Packet, PacketLength); if (CurrentPosition == NULL) goto AbortAndExit; if (RTS->NumberOfSettingCommands != 1) goto AbortAndExit; if (RTS->Flags != 0) goto AbortAndExit; CurrentCommand = (TunnelSettingsCommand *)CurrentPosition; // verify ANCE if (CurrentCommand->CommandType == tsctANCE) *IsAckOrNak = TRUE; else if (CurrentCommand->CommandType == tsctNANCE) *IsAckOrNak = FALSE; else goto AbortAndExit; RpcStatus = RPC_S_OK; goto CleanupAndExit; AbortAndExit: RpcStatus = RPC_S_PROTOCOL_ERROR; CleanupAndExit: RpcFreeBuffer(Packet); return RpcStatus; } RPC_STATUS ParseAndFreeD5_B3 ( IN BYTE *Packet, IN ULONG PacketLength ) /*++ Routine Description: Parses and frees a D5/B3 RTS packet Arguments: Packet - the packet received. PacketLength - the length of the packet Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { ULONG MemorySize; rpcconn_tunnel_settings *RTS = (rpcconn_tunnel_settings *)Packet; BYTE *CurrentPosition; TunnelSettingsCommand *CurrentCommand; RPC_STATUS RpcStatus; MemorySize = BaseRTSSizeAndPadding + BaseRTSCommandSize * 1 + SIZE_OF_RTS_CMD_AND_PADDING(tsctANCE) ; if (PacketLength < MemorySize) goto AbortAndExit; CurrentPosition = ValidateRTSPacketCommon(Packet, PacketLength); if (CurrentPosition == NULL) goto AbortAndExit; if (RTS->NumberOfSettingCommands != 1) goto AbortAndExit; if (RTS->Flags != RTS_FLAG_EOF) goto AbortAndExit; CurrentCommand = (TunnelSettingsCommand *)CurrentPosition; // verify ANCE if (CurrentCommand->CommandType != tsctANCE) goto AbortAndExit; RpcStatus = RPC_S_OK; goto CleanupAndExit; AbortAndExit: RpcStatus = RPC_S_PROTOCOL_ERROR; CleanupAndExit: RpcFreeBuffer(Packet); return RpcStatus; } HTTP2SendContext *AllocateAndInitializeKeepAliveChangePacket ( IN ULONG NewKeepAliveInterval ) /*++ Routine Description: Allocates and initializes a keep alive change packet. Arguments: NewKeepAliveInterval - the new keep alive interval in milliseconds Return Value: The allocated send context or NULL for out-of-memory --*/ { HTTP2SendContext *SendContext; TunnelSettingsCommand *CurrentCommand; rpcconn_tunnel_settings *RTS; SendContext = AllocateAndInitializeRTSPacket( BaseRTSCommandSize * 1 + SIZE_OF_RTS_CMD_AND_PADDING(tsctClientKeepalive) ); if (SendContext) { RTS = GetRTSPacketFromSendContext(SendContext); RTS->Flags = RTS_FLAG_OTHER_CMD; RTS->NumberOfSettingCommands = 1; CurrentCommand = RTS->Cmd; // set destination CurrentCommand->CommandType = tsctClientKeepalive; CurrentCommand->u.ClientKeepalive = NewKeepAliveInterval; } return SendContext; } RPC_STATUS ParseAndFreeKeepAliveChangePacket ( IN BYTE *Packet, IN ULONG PacketLength, OUT ULONG *NewKeepAliveInterval ) /*++ Routine Description: Parses and frees a keep alive change packet Arguments: Packet - the packet received. PacketLength - the length of the packet NewKeepAliveInterval - the new keep alive interval Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { ULONG MemorySize; rpcconn_tunnel_settings *RTS = (rpcconn_tunnel_settings *)Packet; BYTE *CurrentPosition; TunnelSettingsCommand *CurrentCommand; RPC_STATUS RpcStatus; MemorySize = BaseRTSSizeAndPadding + BaseRTSCommandSize * 1 + SIZE_OF_RTS_CMD_AND_PADDING(tsctClientKeepalive) ; if (PacketLength < MemorySize) goto AbortAndExit; CurrentPosition = ValidateRTSPacketCommon(Packet, PacketLength); if (CurrentPosition == NULL) goto AbortAndExit; if (RTS->NumberOfSettingCommands != 1) goto AbortAndExit; if (RTS->Flags != RTS_FLAG_OTHER_CMD) goto AbortAndExit; CurrentCommand = (TunnelSettingsCommand *)CurrentPosition; // get new client keep alive if (CurrentCommand->CommandType != tsctClientKeepalive) goto AbortAndExit; *NewKeepAliveInterval = CurrentCommand->u.ClientKeepalive; if ((*NewKeepAliveInterval < MinimumClientNewKeepAliveInterval) && (*NewKeepAliveInterval != 0)) goto AbortAndExit; RpcStatus = RPC_S_OK; goto CleanupAndExit; AbortAndExit: RpcStatus = RPC_S_PROTOCOL_ERROR; CleanupAndExit: RpcFreeBuffer(Packet); return RpcStatus; } HTTP2SendContext *AllocateAndInitializeFlowControlAckPacket ( IN ULONG BytesReceivedForAck, IN ULONG WindowForAck, IN HTTP2Cookie *CookieForChannel ) /*++ Routine Description: Allocates and initializes a flow control ack packet Arguments: BytesReceivedForAck - the bytes received at the time the ack was issued. WindowForAck - the available window at the time the ack was issued. CookieForChannel - the cookie of the channel we ack to. Return Value: The allocated send context or NULL for out-of-memory --*/ { HTTP2SendContext *SendContext; TunnelSettingsCommand *CurrentCommand; rpcconn_tunnel_settings *RTS; SendContext = AllocateAndInitializeRTSPacket( BaseRTSCommandSize * 1 + SIZE_OF_RTS_CMD_AND_PADDING(tsctFlowControlAck) ); if (SendContext) { RTS = GetRTSPacketFromSendContext(SendContext); RTS->Flags = RTS_FLAG_OTHER_CMD; RTS->NumberOfSettingCommands = 1; CurrentCommand = RTS->Cmd; // set ack command CurrentCommand->CommandType = tsctFlowControlAck; CurrentCommand->u.Ack.BytesReceived = BytesReceivedForAck; CurrentCommand->u.Ack.AvailableWindow = WindowForAck; RpcpMemoryCopy(CurrentCommand->u.Ack.ChannelCookie.Cookie, CookieForChannel->GetCookie(), COOKIE_SIZE_IN_BYTES); } return SendContext; } HTTP2SendContext *AllocateAndInitializeFlowControlAckPacketWithDestination ( IN ForwardDestinations Destination, IN ULONG BytesReceivedForAck, IN ULONG WindowForAck, IN HTTP2Cookie *CookieForChannel ) /*++ Routine Description: Allocates and initializes a flow control ack packet with a forward destination Arguments: Destination - the destination to which to forward the packet BytesReceivedForAck - the bytes received at the time the ack was issued. WindowForAck - the available window at the time the ack was issued. CookieForChannel - the cookie of the channel we ack to. Return Value: The allocated send context or NULL for out-of-memory --*/ { HTTP2SendContext *SendContext; TunnelSettingsCommand *CurrentCommand; rpcconn_tunnel_settings *RTS; SendContext = AllocateAndInitializeRTSPacket( BaseRTSCommandSize * 2 + SIZE_OF_RTS_CMD_AND_PADDING(tsctDestination) + SIZE_OF_RTS_CMD_AND_PADDING(tsctFlowControlAck) ); if (SendContext) { RTS = GetRTSPacketFromSendContext(SendContext); RTS->Flags = RTS_FLAG_OTHER_CMD; RTS->NumberOfSettingCommands = 2; CurrentCommand = RTS->Cmd; // set destination CurrentCommand->CommandType = tsctDestination; CurrentCommand->u.Destination = Destination; CurrentCommand = SkipCommand(CurrentCommand, tsctDestination); // set ack command CurrentCommand->CommandType = tsctFlowControlAck; CurrentCommand->u.Ack.BytesReceived = BytesReceivedForAck; CurrentCommand->u.Ack.AvailableWindow = WindowForAck; RpcpMemoryCopy(CurrentCommand->u.Ack.ChannelCookie.Cookie, CookieForChannel->GetCookie(), COOKIE_SIZE_IN_BYTES); } return SendContext; } RPC_STATUS ParseAndFreeFlowControlAckPacket ( IN BYTE *Packet, IN ULONG PacketLength, OUT ULONG *BytesReceivedForAck, OUT ULONG *WindowForAck, OUT HTTP2Cookie *CookieForChannel ) /*++ Routine Description: Parses and frees a flow control ack packet Arguments: Packet - the packet received. PacketLength - the length of the packet BytesReceivedForAck - the bytes received at the time the ack was issued. WindowForAck - the available window at the time the ack was issued. CookieForChannel - the cookie of the channel we received ack for. Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { ULONG MemorySize; rpcconn_tunnel_settings *RTS = (rpcconn_tunnel_settings *)Packet; BYTE *CurrentPosition; TunnelSettingsCommand *CurrentCommand; RPC_STATUS RpcStatus; MemorySize = BaseRTSSizeAndPadding + BaseRTSCommandSize * 1 + SIZE_OF_RTS_CMD_AND_PADDING(tsctFlowControlAck) ; if (PacketLength < MemorySize) goto AbortAndExit; CurrentPosition = ValidateRTSPacketCommon(Packet, PacketLength); if (CurrentPosition == NULL) goto AbortAndExit; if (RTS->NumberOfSettingCommands != 1) goto AbortAndExit; if (RTS->Flags != RTS_FLAG_OTHER_CMD) goto AbortAndExit; CurrentCommand = (TunnelSettingsCommand *)CurrentPosition; // get ack values if (CurrentCommand->CommandType != tsctFlowControlAck) goto AbortAndExit; *BytesReceivedForAck = CurrentCommand->u.Ack.BytesReceived; *WindowForAck = CurrentCommand->u.Ack.AvailableWindow; CookieForChannel->SetCookie((BYTE *)CurrentCommand->u.Ack.ChannelCookie.Cookie); RpcStatus = RPC_S_OK; goto CleanupAndExit; AbortAndExit: RpcStatus = RPC_S_PROTOCOL_ERROR; CleanupAndExit: RpcFreeBuffer(Packet); return RpcStatus; } RPC_STATUS ParseAndFreeFlowControlAckPacketWithDestination ( IN BYTE *Packet, IN ULONG PacketLength, IN ForwardDestinations ExpectedDestination, OUT ULONG *BytesReceivedForAck, OUT ULONG *WindowForAck, OUT HTTP2Cookie *CookieForChannel ) /*++ Routine Description: Parses and frees a flow control ack packet Arguments: Packet - the packet received. PacketLength - the length of the packet Destination - the expected destination BytesReceivedForAck - the bytes received at the time the ack was issued. WindowForAck - the available window at the time the ack was issued. CookieForChannel - the cookie of the channel we received ack for. Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { RPC_STATUS RpcStatus; RpcStatus = ParseFlowControlAckPacketWithDestination ( Packet, PacketLength, ExpectedDestination, BytesReceivedForAck, WindowForAck, CookieForChannel ); RpcFreeBuffer(Packet); return RpcStatus; } RPC_STATUS ParseFlowControlAckPacketWithDestination ( IN BYTE *Packet, IN ULONG PacketLength, IN ForwardDestinations ExpectedDestination, OUT ULONG *BytesReceivedForAck, OUT ULONG *WindowForAck, OUT HTTP2Cookie *CookieForChannel ) /*++ Routine Description: Parses a flow control ack packet Arguments: Packet - the packet received. PacketLength - the length of the packet Destination - the expected destination BytesReceivedForAck - the bytes received at the time the ack was issued. WindowForAck - the available window at the time the ack was issued. CookieForChannel - the cookie of the channel we received ack for. Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { ULONG MemorySize; rpcconn_tunnel_settings *RTS = (rpcconn_tunnel_settings *)Packet; BYTE *CurrentPosition; TunnelSettingsCommand *CurrentCommand; RPC_STATUS RpcStatus; MemorySize = BaseRTSSizeAndPadding + BaseRTSCommandSize * 2 + SIZE_OF_RTS_CMD_AND_PADDING(tsctDestination) + SIZE_OF_RTS_CMD_AND_PADDING(tsctFlowControlAck) ; if (PacketLength < MemorySize) goto AbortAndExit; CurrentPosition = ValidateRTSPacketCommon(Packet, PacketLength); if (CurrentPosition == NULL) goto AbortAndExit; if (RTS->NumberOfSettingCommands != 2) goto AbortAndExit; if (RTS->Flags != RTS_FLAG_OTHER_CMD) goto AbortAndExit; CurrentCommand = (TunnelSettingsCommand *)CurrentPosition; // verify destination if (CurrentCommand->CommandType != tsctDestination) goto AbortAndExit; if (ExpectedDestination != CurrentCommand->u.Destination) goto AbortAndExit; CurrentCommand = SkipCommand(CurrentCommand, tsctDestination); // get ack values if (CurrentCommand->CommandType != tsctFlowControlAck) goto AbortAndExit; *BytesReceivedForAck = CurrentCommand->u.Ack.BytesReceived; *WindowForAck = CurrentCommand->u.Ack.AvailableWindow; CookieForChannel->SetCookie((BYTE *)CurrentCommand->u.Ack.ChannelCookie.Cookie); RpcStatus = RPC_S_OK; goto CleanupAndExit; AbortAndExit: RpcStatus = RPC_S_PROTOCOL_ERROR; CleanupAndExit: return RpcStatus; } HTTP2SendContext *AllocateAndInitializePingTrafficSentNotifyPacket ( IN ULONG PingTrafficSentBytes ) /*++ Routine Description: Allocates and initializes a ping traffic sent packet Arguments: PingTrafficSentBytes - the number of bytes sent in ping traffic Return Value: The allocated send context or NULL for out-of-memory --*/ { HTTP2SendContext *SendContext; TunnelSettingsCommand *CurrentCommand; rpcconn_tunnel_settings *RTS; SendContext = AllocateAndInitializeRTSPacket( BaseRTSCommandSize * 1 + SIZE_OF_RTS_CMD_AND_PADDING(tsctPingTrafficSentNotify) ); if (SendContext) { RTS = GetRTSPacketFromSendContext(SendContext); RTS->Flags = RTS_FLAG_OTHER_CMD; RTS->NumberOfSettingCommands = 1; CurrentCommand = RTS->Cmd; // set ping traffic sent CurrentCommand->CommandType = tsctPingTrafficSentNotify; CurrentCommand->u.PingTrafficSent = PingTrafficSentBytes; } return SendContext; } RPC_STATUS ParseAndFreePingTrafficSentNotifyPacket ( IN BYTE *Packet, IN ULONG PacketLength, OUT ULONG *PingTrafficSentBytes ) /*++ Routine Description: Parses a ping traffic sent packet Arguments: Packet - the packet received. PacketLength - the length of the packet PingTrafficSentBytes - the number of bytes sent in ping traffic Return Value: RPC_S_OK if the packet was successfully parsed and RPC_S_PROTOCOL_ERROR otherwise. --*/ { ULONG MemorySize; rpcconn_tunnel_settings *RTS = (rpcconn_tunnel_settings *)Packet; BYTE *CurrentPosition; TunnelSettingsCommand *CurrentCommand; RPC_STATUS RpcStatus; MemorySize = BaseRTSSizeAndPadding + BaseRTSCommandSize * 1 + SIZE_OF_RTS_CMD_AND_PADDING(tsctPingTrafficSentNotify) ; if (PacketLength < MemorySize) goto AbortAndExit; CurrentPosition = ValidateRTSPacketCommon(Packet, PacketLength); if (CurrentPosition == NULL) goto AbortAndExit; if (RTS->NumberOfSettingCommands != 1) goto AbortAndExit; if (RTS->Flags != RTS_FLAG_OTHER_CMD) goto AbortAndExit; CurrentCommand = (TunnelSettingsCommand *)CurrentPosition; // get ping traffic sent values if (CurrentCommand->CommandType != tsctPingTrafficSentNotify) goto AbortAndExit; *PingTrafficSentBytes = CurrentCommand->u.PingTrafficSent; RpcStatus = RPC_S_OK; goto CleanupAndExit; AbortAndExit: RpcStatus = RPC_S_PROTOCOL_ERROR; CleanupAndExit: RpcFreeBuffer(Packet); return RpcStatus; }