private void FlushReceivingQueue() { if (this.mReceivingSemaphore.WaitOne(0) == true) { // handle required packets while (this.mPacketizer.PacketCount > 0 && this.mPacketReceiveCallback != null) { try { // unmarshal the packet PyDataType packet = Unmarshal.ReadFromByteArray(this.mPacketizer.PopItem()); #if DEBUG this.mPacketLog.Trace(PrettyPrinter.FromDataType(packet)); #endif // and invoke the callback for the packet handling if it is present this.mPacketReceiveCallback.Invoke(packet); } catch (Exception e) { this.HandleException(e); } } // finally free the receiving semaphore this.mReceivingSemaphore.Release(); } // semaphore not acquired, there's something already sending data, so we're sure the data will get there eventually }
/// <summary> /// Sends a PyObject through this socket /// </summary> /// <param name="packet">The packet data to send</param> public void Send(PyDataType packet) { #if DEBUG this.mPacketLog.Trace(PrettyPrinter.FromDataType(packet)); #endif MemoryStream stream = new MemoryStream(); BinaryWriter writer = new BinaryWriter(stream); // marshal the packet first byte[] encodedPacket = PythonTypes.Marshal.Marshal.ToByteArray(packet); // compress the packet if it exceeds the maximum size if (encodedPacket.Length > Constants.Network.MAX_PACKET_SIZE) { encodedPacket = ZlibHelper.Compress(encodedPacket); } // write the size to the stream writer.Write(encodedPacket.Length); // finally copy the packet buffer writer.Write(encodedPacket); // after processing the whole packet queue the actual data this.Send(stream.ToArray()); }
/// <summary> /// Sends a PyObject through this socket /// </summary> /// <param name="packet">The packet data to send</param> public void Send(PyDataType packet) { #if DEBUG this.mPacketLog.Trace(PrettyPrinter.FromDataType(packet)); #endif // marshal the packet first byte[] encodedPacket = PythonTypes.Marshal.Marshal.ToByteArray(packet); // compress the packet if it exceeds the maximum size if (encodedPacket.Length > Constants.Network.MAX_PACKET_SIZE) { encodedPacket = ZlibHelper.Compress(encodedPacket); } // generate the final buffer byte[] packetBuffer = new byte[encodedPacket.Length + sizeof(int)]; // write the packet size and the buffer to the new buffer Buffer.BlockCopy(BitConverter.GetBytes(encodedPacket.Length), 0, packetBuffer, 0, sizeof(int)); Buffer.BlockCopy(encodedPacket, 0, packetBuffer, sizeof(int), encodedPacket.Length); // after processing the whole packet queue the actual data this.Send(packetBuffer); }
private void HandleCallReq(PyPacket packet, Client client) { PyTuple callInfo = ((packet.Payload[0] as PyTuple)[1] as PySubStream).Stream as PyTuple; string call = callInfo[1] as PyString; PyTuple args = callInfo[2] as PyTuple; PyDictionary sub = callInfo[3] as PyDictionary; PyDataType callResult = null; PyAddressClient source = packet.Source as PyAddressClient; string destinationService = null; CallInformation callInformation; if (packet.Destination is PyAddressAny destAny) { destinationService = destAny.Service; } else if (packet.Destination is PyAddressNode destNode) { destinationService = destNode.Service; if (destNode.NodeID != Container.NodeID) { Log.Fatal( "Received a call request for a node that is not us, did the ClusterController get confused or something?!" ); return; } } callInformation = new CallInformation { Client = client, CallID = source.CallID, NamedPayload = sub, PacketType = packet.Type, Service = destinationService, From = packet.Source, To = packet.Destination }; try { if (destinationService == null) { if (callInfo[0] is PyString == false) { Log.Fatal("Expected bound call with bound string, but got something different"); return; } string boundString = callInfo[0] as PyString; // parse the bound string to get back proper node and bound ids Match regexMatch = Regex.Match(boundString, "N=([0-9]+):([0-9]+)"); if (regexMatch.Groups.Count != 3) { Log.Fatal($"Cannot find nodeID and boundID in the boundString {boundString}"); return; } int nodeID = int.Parse(regexMatch.Groups[1].Value); int boundID = int.Parse(regexMatch.Groups[2].Value); if (nodeID != this.Container.NodeID) { Log.Fatal("Got bound service call for a different node"); // TODO: MIGHT BE A GOOD IDEA TO RELAY THIS CALL TO THE CORRECT NODE // TODO: INSIDE THE NETWORK, AT LEAST THAT'S WHAT CCP IS DOING BASED // TODO: ON THE CLIENT'S CODE... NEEDS MORE INVESTIGATION return; } #if DEBUG CallLog.Trace("Payload"); CallLog.Trace(PrettyPrinter.FromDataType(args)); CallLog.Trace("Named payload"); CallLog.Trace(PrettyPrinter.FromDataType(sub)); #endif callResult = this.BoundServiceManager.ServiceCall( boundID, call, args, callInformation ); #if DEBUG ResultLog.Trace("Result"); ResultLog.Trace(PrettyPrinter.FromDataType(callResult)); #endif } else { Log.Trace($"Calling {destinationService}::{call}"); #if DEBUG CallLog.Trace("Payload"); CallLog.Trace(PrettyPrinter.FromDataType(args)); CallLog.Trace("Named payload"); CallLog.Trace(PrettyPrinter.FromDataType(sub)); #endif callResult = this.ServiceManager.ServiceCall( destinationService, call, args, callInformation ); #if DEBUG ResultLog.Trace("Result"); ResultLog.Trace(PrettyPrinter.FromDataType(callResult)); #endif } this.SendCallResult(callInformation, callResult); } catch (PyException e) { this.SendException(callInformation, e); } catch (ProvisionalResponse provisional) { this.SendProvisionalResponse(callInformation, provisional); } }
public PyDataType JoinChannels(PyList channels, PyInteger role, CallInformation call) { int callerCharacterID = call.Client.EnsureCharacterIsSelected(); PyList result = new PyList(); foreach (PyDataType channel in channels) { int channelID; string channelType; int? entityID; PyDataType channelIDExtended = null; try { this.ParseChannelIdentifier(channel, out channelID, out channelType, out entityID); } catch (InvalidDataException) { throw new LSCCannotJoin("The specified channel cannot be found: " + PrettyPrinter.FromDataType(channel)); } if (channelType == ChatDB.CHANNEL_TYPE_NORMAL) { channelIDExtended = channelID; } else { channelIDExtended = new PyTuple(1) { [0] = new PyTuple(2) { [0] = channelType, [1] = entityID } }; } // send notifications only on channels that should be receiving notifications // we don't want people in local to know about players unless they talk there if (channelType != ChatDB.CHANNEL_TYPE_REGIONID && channelType != ChatDB.CHANNEL_TYPE_CONSTELLATIONID && channelType != ChatDB.CHANNEL_TYPE_SOLARSYSTEMID2) { PyDataType notification = GenerateLSCNotification("JoinChannel", channelIDExtended, new PyTuple(0), call.Client); if (channelType == ChatDB.CHANNEL_TYPE_NORMAL) { if (channelID < ChatDB.MIN_CHANNEL_ENTITY_ID) { // get users in the channel that are online now PyList characters = this.DB.GetOnlineCharsOnChannel(channelID); // notify them all call.Client.ClusterConnection.SendNotification("OnLSC", "charid", characters, notification); } } else { // notify all players on the channel call.Client.ClusterConnection.SendNotification("OnLSC", channelType, new PyDataType [] { entityID }, notification); } } try { result.Add( this.GetChannelInformation( channelType, channelID, entityID, callerCharacterID, channelIDExtended, call ) ); } catch (Exception e) { // most of the time this indicates a destroyed channel // so build a destroy notification and let the client know this channel // can be removed from it's lists if (channelType == ChatDB.CHANNEL_TYPE_NORMAL && channelID != entityID) { // notify everyone in the channel only when it should PyDataType notification = GenerateLSCNotification("DestroyChannel", channelID, new PyTuple(0), call.Client); // notify all characters in the channel call.Client.ClusterConnection.SendNotification("OnLSC", "charid", callerCharacterID, call.Client, notification); } Log.Error($"LSC could not get channel information. Error: {e.Message}"); } } return(result); }