#include "precomp.h" // // S20.CPP // T.128 Protocol // // Copyright(c) Microsoft 1997- // #define MLZ_FILE_ZONE ZONE_NET // // S20_Init() // Initializes the T.128 protocol layer // BOOL S20_Init(void) { BOOL rc = FALSE; DebugEntry(S20_Init); ASSERT(g_s20State == S20_TERM); // // Register with the network layer. // if (!MG_Register(MGTASK_DCS, &g_s20pmgClient, g_putAS)) { ERROR_OUT(("Failed to register MG layer")); DC_QUIT; } g_s20State = S20_INIT; TRACE_OUT(("g_s20State is S20_INIT")); rc = TRUE; DC_EXIT_POINT: DebugExitBOOL(S20_Init, rc); return(rc); } // // S20_Term() // This cleans up the T.128 protocol layer. // void S20_Term(void) { DebugEntry(S20_Term); // // Note that this case statement is unusual in that it falls through // from each condition. This happens to suit the termination // processing rather well. // switch (g_s20State) { case S20_IN_SHARE: case S20_SHARE_PEND: // // Notify share ended // SC_End(); // // FALL THROUGH // case S20_NO_SHARE: case S20_JOIN_PEND: // // Leave our channels // if (g_s20BroadcastID != 0) { MG_ChannelLeave(g_s20pmgClient, g_s20BroadcastID); g_s20BroadcastID = 0; } if (g_s20JoinedLocal) { MG_ChannelLeave(g_s20pmgClient, g_s20LocalID); g_s20JoinedLocal = FALSE; } // // FALL THROUGH // case S20_ATTACH_PEND: // // Detach from the domain. // MG_Detach(g_s20pmgClient); case S20_INIT: // // We may end up here with g_s20BroadcastID & g_s20JoinedLocal // non-zero if Term was called in the middle of a share. Clear these // variables so when we start back up again via Init, it // works the same way as first initialization. // // Note we do not need to leave the channels. // g_s20BroadcastID = 0; g_s20JoinedLocal = FALSE; // // Deregister. // MG_Deregister(&g_s20pmgClient); g_s20State = S20_TERM; TRACE_OUT(("g_s20State is S20_TERM")); case S20_TERM: // // Finally we break out. // break; default: ERROR_OUT(("invalid state %d", g_s20State)); break; } DebugExitVOID(S20_Term); } // // S20_AllocPkt // Allocates a SEND packet for either the S20 protocol, syncs, or data // PS20DATAPACKET S20_AllocDataPkt ( UINT streamID, UINT nodeID, // One person or broadcast UINT cbSizePacket ) { PS20DATAPACKET pS20Packet = NULL; NET_PRIORITY priority; BOOL rc = FALSE; DebugEntry(S20_AllocDataPkt); ASSERT(g_s20State == S20_IN_SHARE); // // Try to send queued control packets first. // if (S20SendQueuedControlPackets() != 0) { // // If there are still queued control packets then don't allow any // allocation. // DC_QUIT; } priority = S20StreamToS20Priority(streamID); // // Note: // Sends to an individual node are NOT flow-controlled. Only the // global app sharing channel is. // if (MG_GetBuffer(g_s20pmgClient, cbSizePacket, priority, (NET_CHANNEL_ID)nodeID, (void **)&pS20Packet) != 0) { TRACE_OUT(("MG_GetBuffer failed; can't allocate S20 packet")); } else { pS20Packet->header.packetType = S20_DATA | S20_ALL_VERSIONS; pS20Packet->header.user = g_s20LocalID; pS20Packet->correlator = g_s20ShareCorrelator; pS20Packet->stream = 0; pS20Packet->dataLength = cbSizePacket - sizeof(S20DATAPACKET) + sizeof(DATAPACKETHEADER); rc = TRUE; } DC_EXIT_POINT: DebugExitPVOID(S20_AllocDataPkt, pS20Packet); return(pS20Packet); } // // S20_FreeDataPkt - see s20.h // void S20_FreeDataPkt(PS20DATAPACKET pS20Packet) { DebugEntry(S20_FreeDataPkt); MG_FreeBuffer(g_s20pmgClient, (void **)&pS20Packet); DebugExitVOID(S20_FreeDataPkt); } // // S20_SendDataPkt - see s20.h // void S20_SendDataPkt ( UINT streamID, UINT nodeID, PS20DATAPACKET pS20Packet ) { UINT rc; NET_PRIORITY priority; DebugEntry(S20_SendDataPkt); priority = S20StreamToS20Priority(streamID); // // Note: // Sends to an individual are not flow-controlled. Only sends to // everybody on the global app sharing channel are. // // // Try to send queued control packets first. // rc = S20SendQueuedControlPackets(); if (rc == 0) { // // Fill in the stream, length and correlator before sending. // pS20Packet->stream = (BYTE)streamID; pS20Packet->correlator = g_s20ShareCorrelator; // // dataLength includes the DATAPACKETHEADER part of the S20DATAPACKET // structure // TRACE_OUT(("S20_SendPkt: sending data packet size %d", pS20Packet->dataLength + sizeof(S20DATAPACKET) - sizeof(DATAPACKETHEADER))); rc = MG_SendData(g_s20pmgClient, priority, (NET_CHANNEL_ID)nodeID, pS20Packet->dataLength + sizeof(S20DATAPACKET) - sizeof(DATAPACKETHEADER), (void **)&pS20Packet); } // lonchanc: it is ok for MG_SendData returns 0 and NET_CHANNEL_EMPTY if (rc == NET_RC_MGC_NOT_CONNECTED) { S20LeaveOrEndShare(); } else { if (rc != 0) { ERROR_OUT(("SendData rc=%lx - expecting share termination soon", rc)); } } DebugExitVOID(S20_SendDataPkt); } // // S20_UTEventProc() // BOOL CALLBACK S20_UTEventProc ( LPVOID userData, UINT event, UINT_PTR data1, UINT_PTR data2 ) { BOOL processed; DebugEntry(S20_UTEventProc); processed = TRUE; switch (event) { case NET_EVENT_USER_ATTACH: S20AttachConfirm(LOWORD(data1), HIWORD(data1), (UINT)data2); break; case NET_EVENT_USER_DETACH: S20DetachIndication(LOWORD(data1), (UINT)data2); break; case NET_EVENT_CHANNEL_JOIN: S20JoinConfirm((PNET_JOIN_CNF_EVENT)data2); MG_FreeBuffer(g_s20pmgClient, (void **)&data2); break; case NET_EVENT_CHANNEL_LEAVE: S20LeaveIndication(LOWORD(data1), (UINT)data2); break; case NET_EVENT_DATA_RECEIVED: S20SendIndication((PNET_SEND_IND_EVENT)data2); break; case NET_FLOW: // // Handle the feedback event. // S20Flow((UINT)data1, (UINT)data2); break; case CMS_NEW_CALL: if (g_asSession.scState == SCS_INIT) { // // This happens when (a) a new real call is started // (b) creating a new share in a call fails, so we want to // then try to join an existing share. // SCCheckForCMCall(); } break; case CMS_END_CALL: if (g_asSession.callID) { // // AS lock protects g_asSession global fields // TRACE_OUT(("AS LOCK: CMS_END_CALL")); UT_Lock(UTLOCK_AS); g_asSession.gccID = 0; g_asSession.callID = 0; UT_Unlock(UTLOCK_AS); TRACE_OUT(("AS UNLOCK: CMS_END_CALL")); if (g_asSession.scState > SCS_SHAREENDING) { SC_EndShare(); } DCS_NotifyUI(SH_EVT_APPSHARE_READY, FALSE, 0); g_s20BroadcastID = 0; g_s20JoinedLocal = FALSE; g_s20State = S20_INIT; TRACE_OUT(("g_s20State is S20_INIT")); } break; default: processed = FALSE; break; } DebugExitBOOL(S20_UTEventProc, processed); return(processed); } // // FUNCTION: S20AttachUser // // DESCRIPTION: // // Called when we want to attach this sets up the various parameters for // MG_Attach, calls it and handles the return codes from NET. // // PARAMETERS: // // callID - the callID provided by the SC user // // // const NET_FLOW_CONTROL c_S20FlowControl = { // latency { S20_LATENCY_TOP_PRIORITY, S20_LATENCY_HIGH_PRIORITY, S20_LATENCY_MEDIUM_PRIORITY, S20_LATENCY_LOW_PRIORITY }, // stream size { S20_SIZE_TOP_PRIORITY, S20_SIZE_HIGH_PRIORITY, S20_SIZE_MEDIUM_PRIORITY, S20_SIZE_LOW_PRIORITY } }; // // S20CreateOrJoinShare() // Creates a share for the first time or joins an existing one // // Normally, creating a share requires // * registration // * broadcast of S20_CREATE packet // * reception of one S20_RESPOND packet // for the share to be created. However, if we're the top provider, we // assume it's created without waiting for an S20_RESPOND. If something // goes wrong later, it will clean itself up anyway. Then that allows us // to host a conference, share an app, and have it be shared through the // life of the conference, even if remotes call/hang up repeatedly. // BOOL S20CreateOrJoinShare ( UINT what, UINT callID ) { UINT rc = 0; BOOL noFlowControl; NET_FLOW_CONTROL flowControl; DebugEntry(S20CreateOrJoinShare); ASSERT((what == S20_CREATE) || (what == S20_JOIN)); switch (g_s20State) { case S20_INIT: // // Remember what to do when we have attached and joined. // g_s20Pend = what; // // ATTACH the S20 MCS USER // COM_ReadProfInt(DBG_INI_SECTION_NAME, S20_INI_NOFLOWCONTROL, FALSE, &noFlowControl); if (noFlowControl) { WARNING_OUT(("S20 Flow Control is OFF")); ZeroMemory(&flowControl, sizeof(flowControl)); } else { // Set up our target latencies and stream sizes flowControl = c_S20FlowControl; } // // Initiate an attach - the domain equals the callID. // rc = MG_Attach(g_s20pmgClient, callID, &flowControl); if (rc == 0) { // // Make the state change if we succeeded // g_s20State = S20_ATTACH_PEND; TRACE_OUT(("g_s20State is S20_ATTACH_PEND")); } else { // // End the share immediately and no state change. // WARNING_OUT(("MG_Attach of S20 User failed, rc = %u", rc)); g_s20Pend = 0; SC_End(); } break; case S20_ATTACH_PEND: case S20_JOIN_PEND: // // We just need to set the flag in these cases - we will try // to create a share when we have attached and joined our // channel. // g_s20Pend = what; break; case S20_SHARE_PEND: // // If a share is pending but the SC user wants to create // or join again we let them. Multiple outstanding joins are // benign and another create will have a new correlator so the // previous one (and any responses to it) will be obsolete. // // NOTE DELIBERATE FALL THROUGH // // case S20_NO_SHARE: TRACE_OUT(("S20_NO_SHARE")); // // Broadcast a S20CREATE packet. // if (what == S20_CREATE) { g_s20ShareCorrelator = S20NewCorrelator(); TRACE_OUT(("CP CREATE %lu %d", g_s20ShareCorrelator, 0)); rc = S20FlushAndSendControlPacket(what, g_s20ShareCorrelator, 0, NET_TOP_PRIORITY); } else { g_s20ShareCorrelator = 0; TRACE_OUT(("CP JOIN %lu %d", 0, 0)); rc = S20FlushAndSendControlPacket(what, 0, 0, NET_TOP_PRIORITY); } TRACE_OUT(("S20FlushAndSendControlPacket %u", rc)); if (rc == 0) { // // Switch state. // g_s20State = S20_SHARE_PEND; TRACE_OUT(("g_s20State is S20_SHARE_PEND")); // // Assume success right away when creating the share. We'll // hear back in a bit if there's a problem. // if (what == S20_CREATE) { // Don't check for top provider, assume success always. TRACE_OUT(("S20: Creating share, assume success")); // // LAURABU -- IF THIS CAUSES PROBLEMS, fall back to // checking for one person only in call. // if (!SC_Start(g_s20LocalID)) { WARNING_OUT(("S20CreateOrJoin: couldn't start share")); SC_End(); } else { g_s20State = S20_IN_SHARE; TRACE_OUT(("g_s20State is S20_IN_SHARE")); } } } else { // // Something failed so we will just forget about the share. // WARNING_OUT(("Failed to create share")); if (what == S20_CREATE) { SC_End(); } } break; default: ERROR_OUT(("Invalid state %u for %u", g_s20State, what)); } DebugExitBOOL(S20CreateOrJoinShare, (rc == 0)); return(rc == 0); } // // FUNCTION: S20LeaveOrEndShare // // DESCRIPTION: // // Handles processing a S20_LeaveShare or a S20_EndShare call. // // PARAMETERS: // // what - what to do (the protocol packet type corresponding to the // action). // // RETURNS: NONE // // void S20LeaveOrEndShare(void) { UINT what; DebugEntry(S20LeaveOrEndShare); // // The share is destroyed whenever the creator leaves. Nobody else // can end it. // if (S20_GET_CREATOR(g_s20ShareCorrelator) == g_s20LocalID) { what = S20_END; } else { what = S20_LEAVE; } ASSERT(what == S20_LEAVE || what == S20_END); switch (g_s20State) { case S20_ATTACH_PEND: case S20_JOIN_PEND: // // We just need to reset the pending flags here - no state // change required. // g_s20Pend = 0; break; case S20_IN_SHARE: case S20_SHARE_PEND: TRACE_OUT(("S20_SHARE_PEND")); // // Now try and make and send the appropriate control packet. // TRACE_OUT(("CP %u %u %d", what, g_s20ShareCorrelator, 0)); S20FlushSendOrQueueControlPacket(what, g_s20ShareCorrelator, 0, NET_TOP_PRIORITY); // // Make the SHARE_ENDED callback. // SC_End(); break; default: WARNING_OUT(("invalid state %d for %d", g_s20State, what)); break; } DebugExitVOID(S20LeaveOrEndShare); } // // FUNCTION: S20MakeControlPacket // // DESCRIPTION: // // Attempts to allocate and construct a S20 control packet. // // PARAMETERS: // // what - which type of packet // // correlator - the correlator to place in the packet // // who - the target party (if what is a S20_DELETE) or the originator (if // what is S20_RESPOND) // // ppPacket - where to return a pointer to the packet. // // pLength - where to return the length of the packet. // // priority - priority of packet to make // // RETURNS: // // UINT S20MakeControlPacket ( UINT what, UINT correlator, UINT who, PS20PACKETHEADER * ppPacket, LPUINT pcbPacketSize, UINT priority ) { UINT rc; BOOL fPutNameAndCaps; UINT cbPacketSize; UINT personNameLength; PS20PACKETHEADER pS20Packet = NULL; LPBYTE pData; DebugEntry(S20MakeControlPacket); // // Assume success // rc = 0; // // Work out how big the packet needs to be. Start with the fixed // length then add in capabilities and our name (if they are required). // switch (what) { case S20_CREATE: cbPacketSize = sizeof(S20CREATEPACKET) - 1; fPutNameAndCaps = TRUE; break; case S20_JOIN: cbPacketSize = sizeof(S20JOINPACKET) - 1; fPutNameAndCaps = TRUE; break; case S20_RESPOND: cbPacketSize = sizeof(S20RESPONDPACKET) - 1; fPutNameAndCaps = TRUE; break; case S20_DELETE: cbPacketSize = sizeof(S20DELETEPACKET) - 1; fPutNameAndCaps = FALSE; break; case S20_LEAVE: cbPacketSize = sizeof(S20LEAVEPACKET); fPutNameAndCaps = FALSE; break; case S20_END: cbPacketSize = sizeof(S20ENDPACKET) - 1; fPutNameAndCaps = FALSE; break; case S20_COLLISION: cbPacketSize = sizeof(S20COLLISIONPACKET); fPutNameAndCaps = FALSE; break; default: ERROR_OUT(("BOGUS S20 packet %u", what)); break; } if (fPutNameAndCaps) { ASSERT(g_asSession.gccID); ASSERT(g_asSession.cchLocalName); // // The name data is always dword aligned (including the NULL) // personNameLength = DC_ROUND_UP_4(g_asSession.cchLocalName+1); cbPacketSize += personNameLength + sizeof(g_cpcLocalCaps); } // // Now try to allocate a buffer for this. // rc = MG_GetBuffer( g_s20pmgClient, cbPacketSize, (NET_PRIORITY)priority, g_s20BroadcastID, (void **)&pS20Packet ); if (rc != 0) { TRACE_OUT(("MG_GetBuffer failed; can't send S20 control packet")); DC_QUIT; } pS20Packet->packetType = (TSHR_UINT16)what | S20_ALL_VERSIONS; pS20Packet->user = g_s20LocalID; // // This will point to where we need to stuff the name and/or // capabilities. // pData = NULL; // // Now do the packet dependant fields. // switch (what) { case S20_CREATE: { ASSERT(fPutNameAndCaps); ((PS20CREATEPACKET)pS20Packet)->correlator = correlator; ((PS20CREATEPACKET)pS20Packet)->lenName = (TSHR_UINT16)personNameLength; ((PS20CREATEPACKET)pS20Packet)->lenCaps = (TSHR_UINT16)sizeof(g_cpcLocalCaps); pData = ((PS20CREATEPACKET)pS20Packet)->data; } break; case S20_JOIN: { ASSERT(fPutNameAndCaps); ((PS20JOINPACKET)pS20Packet)->lenName = (TSHR_UINT16)personNameLength; ((PS20JOINPACKET)pS20Packet)->lenCaps = (TSHR_UINT16)sizeof(g_cpcLocalCaps); pData = ((PS20JOINPACKET)pS20Packet)->data; } break; case S20_RESPOND: { ASSERT(fPutNameAndCaps); ((PS20RESPONDPACKET)pS20Packet)->correlator = correlator; ((PS20RESPONDPACKET)pS20Packet)->originator = (TSHR_UINT16)who; ((PS20RESPONDPACKET)pS20Packet)->lenName = (TSHR_UINT16)personNameLength; ((PS20RESPONDPACKET)pS20Packet)->lenCaps = (TSHR_UINT16)sizeof(g_cpcLocalCaps); pData = ((PS20RESPONDPACKET)pS20Packet)->data; } break; case S20_DELETE: { ASSERT(!fPutNameAndCaps); ((PS20DELETEPACKET)pS20Packet)->correlator = correlator; ((PS20DELETEPACKET)pS20Packet)->target = (TSHR_UINT16)who; ((PS20DELETEPACKET)pS20Packet)->lenName = 0; } break; case S20_LEAVE: { ASSERT(!fPutNameAndCaps); ((PS20LEAVEPACKET)pS20Packet)->correlator = correlator; } break; case S20_END: { ASSERT(!fPutNameAndCaps); ((PS20ENDPACKET)pS20Packet)->correlator = correlator; ((PS20ENDPACKET)pS20Packet)->lenName = 0; } break; case S20_COLLISION: { ASSERT(!fPutNameAndCaps); ((PS20COLLISIONPACKET)pS20Packet)->correlator = correlator; } break; default: { ERROR_OUT(("Invalid type %u", what)); } break; } // // Now we can copy in the name and capabilities. // if (fPutNameAndCaps) { lstrcpy((LPSTR)pData, g_asSession.achLocalName); // The local name is always null-terminated (truncated to fit in 48 bytes inc. null) pData += personNameLength; memcpy(pData, &g_cpcLocalCaps, sizeof(g_cpcLocalCaps)); // // FILL IN GCC-ID HERE; the local caps are shared but the local // person entity in the share doesn't exist yet. // ((CPCALLCAPS *)pData)->share.gccID = g_asSession.gccID; } // // Return the packet and length. // *ppPacket = pS20Packet; *pcbPacketSize = cbPacketSize; DC_EXIT_POINT: DebugExitDWORD(S20MakeControlPacket, rc); return(rc); } // // FUNCTION: S20FlushSendOrQueueControlPacket // // DESCRIPTION: // // Attempts to flush any queued S20 control packets and then attempte to // send a S20 control packet. If this fails the queue the packet (the // actual packet is freed. // // PARAMETERS: // // what - which type of packet // // correlator - the correlator to place in the packet // // who - the target party (if what is a S20_DELETE) or the originator (if // what is S20_RESPOND) // // priority - priority to send packet at // // RETURNS: NONE // // UINT S20FlushSendOrQueueControlPacket( UINT what, UINT correlator, UINT who, UINT priority) { UINT rc; DebugEntry(S20FlushSendOrQueueControlPacket); rc = S20FlushAndSendControlPacket(what, correlator, who, priority); if (rc != 0) { // Let's queue this packet if (((g_s20ControlPacketQTail + 1) % S20_MAX_QUEUED_CONTROL_PACKETS) == g_s20ControlPacketQHead) { // // There is no more space in the control packet queue. We will // discard everything from it and say the share ended because of // a network error (if we're in a share). // ERROR_OUT(("No more space in control packet queue")); } else { S20CONTROLPACKETQENTRY *p = &(g_s20ControlPacketQ[g_s20ControlPacketQTail]); p->who = who; p->correlator = correlator; p->what = what; p->priority = priority; g_s20ControlPacketQTail = (g_s20ControlPacketQTail + 1) % S20_MAX_QUEUED_CONTROL_PACKETS; rc = 0; } } DebugExitDWORD(S20FlushSendOrQueueControlPacket, rc); return rc; } // // FUNCTION: S20FlushAndSendControlPacket // // DESCRIPTION: // // Attempts to flush any queued S20 control packets and then send a S20 // control packet. If sending fails then free the packet. // // PARAMETERS: // // what - which type of packet // // correlator - the correlator to place in the packet // // who - the target party (if what is a S20_DELETE) or the originator (if // what is S20_RESPOND) // // priority - priority to send packet at // // RETURNS: // // UINT S20FlushAndSendControlPacket ( UINT what, UINT correlator, UINT who, UINT priority ) { UINT rc; PS20PACKETHEADER pS20Packet; UINT length; DebugEntry(S20FlushAndSendControlPacket); // // First try to flush. // rc = S20SendQueuedControlPackets(); if (rc != 0) { TRACE_OUT(("S20SendQueuedControlPackets %u", rc)); DC_QUIT; } rc = S20MakeControlPacket(what, correlator, who, &pS20Packet, &length, priority); if (rc != 0) { TRACE_OUT(("S20MakeControlPacket %u", rc)); DC_QUIT; } TRACE_OUT(("CP %u %lu %u sent", what, correlator, who)); rc = S20SendControlPacket(pS20Packet, length, priority); if (rc != 0) { TRACE_OUT(("S20SendControlPacket %u", rc)); DC_QUIT; } DC_EXIT_POINT: DebugExitDWORD(S20FlushAndSendControlPacket, rc); return(rc); } // // FUNCTION: S20SendControlPacket // // DESCRIPTION: // // Attempts to send a S20 control packet. If sending fails then free the // packet. // // PARAMETERS: // // pPacket - pointer to the control packet to send. These are always // broadcast. // // length - length of aforementioned packet. // // priority - priority to send packet at // // RETURNS: // // UINT S20SendControlPacket ( PS20PACKETHEADER pS20Packet, UINT length, UINT priority ) { UINT rc; DebugEntry(S20SendControlPacket); TRACE_OUT(("S20SendControlPacket: sending packet type %x, size %d", pS20Packet->packetType, length)); rc = MG_SendData( g_s20pmgClient, (NET_PRIORITY)priority, g_s20BroadcastID, length, (void **)&pS20Packet ); if (rc != 0) { TRACE_OUT(("MG_SendData %lx", rc)); } if (pS20Packet != NULL) { // // The packet was not freed by the NL - we will do it instead. // MG_FreeBuffer(g_s20pmgClient, (void **)&pS20Packet); } DebugExitDWORD(S20SendControlPacket, rc); return(rc); } // // FUNCTION: S20SendQueuedControlPackets // // DESCRIPTION: // // Sends as many queued packets as possible // // PARAMETERS: // // // RETURNS: // // 0 - all queued packets have been sent. // // UINT S20SendQueuedControlPackets(void) { PS20PACKETHEADER pS20Packet; UINT length; UINT rc; UINT priority; DebugEntry(S20SendQueuedControlPackets); // // Assume success until something fails. // rc = 0; // // While there are packets to send - try to send them // while (g_s20ControlPacketQTail != g_s20ControlPacketQHead) { S20CONTROLPACKETQENTRY *p = &(g_s20ControlPacketQ[g_s20ControlPacketQHead]); priority = p->priority; rc = S20MakeControlPacket(p->what, p->correlator, p->who, &pS20Packet, &length, priority); if (rc != 0) { // // Failed to make the packet - give up. // WARNING_OUT(("S20MakeControlPacket failed error %u", rc)); break; } rc = S20SendControlPacket(pS20Packet, length, priority); if (rc != 0) { // // Failed to send the packet - give up. // break; } // // Succesfully sent the queue packet - move the head of the queue // along one. // g_s20ControlPacketQHead = (g_s20ControlPacketQHead + 1) % S20_MAX_QUEUED_CONTROL_PACKETS; } DebugExitDWORD(S20SendQueuedControlPackets, rc); return(rc); } // // S20AttachConfirm() // // Handles the MCS attach confirmation // void S20AttachConfirm ( NET_UID userId, NET_RESULT result, UINT callID ) { NET_CHANNEL_ID correlator; UINT rc; DebugEntry(S20AttachConfirm); if (g_s20State == S20_ATTACH_PEND) { // // Assume we need to clear up. // rc = NET_RC_S20_FAIL; if (result == NET_RESULT_OK) { // // We're in. Now try to join our channel and remember our // userID. // g_s20LocalID = userId; // // We must join our single member channel for flow control // rc = MG_ChannelJoin(g_s20pmgClient, &correlator, g_s20LocalID); if (rc == 0) { // // Now join the broadcast channel // rc = MG_ChannelJoinByKey(g_s20pmgClient, &correlator, GCC_AS_CHANNEL_KEY); if (rc != 0) { MG_ChannelLeave(g_s20pmgClient, g_s20LocalID); } } if (rc == 0) { // // It worked - make the state change. // g_s20State = S20_JOIN_PEND; TRACE_OUT(("g_s20State is S20_JOIN_PEND")); } else { // // Everything else is some sort of logic error (we will // follow our recovery path). // WARNING_OUT(("ChannelJoin unexpected error %u", rc)); } } if (rc != 0) { // // Something didn't work work out - clear up with a // SHARE_ENDED if a create or join was pending. // if (result == NET_RESULT_OK) { // // The attach succeeded so detach because the join // failed and we want to go back to initialised state. // MG_Detach(g_s20pmgClient); g_s20LocalID = 0; } // // Now make the state change and generate event if // necessary. // g_s20State = S20_INIT; TRACE_OUT(("g_s20State is S20_INIT")); if (g_s20Pend) { g_s20Pend = 0; SC_End(); } } } DebugExitVOID(S20AttachConfirm); } // // S20DetachIndication() // // Handles NET_EVENT_DETACH notification for a user // void S20DetachIndication ( NET_UID userId, UINT callID ) { DebugEntry(S20DetachIndication); // // There are three possibilities here // // 1. We have been forced out. // 2. All remote users have detached. // 3. A remote user has detached. // // 2 is effectively a 3 for each current remote user. We report 1 as a // network error. // if (userId == g_s20LocalID) { // // We have been forced out. // switch (g_s20State) { case S20_IN_SHARE: case S20_SHARE_PEND: case S20_SHARE_STARTING: // // Generate a share ended event. // SC_End(); // FALL THROUGH case S20_NO_SHARE: // // Just revert to init state. // g_s20State = S20_INIT; TRACE_OUT(("g_s20State is S20_INIT")); break; case S20_JOIN_PEND: case S20_ATTACH_PEND: // // Check the join or create pending flags here and if // either one is set then generate a share ended // if (g_s20Pend) { g_s20Pend = 0; SC_End(); } g_s20State = S20_INIT; TRACE_OUT(("g_s20State is S20_INIT")); break; case S20_TERM: case S20_INIT: // // Unusual but not impossible. // TRACE_OUT(("Ignored in state %u", g_s20State)); break; default: ERROR_OUT(("Invalid state %u", g_s20State)); break; } } else { ASSERT(userId != NET_ALL_REMOTES); // // A single remote user has left. // switch (g_s20State) { case S20_IN_SHARE: { // // If we are in a share then issue a PARTY_DELETED event // for the appropriate party if they have been added. // S20MaybeIssuePersonDelete will only issue deletes for // parties which have been added succesfully. // S20MaybeIssuePersonDelete(userId); } break; default: { // // In any other state this makes no difference to us. // TRACE_OUT(("ignored in state %u", g_s20State)); } break; } } DebugExitVOID(S20DetachIndication); } // // FUNCTION: S20JoinConfirm // // DESCRIPTION: // // Handles the NET_EVENT_CHANNEL_JOIN message from the NL // // PARAMETERS: // // pNetEventHeader - pointer to the event // // RETURNS: NONE // // void S20JoinConfirm(PNET_JOIN_CNF_EVENT pJoinConfirm) { UINT rc; DebugEntry(S20JoinConfirm); if (g_s20State == S20_JOIN_PEND) { // // Handle the join completing // if (pJoinConfirm->result == NET_RESULT_OK) { // // We have sucessfully joined, either our single user // channel or our broadcast channel // We detect that both are successful when the g_s20BroadcastID // field is filled in and g_s20JoinedLocal is TRUE // if (pJoinConfirm->channel == g_s20LocalID) { g_s20JoinedLocal = TRUE; TRACE_OUT(("Joined user channel")); } else { // // Store the assigned channel. // g_s20BroadcastID = pJoinConfirm->channel; TRACE_OUT(("Joined channel %u", (UINT)g_s20BroadcastID)); } // // If we have joined both channels then let it rip // if (g_s20JoinedLocal && g_s20BroadcastID) { g_s20State = S20_NO_SHARE; TRACE_OUT(("g_s20State is S20_NO_SHARE")); DCS_NotifyUI(SH_EVT_APPSHARE_READY, TRUE, 0); // // Issue create or join if they are pending. // if (g_s20Pend != 0) { ASSERT(g_s20Pend == S20_JOIN); UINT sPend; sPend = g_s20Pend; g_s20Pend = 0; S20CreateOrJoinShare(sPend, pJoinConfirm->callID); } } } else { ERROR_OUT(("Channel join failed")); // // Clear up by reverting to initialised state. // MG_Detach(g_s20pmgClient); g_s20LocalID = 0; g_s20BroadcastID = 0; g_s20JoinedLocal = FALSE; // // Now make the state change and generate event if // necessary. // g_s20State = S20_INIT; TRACE_OUT(("g_s20State is S20_INIT")); if (g_s20Pend) { g_s20Pend = 0; SC_End(); } } } DebugExitVOID(S20JoinConfirm); } // // FUNCTION: S20LeaveIndication // // DESCRIPTION: // // Handles the NET_EV_LEAVE_INDICATION message from the NL // // PARAMETERS: // // pNetEventHeader - pointer to the event // // RETURNS: NONE // // void S20LeaveIndication ( NET_CHANNEL_ID channelID, UINT callID ) { UINT rc; DebugEntry(S20LeaveIndication); // // A leave indication means we were forced out of a channel. As we // only use one channel this is bound to be terminal and we will // generate appropriate share ending type events and detach (this will // hopefully tell the remote systems we have gone - also we have no // state which is attached but not trying to join so the alternatives // would be to 1) add a new state or 2) try and re-join a channel // immediately we get chucked out. Neither appeals. // switch (g_s20State) { case S20_IN_SHARE: case S20_SHARE_PEND: case S20_SHARE_STARTING: // // Generate a share ended event. // SC_End(); // FALL THROUGH case S20_NO_SHARE: case S20_JOIN_PEND: case S20_ATTACH_PEND: // // Detach from the domain. // MG_Detach(g_s20pmgClient); g_s20LocalID = 0; // // Check the join or create pending flags here and if either // one is set then generate a share ended // if (g_s20Pend) { g_s20Pend = 0; SC_End(); } g_s20State = S20_INIT; TRACE_OUT(("g_s20State is S20_INIT")); break; case S20_TERM: case S20_INIT: // // Unusual but not impossible. // TRACE_OUT(("Ignored in state %u", g_s20State)); break; default: ERROR_OUT(("Invalid state %u", g_s20State)); break; } DebugExitVOID(S20LeaveIndication); } // // S20SendIndication() // // Handles received data notification // void S20SendIndication(PNET_SEND_IND_EVENT pSendIndication) { PS20PACKETHEADER pS20Packet; DebugEntry(S20SendIndication); pS20Packet = (PS20PACKETHEADER)(pSendIndication->data_ptr); // // If App Sharing detaches from the T.120 conference, it will free up // all data indication buffers. We need to check for this condition. // if (NULL != pS20Packet) { if (!(pS20Packet->packetType & S20_ALL_VERSIONS)) { ERROR_OUT(("User is trying to connect from %#hx system", pS20Packet->packetType & 0xF0)); // // This should never happen, but if it does then we assert in the // debug build and quietly fail in the retail build. // ERROR_OUT(("An unsupported version of app sharing joined the conference")); DC_QUIT; } // // Mask out the protocol version // switch (pS20Packet->packetType & S20_PACKET_TYPE_MASK) { case S20_CREATE: S20CreateMsg((PS20CREATEPACKET)pS20Packet); break; case S20_JOIN: S20JoinMsg((PS20JOINPACKET)pS20Packet); break; case S20_RESPOND: S20RespondMsg((PS20RESPONDPACKET)pS20Packet); break; case S20_DELETE: S20DeleteMsg((PS20DELETEPACKET)pS20Packet); break; case S20_LEAVE: S20LeaveMsg((PS20LEAVEPACKET)pS20Packet); break; case S20_END: S20EndMsg((PS20ENDPACKET)pS20Packet); break; case S20_COLLISION: S20CollisionMsg((PS20COLLISIONPACKET)pS20Packet); break; case S20_DATA: S20DataMsg((PS20DATAPACKET)pS20Packet); break; default: ERROR_OUT(("invalid packet %hu", pS20Packet->packetType)); break; } } DC_EXIT_POINT: MG_FreeBuffer(g_s20pmgClient, (void **)&pSendIndication); DebugExitVOID(S20SendIndication); } // // FUNCTION: S20Flow // // DESCRIPTION: // // Handles the NET_FLOW event // // PARAMETERS: // // data1, data2 - the data from the UT event handler // // RETURNS: NONE // // void S20Flow ( UINT priority, UINT newBufferSize ) { DebugEntry(S20Flow); // // We know this is our data channel (it is the only one we flow // control) but if this is not the UPDATE stream, then ignore it. // UPDATEs are low priority. // ASSERT(priority == NET_LOW_PRIORITY); if (g_asSession.pShare != NULL) { TRACE_OUT(("Received flow control notification, new size %lu", newBufferSize)); if (g_asSession.pShare->m_pHost != NULL) { // // First try and improve the LAN performance by sending orders in // large buffers, if we find that the throughput can handle it. // g_asSession.pShare->m_pHost->UP_FlowControl(newBufferSize); // // Adjust the depth which we try to spoil orders to based on // feedback. // g_asSession.pShare->m_pHost->OA_FlowControl(newBufferSize); } // // Tell DCS so that we can skip GDC compression. // This improves responsiveness over high bandwidth links because it // reduces the CPU loading on the sender // g_asSession.pShare->DCS_FlowControl(newBufferSize); } DebugExitVOID(S20Flow); } // // FUNCTION: S20CreateMsg // // DESCRIPTION: // // Handles an incoming create message. // // PARAMETERS: // // pS20Packet - pointer to the create message itself // // RETURNS: NONE // void S20CreateMsg ( PS20CREATEPACKET pS20Packet ) { BOOL rc; DebugEntry(S20CreateMsg); TRACE_OUT(("S20_CREATE from [%d - %s], correlator %x", pS20Packet->header.user, (LPSTR)pS20Packet->data, pS20Packet->correlator)); // // First of all check if the correlator on this CREATE is the same as // our current view of the correlator. This may happen if a sweep // RESPOND overtakes a CREATE - in this case we will create the share // on the RESPOND and this is simply the delayed CREATE arriving now so // we don't need to do anything here. // if (g_s20ShareCorrelator == pS20Packet->correlator) { WARNING_OUT(("Received S20_CREATE from [%d] with bogus correlator %x", pS20Packet->header.user, pS20Packet->correlator)); DC_QUIT; } if ((g_s20State == S20_NO_SHARE) || ((g_s20State == S20_SHARE_PEND) && (g_s20ShareCorrelator == 0))) { // // Either there is no share or we have issued a join. In these // curcumstances we want to try to accept the create message. // // // Remember the share correlator. // g_s20ShareCorrelator = pS20Packet->correlator; // // Start the share // CHECK FOR FAILURE FOR THE FIRST ONE. // rc = SC_Start(g_s20LocalID); if (rc) { g_s20State = S20_SHARE_STARTING; TRACE_OUT(("g_s20State is S20_SHARE_STARTING")); rc = S20MaybeAddNewParty(pS20Packet->header.user, pS20Packet->lenCaps, pS20Packet->lenName, pS20Packet->data); } if (!rc) { // // Something went wrong. Kill the share, this will clean up // everything. // SC_End(); } } else if ((g_s20State == S20_SHARE_PEND) || (g_s20State == S20_SHARE_STARTING) || (g_s20State == S20_IN_SHARE)) { // // Only current share creator should tell other dude there's an // error. // if (S20_GET_CREATOR(g_s20ShareCorrelator) == g_s20LocalID) { // // If we know about a share already then ignore this one. // WARNING_OUT(("Received S20_CREATE from [%d] with correlator %x, share colllision", pS20Packet->header.user, pS20Packet->correlator)); S20FlushSendOrQueueControlPacket(S20_END, pS20Packet->correlator, 0, NET_TOP_PRIORITY); S20FlushSendOrQueueControlPacket(S20_COLLISION, pS20Packet->correlator, 0, NET_TOP_PRIORITY); } } DC_EXIT_POINT: DebugExitVOID(S20CreateMsg); } // // FUNCTION: S20JoinMsg // // DESCRIPTION: // // Handles an incoming join message. // // PARAMETERS: // // pS20Packet - pointer to the join message itself // // RETURNS: NONE // void S20JoinMsg ( PS20JOINPACKET pS20Packet ) { DebugEntry(S20JoinMsg); TRACE_OUT(("S20_JOIN from [%d - %s]", pS20Packet->header.user, (LPSTR)pS20Packet->data)); switch (g_s20State) { case S20_SHARE_PEND: // // If we receive a join when a share is pending which we are // creating then we will try to add the party. If it succeeds // then we will respond to the join as we would if we were in a // share (and we will indeed then be in a share). If it fails // we will delete the joiner. // // If we receive a join when a share is pending because we are // trying to join (ie simultaneous joiners) then we can just // ignore it because a party which is joining a share will send // a respond as soon as they know the correlator for the share // they have succesfully joined. This respond will be ignored // by any parties which saw and added the new party but it will // be seen by any simultaneous joiners and they will then get a // chance to try and add the other joiner. If this fails they // will then do the normal processing for a failure handling a // respond message when we joined a share (ie delete // themselves). // // This will potentially mean that simultaneous joiners will // cause each other to delete themselves when there was room // for one of them in the share - we accept this. // // // Why is the share pending? If the correlator is non-zero // then we are creating a share. // if (g_s20ShareCorrelator != 0) { // // We are creating a share - treat this like a respond. // if (!SC_Start(g_s20LocalID)) { WARNING_OUT(("S20Join: couldn't create share, clean up")); SC_End(); } else { g_s20State = S20_SHARE_STARTING; TRACE_OUT(("g_s20State is S20_SHARE_STARTING")); S20MaybeAddNewParty(pS20Packet->header.user, pS20Packet->lenCaps, pS20Packet->lenName, pS20Packet->data); } } else { // // We are joining a share - simultaneous joiners. // TRACE_OUT(("Simultaneous joiner - ignored for now, expect a respond")); } break; case S20_IN_SHARE: case S20_SHARE_STARTING: { // // When we are in a share we will try and add this person then // give them a respond or a delete depending on what we did. // S20MaybeAddNewParty(pS20Packet->header.user, pS20Packet->lenCaps, pS20Packet->lenName, pS20Packet->data); break; } default: break; } DebugExitVOID(S20JoinMsg); } // // FUNCTION: S20RespondMsg // // DESCRIPTION: // // Handles an incoming respond message. // // PARAMETERS: // // pS20Packet - pointer to the respond message itself // // RETURNS: NONE // void S20RespondMsg ( PS20RESPONDPACKET pS20Packet ) { BOOL rc; DebugEntry(S20RespondMsg); TRACE_OUT(("S20_RESPOND from [%d - %s], for [%d], correlator %x", pS20Packet->header.user, pS20Packet->data, pS20Packet->originator, pS20Packet->correlator)); // // First filter the incoming respond messages as follows. // // If we know what share we are in and this does not have the same // correlator then respond with a delete and don't process any further. // // If the respond is not a response for us (ie we are not the // originator and it is not a sweep-up response (the originator equals // zero) then ignore it. // if ((g_s20ShareCorrelator != 0) && (pS20Packet->correlator != g_s20ShareCorrelator)) { // // Make sure sender knows we're not in this share. // TRACE_OUT(("S20_RESPOND from [%d] with unknown correlator %x", pS20Packet->header.user, pS20Packet->correlator)); S20FlushSendOrQueueControlPacket(S20_LEAVE, pS20Packet->correlator, 0, NET_TOP_PRIORITY); DC_QUIT; } // // Now handle incoming message according to state. // switch (g_s20State) { case S20_SHARE_PEND: if ((pS20Packet->originator == g_s20LocalID) || (pS20Packet->originator == 0)) { // // A respond in share pending and it is for us. First, // start a share. // rc = SC_Start(g_s20LocalID); if (!rc) { SC_End(); } else { g_s20State = S20_SHARE_STARTING; TRACE_OUT(("g_s20State is S20_SHARE_STARTING")); // // Why is the share pending? If the correlator is non-zero // then we are creating a share. // if (g_s20ShareCorrelator == 0) { // // We are joining a share so do nothing if we fail (we // will move back to NO_SHARE state if this happens). // g_s20ShareCorrelator = pS20Packet->correlator; } // // Now try and add this new party. // rc = S20MaybeAddNewParty(pS20Packet->header.user, pS20Packet->lenCaps, pS20Packet->lenName, pS20Packet->data); if (!rc) { // // The responding party has been rejected by us. What // happens next depends on whether we are creating the // share or not. // if (S20_GET_CREATOR(g_s20ShareCorrelator) != g_s20LocalID) { // // We are not creating (ie we are joining) and we // have failed to add a party so end the share // (indicating that we are rejecting the remote // party). // SC_End(); } // // If we were creating the share then there is nothing // to do - just stay in SHARE_STARTING waiting for the // next response. // } } } break; case S20_IN_SHARE: case S20_SHARE_STARTING: // // Who created this share. If it was us then we want to // delete people we reject, otherwise we want to leave if we // reject people. // // // Now try and add this new party. Of course it is entirely // possible that we've already added them at this stage - but // S20MaybeAddNewParty will just pretend to add them and return // if that's the case. // rc = S20MaybeAddNewParty(pS20Packet->header.user, pS20Packet->lenCaps, pS20Packet->lenName, pS20Packet->data); if (!rc) { WARNING_OUT(("Couldn't add [%d] to our share party list", pS20Packet->header.user)); } break; default: break; } DC_EXIT_POINT: DebugExitVOID(S20RespondMsg); } // // FUNCTION: S20DeleteMsg // // DESCRIPTION: // // Handles an incoming delete message. // // PARAMETERS: // // pS20Packet - pointer to the delete message itself // // RETURNS: NONE // void S20DeleteMsg ( PS20DELETEPACKET pS20Packet ) { DebugEntry(S20DeleteMsg); TRACE_OUT(("S20_DELETE from [%d], for [%d], correlator %x", pS20Packet->header.user, pS20Packet->target, pS20Packet->correlator)); // // ONLY SHARE CREATOR can delete people from share // if (!g_s20ShareCorrelator) { WARNING_OUT(("S20_DELETE, ignoring we're not in a share")); DC_QUIT; } if (pS20Packet->target != g_s20LocalID) { // // Not for us, ignore. // DC_QUIT; } if (g_s20ShareCorrelator != pS20Packet->correlator) { WARNING_OUT(("Received S20_DELETE from [%d] with unknown correlator %x", pS20Packet->header.user, pS20Packet->correlator)); S20FlushSendOrQueueControlPacket(S20_LEAVE, pS20Packet->correlator, 0, NET_TOP_PRIORITY); DC_QUIT; } if (S20_GET_CREATOR(g_s20ShareCorrelator) != pS20Packet->header.user) { WARNING_OUT(("Received S20_DELETE from [%d] who did not create share, ignore", pS20Packet->header.user)); DC_QUIT; } // // Now handle incoming messages according to state. // switch (g_s20State) { case S20_SHARE_PEND: case S20_SHARE_STARTING: // // Just tell everyone else we're leaving and then issue a // SHARE_ENDED event. // TRACE_OUT(("CP LEAVE %lu %d", g_s20ShareCorrelator, 0)); S20FlushSendOrQueueControlPacket(S20_LEAVE, g_s20ShareCorrelator, 0, NET_TOP_PRIORITY); // FALL THROUGH case S20_IN_SHARE: SC_End(); g_s20State = S20_NO_SHARE; TRACE_OUT(("g_s20State is S20_NO_SHARE")); break; default: break; } DC_EXIT_POINT: DebugExitVOID(S20DeleteMsg); } // // FUNCTION: S20LeaveMsg // // DESCRIPTION: // // Handles an incoming leave message. // // PARAMETERS: // // pS20Packet - pointer to the leave message itself // // RETURNS: NONE // void S20LeaveMsg(PS20LEAVEPACKET pS20Packet) { DebugEntry(S20LeaveMsg); TRACE_OUT(("S20_LEAVE from [%d], correlator %x", pS20Packet->header.user, pS20Packet->correlator)); if (!g_s20ShareCorrelator) { WARNING_OUT(("S20_LEAVE, ignoring we're not in a share")); DC_QUIT; } if (g_s20ShareCorrelator != pS20Packet->correlator) { WARNING_OUT(("Received S20_LEAVE from [%d] for unknown correlator %x", pS20Packet->header.user, pS20Packet->correlator)); DC_QUIT; } switch (g_s20State) { case S20_IN_SHARE: // // We only need to handle this when we are in a share. // S20MaybeIssuePersonDelete(pS20Packet->header.user); break; default: break; } DC_EXIT_POINT: DebugExitVOID(S20LeaveMsg); } // // FUNCTION: S20EndMsg // // DESCRIPTION: // // Handles an incoming end message. // // PARAMETERS: // // pS20Packet - pointer to the end message itself // // RETURNS: NONE // void S20EndMsg(PS20ENDPACKET pS20Packet) { DebugEntry(S20EndMsg); TRACE_OUT(("S20_END from [%d], correlator %x", pS20Packet->header.user, pS20Packet->correlator)); if (!g_s20ShareCorrelator) { // We don't care WARNING_OUT(("S20_END ignored, not in share")); DC_QUIT; } if (g_s20ShareCorrelator != pS20Packet->correlator) { // // Just discard this. // WARNING_OUT(("Received S20_END from [%d] with unknown correlator %x", pS20Packet->header.user, pS20Packet->correlator)); DC_QUIT; } // // Only the share creator can end the share. // if (S20_GET_CREATOR(g_s20ShareCorrelator) != pS20Packet->header.user) { WARNING_OUT(("Received S20_END from [%d] who did not create share, simply remove from user list.", pS20Packet->header.user)); if (g_s20State == S20_IN_SHARE) { S20MaybeIssuePersonDelete(pS20Packet->header.user); } DC_QUIT; } switch (g_s20State) { case S20_IN_SHARE: case S20_SHARE_PEND: case S20_SHARE_STARTING: // // We just need to generate a share ended event. // SC_End(); g_s20State = S20_NO_SHARE; TRACE_OUT(("g_s20State is S20_NO_SHARE")); break; default: break; } DC_EXIT_POINT: DebugExitVOID(S20EndMsg); } // // S20CollisionMsg() // // DESCRIPTION: // // Handles an incoming collision message. // // PARAMETERS: // // pS20Packet - pointer to the collision message itself // // RETURNS: NONE // void S20CollisionMsg(PS20COLLISIONPACKET pS20Packet) { DebugEntry(S20CollisionMsg); TRACE_OUT(("S20_COLLISION from [%d], correlator %x", pS20Packet->header.user, pS20Packet->correlator)); if (!g_s20ShareCorrelator) { // We don't care WARNING_OUT(("S20_COLLISION ignored, not in share")); DC_QUIT; } if (g_s20ShareCorrelator != pS20Packet->correlator) { // // Just discard this. // WARNING_OUT(("Received S20_COLLISION from [%d] with unknown correlator %x", pS20Packet->header.user, pS20Packet->correlator)); DC_QUIT; } // // If we created our own share, but got a collision from the remote, // then kill our share. // if (S20_GET_CREATOR(g_s20ShareCorrelator) != g_s20LocalID) { TRACE_OUT(("S20_COLLISION ignored, we didn't create share")); DC_QUIT; } switch (g_s20State) { case S20_IN_SHARE: case S20_SHARE_PEND: case S20_SHARE_STARTING: // // We just need to generate a share ended event. // SC_End(); g_s20State = S20_NO_SHARE; TRACE_OUT(("g_s20State is S20_NO_SHARE")); break; default: break; } DC_EXIT_POINT: DebugExitVOID(S20CollisionMsg); } // // FUNCTION: S20DataMsg // // DESCRIPTION: // // Handles an incoming data message. // // PARAMETERS: // // pS20Packet - pointer to the data message itself // // RETURNS: TRUE - free the event, FALSE - do not free the event // void S20DataMsg(PS20DATAPACKET pS20Packet) { DebugEntry(S20DataMsg); ASSERT(!IsBadWritePtr(pS20Packet, sizeof(S20DATAPACKET))); ASSERT(!IsBadWritePtr(pS20Packet, sizeof(S20DATAPACKET) - sizeof(DATAPACKETHEADER) + pS20Packet->dataLength)); // // Check if we're interseted in this data. // if ((pS20Packet->correlator == g_s20ShareCorrelator) && (g_s20State == S20_IN_SHARE) && g_asSession.pShare) { // // Return it. // g_asSession.pShare->SC_ReceivedPacket(pS20Packet); } DebugExitVOID(S20DataMsg); } // // FUNCTION: S20MaybeAddNewParty // // DESCRIPTION: // // If the specified party has not already been added then try to add them // now. // // PARAMETERS: // // userID - the new party's network user ID. // lenCaps - the length of the new party's capabilities. // lenName - the length of the new party's name. // pData - a pointer to the new party's data which contains the name // followed by the capabilities data. // // RETURNS: // BOOL for success // BOOL S20MaybeAddNewParty ( MCSID mcsID, UINT lenCaps, UINT lenName, LPBYTE pData ) { BOOL rc = FALSE; UINT oldState; LPBYTE pCaps = NULL; BOOL memAllocated = FALSE; DebugEntry(S20MaybeAddNewParty); // // If we don't have a share, fail. // if (!g_asSession.pShare) { WARNING_OUT(("No ASShare; ignoring add party for [%d]", mcsID)); DC_QUIT; } // // Check if this party has already been added. // if (g_asSession.pShare->SC_ValidateNetID(mcsID, NULL)) { TRACE_OUT(("S20MaybeAddNewParty: already added %u", mcsID)); rc = TRUE; DC_QUIT; } // // We need the caps structure to be 4-byte aligned. It currently // follows a variable-length name string and may therefore not be // aligned. If it is not aligned, we allocate an aligned buffer and // copy it there. // if (0 != (((UINT_PTR)pData + lenName) % 4)) { TRACE_OUT(("Capabilities data is unaligned - realigning")); // // Get a 4-byte aligned buffer for the capabilities data. // pCaps = new BYTE[lenCaps]; if (!pCaps) { ERROR_OUT(("Could not allocate %u bytes for aligned caps.", lenCaps)); DC_QUIT; } // // Flag so we know to free the memory later. // memAllocated = TRUE; // // Copy the caps data into our 4-byte aligned memory block. // memcpy(pCaps, (pData + lenName), lenCaps); } else { // // The capabilities data is already aligned so we don't need to // move it. // pCaps = pData + lenName; } // // Make sure we are in a share before we issue person add events. // oldState = g_s20State; g_s20State = S20_IN_SHARE; TRACE_OUT(("g_s20State is S20_IN_SHARE")); // // Attempt to add the new party. // rc = g_asSession.pShare->SC_PartyAdded(mcsID, (LPSTR)pData, lenCaps, pCaps); if (rc) { // // The new party has been accepted so send a response packet. Do // this at ALL priorities, so it gets there before any type of data // at one particular priority. // TRACE_OUT(("CP RESPOND %lu %d", g_s20ShareCorrelator, 0)); S20FlushSendOrQueueControlPacket(S20_RESPOND, g_s20ShareCorrelator, mcsID, NET_TOP_PRIORITY | NET_SEND_ALL_PRIORITIES); } else { g_asSession.pShare->SC_PartyDeleted(mcsID); // // Reset the state back to what it was if we failed. // g_s20State = oldState; TRACE_OUT(("g_s20State is %u", g_s20State)); if (S20_GET_CREATOR(g_s20ShareCorrelator) == g_s20LocalID) { // // The new party has been rejected so send a delete packet. // TRACE_OUT(("CP DELETE %lu %u", g_s20ShareCorrelator, mcsID)); S20FlushSendOrQueueControlPacket(S20_DELETE, g_s20ShareCorrelator, mcsID, NET_TOP_PRIORITY); } } DC_EXIT_POINT: // // Free memory used to store aligned caps. // if (memAllocated) { delete[] pCaps; } DebugExitBOOL(S20MaybeAddNewParty, rc); return(rc); } // // FUNCTION: S20NewCorrelator // // DESCRIPTION: // // Returns a new correlator for us to use when we are creating a share. // This is a combination of our mcsID (low 16 bits in Intel format) and // a generation count (high 16 bits in Intel format). // // PARAMETERS: NONE // // RETURNS: the new correlator // // UINT S20NewCorrelator(void) { UINT correlator; DebugEntry(S20NewCorrelator); g_s20Generation++; correlator = g_s20LocalID | (((UINT)(g_s20Generation & 0xFFFF)) << 16); DebugExitDWORD(S20NewCorrelator, correlator); return(correlator); } // // FUNCTION: S20MaybeIssuePersonDelete // // DESCRIPTION: // // If the supplied person is in the share then issue a PARTY_DELETED event // for them. // // PARAMTERS: // // mcsID - a network personID // // reason - the reason code to use // // RETURNS: NONE // // void S20MaybeIssuePersonDelete(MCSID mcsID) { DebugEntry(S20MaybeIssuePersonDelete); if (g_asSession.pShare) { g_asSession.pShare->SC_PartyDeleted(mcsID); } // // HET will kill the share if there aren't any hosts left. So we // don't need to do anything here. // DebugExitVOID(S20MaybeIssuePersonDelete); } // // FUNCTION: S20StreamToS20Priority // // DESCRIPTION: // // Converts a stream ID into a NET priority // // PARAMETERS: // // streamID - the stream ID. // // RETURNS: the priority // // const NET_PRIORITY c_StreamS20Priority[NUM_PROT_STR - 1] = { NET_LOW_PRIORITY, // PROT_STR_UPDATES NET_MEDIUM_PRIORITY, // PROT_STR_MISC NET_MEDIUM_PRIORITY, // PROT_STR_UNUSED NET_MEDIUM_PRIORITY, // PROT_STR_INPUT }; NET_PRIORITY S20StreamToS20Priority(UINT streamID) { NET_PRIORITY priority; DebugEntry(S20StreamToS20Priority); ASSERT(streamID > PROT_STR_INVALID); ASSERT(streamID < NUM_PROT_STR); ASSERT(streamID != PROT_STR_UNUSED); priority = c_StreamS20Priority[streamID - 1]; DebugExitDWORD(S20StreamToS20Priority, priority); return(priority); }