Exemplo n.º 1
0
        public void NotifyByCharacterID(PyPacket packet, PyAddressBroadcast destination)
        {
            lock (this.Clients)
            {
                PyList idlist = destination.IDsOfInterest;

                foreach (PyDataType idData in idlist)
                {
                    PyInteger id = idData as PyInteger;

                    foreach (KeyValuePair <long, ClientConnection> entry in this.Clients)
                    {
                        if (entry.Value.CharacterID == id)
                        {
                            // use the key instead of AccountID as this should be faster
                            packet.UserID = entry.Key;
                            // change the ids of interest to hide the character's we've notified
                            destination.IDsOfInterest = new PyDataType[] { id };
                            // queue the packet for the user
                            entry.Value.Socket.Send(packet);
                        }
                    }
                }
            }
        }
Exemplo n.º 2
0
        private void ReceivePacketCallback(PyDataType input)
        {
            Log.Debug("Processing packet from node");

            PyPacket packet = input;

            if (packet.Type == PyPacket.PacketType.CALL_RSP || packet.Type == PyPacket.PacketType.ERRORRESPONSE)
            {
                if (packet.Destination is PyAddressClient)
                {
                    Log.Trace($"Sending packet to client {packet.UserID}");
                    this.ConnectionManager.NotifyClient((int)(packet.UserID), packet);
                }
                else if (packet.Destination is PyAddressNode address)
                {
                    Log.Trace($"Sending packet to node {address.NodeID}");
                    this.ConnectionManager.NotifyNode((int)(address.NodeID), packet);
                }
                else if (packet.Destination is PyAddressBroadcast)
                {
                    Log.Error("Broadcast packets not supported yet");
                }

                // TODO: Handle Broadcast packets
            }
            else
            {
                Log.Error($"Wrong packet name: {packet.TypeString}");
            }
        }
Exemplo n.º 3
0
        public void SendProvisionalResponse(CallInformation answerTo, ProvisionalResponse response)
        {
            PyPacket result = new PyPacket(PyPacket.PacketType.CALL_RSP);

            // ensure destination has clientID in it
            PyAddressClient source = answerTo.From as PyAddressClient;

            source.ClientID = answerTo.Client.AccountID;
            // switch source and dest
            result.Source      = answerTo.To;
            result.Destination = source;

            result.UserID      = source.ClientID;
            result.Payload     = new PyTuple(0);
            result.OutOfBounds = new PyDictionary
            {
                ["provisional"] = new PyTuple(3)
                {
                    [0] = response.Timeout, // macho timeout in seconds
                    [1] = response.EventID,
                    [2] = response.Arguments
                }
            };

            this.Socket.Send(result);
        }
Exemplo n.º 4
0
        private void ReceiveNormalPacketCallback(PyDataType ar)
        {
            PyPacket packet = ar;

            this.ClientManager.TryGetClient(packet.UserID, out Client client);

            switch (packet.Type)
            {
            case PyPacket.PacketType.CALL_REQ:
                this.HandleCallReq(packet, client);
                break;

            case PyPacket.PacketType.SESSIONCHANGENOTIFICATION:
                this.HandleSessionChangeNotification(packet, client);
                break;

            case PyPacket.PacketType.PING_REQ:
                this.HandlePingReq(packet, client);
                break;

            case PyPacket.PacketType.CALL_RSP:
                this.HandleCallRes(packet, client);
                break;

            case PyPacket.PacketType.NOTIFICATION:
                this.HandleNotification(packet, client);
                break;
            }

            // send any notification that might be pending
            client?.SendPendingNotifications();
        }
Exemplo n.º 5
0
        private void HandleNotification(PyPacket packet)
        {
            if (packet.Destination is PyAddressBroadcast == false)
            {
                Log.Error("Received a notification that is not a broadcast...");
                return;
            }

            PyAddressBroadcast destination = packet.Destination as PyAddressBroadcast;

            if (packet.UserID != -1)
            {
                Log.Trace($"Relaying notification to client {packet.UserID}");

                this.ConnectionManager.NotifyClient((int)packet.UserID, packet);
                return;
            }

            // special situation, the ClusterController has to take care of fullfiling the proper information
            // in the packet, like UserID
            switch (destination.IDType)
            {
            case "solarsystemid2":
                this.ConnectionManager.NotifyBySolarSystemID2(packet, destination);
                break;

            case "constellationid":
                this.ConnectionManager.NotifyByConstellationID(packet, destination);
                break;

            case "corpid":
                this.ConnectionManager.NotifyByCorporationID(packet, destination);
                break;

            case "regionid":
                this.ConnectionManager.NotifyByRegionID(packet, destination);
                break;

            case "charid":
                this.ConnectionManager.NotifyByCharacterID(packet, destination);
                break;

            case "stationid":
                this.ConnectionManager.NotifyByStationID(packet, destination);
                break;

            case "allianceid":
                this.ConnectionManager.NotifyByAllianceID(packet, destination);
                break;

            case "nodeid":
                this.ConnectionManager.NotifyByNodeID(packet, destination);
                break;

            // TODO: IMPLEMENT OTHER NOTIFICATION ID TYPES BASED ON THE CLIENT CODE IF THEY'RE ACTUALLY USEFUL
            default:
                Log.Error($"Unexpected broadcast with idtype {destination.IDType.Value} and negative userID (autofill by ClusterController)");
                break;
            }
        }
Exemplo n.º 6
0
        /// <summary>
        /// Creates a session change notification including only the last changes to the session
        /// </summary>
        /// <param name="container">Information about the current node the client is in</param>
        /// <returns>The packet ready to be sent</returns>
        private PyPacket CreateEmptySessionChange(NodeContainer container)
        {
            // Fill all the packet data, except the dest/source
            SessionChangeNotification scn = new SessionChangeNotification
            {
                Changes = Session.GenerateSessionChange()
            };

            if (scn.Changes.Length == 0)
            {
                // Nothing to do
                return(null);
            }

            // add ourselves as nodes of interest
            // TODO: DETECT NODE OF INTEREST BASED ON THE SERVER THAT HAS THE SOLAR SYSTEM LOADED IN
            scn.NodesOfInterest.Add(container.NodeID);

            PyPacket packet = new PyPacket(PyPacket.PacketType.SESSIONCHANGENOTIFICATION)
            {
                Source      = new PyAddressNode(container.NodeID),
                Destination = new PyAddressClient(this.Session["userid"] as PyInteger),
                UserID      = this.Session["userid"] as PyInteger,
                Payload     = scn,
                OutOfBounds = new PyDictionary()
                {
                    { "channel", "sessionchange" }
                }
            };

            return(packet);
        }
Exemplo n.º 7
0
        public PyPacket CreateEmptySessionChange()
        {
            // Fill all the packet data, except the dest/source
            SessionChangeNotification scn = new SessionChangeNotification
            {
                Changes = Session.GenerateSessionChange()
            };

            if (scn.Changes.Length == 0)
            {
                // Nothing to do
                return(null);
            }

            PyPacket packet = new PyPacket(PyPacket.PacketType.SESSIONCHANGENOTIFICATION)
            {
                UserID      = this.Session["userid"] as PyInteger,
                Payload     = scn,
                OutOfBounds = new PyDictionary
                {
                    ["channel"] = "sessionchange"
                }
            };

            return(packet);
        }
Exemplo n.º 8
0
        private void ReceivePacketCallback(PyDataType input)
        {
            Log.Debug("Processing packet from node");

            PyPacket packet = input;

            // alter the ping responses from nodes to add the extra required information
            if (packet.Type == PyPacket.PacketType.PING_RSP)
            {
                HandlePingRsp(packet);
            }

            switch (packet.Type)
            {
            // relay packet if needed
            case PyPacket.PacketType.CALL_RSP:
            case PyPacket.PacketType.CALL_REQ:
            case PyPacket.PacketType.ERRORRESPONSE:
            case PyPacket.PacketType.PING_RSP:
                this.RelayPacket(packet);
                break;

            case PyPacket.PacketType.SESSIONCHANGENOTIFICATION:
                this.HandleSessionChangeNotification(packet);
                break;

            case PyPacket.PacketType.NOTIFICATION:
                this.HandleNotification(packet);
                break;

            default:
                Log.Error($"Wrong packet name: {packet.TypeString}");
                break;
            }
        }
Exemplo n.º 9
0
        public PyDataType SetSessionChangeDestination(PyPacket packet)
        {
            packet.Source      = new PyAddressNode(Network.PROXY_NODE_ID, 0);
            packet.Destination = new PyAddressClient(this.Session["userid"] as PyInteger, 0);

            return(packet);
        }
Exemplo n.º 10
0
        public PyPacket CreateEmptySessionChange()
        {
            // Fill all the packet data, except the dest/source
            SessionChangeNotification scn = new SessionChangeNotification();

            scn.changes = Session.EncodeChanges();

            if (scn.changes.Dictionary.Count == 0)
            {
                // Nothing to do
                return(null);
            }

            Dictionary <int, Connection> nodes = ConnectionManager.Nodes;

            // Add all the nodeIDs
            foreach (KeyValuePair <int, Connection> node in nodes)
            {
                scn.nodesOfInterest.Items.Add(new PyInt(node.Key));
            }

            PyPacket p = new PyPacket();

            p.type_string = "macho.SessionChangeNotification";
            p.type        = Macho.MachoNetMsg_Type.SESSIONCHANGENOTIFICATION;

            p.userID = (uint)AccountID;

            p.payload = scn.Encode().As <PyTuple>();

            p.named_payload = new PyDict();
            p.named_payload.Set("channel", new PyString("sessionchange"));

            return(p);
        }
Exemplo n.º 11
0
        public PyDataType SetSessionChangeDestination(PyPacket packet, int node)
        {
            packet.Source      = new PyAddressNode(1, 0);
            packet.Destination = new PyAddressNode(node, 0);

            return(packet);
        }
Exemplo n.º 12
0
        public void SendException(CallInformation answerTo, PyDataType content)
        {
            // build a new packet with the correct information
            PyPacket result = new PyPacket(PyPacket.PacketType.ERRORRESPONSE);

            // ensure destination has clientID in it
            PyAddressClient source = answerTo.From as PyAddressClient;

            source.ClientID = answerTo.Client.AccountID;
            // switch source and dest
            result.Source      = answerTo.To;
            result.Destination = source;

            result.UserID  = source.ClientID;
            result.Payload = new PyTuple(3)
            {
                [0] = (int)answerTo.PacketType,
                [1] = (int)MachoErrorType.WrappedException,
                [2] = new PyTuple(1)
                {
                    [0] = new PySubStream(content)
                },
            };

            this.ClusterConnection.Send(result);
        }
Exemplo n.º 13
0
        private void HandlePingReq(PyPacket packet, Client client)
        {
            // alter package to include the times the data
            PyTuple         handleMessage = new PyTuple(3);
            PyAddressClient source        = packet.Source as PyAddressClient;

            // this time should come from the stream packetizer or the socket itself
            // but there's no way we're adding time tracking for all the goddamned packets
            // so this should be sufficient
            handleMessage[0] = DateTime.UtcNow.ToFileTime();
            handleMessage[1] = DateTime.UtcNow.ToFileTime();
            handleMessage[2] = "server::handle_message";

            PyTuple turnaround = new PyTuple(3);

            turnaround[0] = DateTime.UtcNow.ToFileTime();
            turnaround[1] = DateTime.UtcNow.ToFileTime();
            turnaround[2] = "server::turnaround";

            (packet.Payload[0] as PyList)?.Add(handleMessage);
            (packet.Payload[0] as PyList)?.Add(turnaround);

            // change to a response
            packet.Type = PyPacket.PacketType.PING_RSP;

            // switch source and destination
            packet.Source      = packet.Destination;
            packet.Destination = source;

            // queue the packet back
            this.Socket.Send(packet);
        }
Exemplo n.º 14
0
        private PyObject OldHandle(PyObject packet)
        {
            // Check for login packets and just forward them
            if (packet is PyTuple)
            {
                // Those are the first packets, sent by both client and server
                return(packet);
            }
            else if (packet is PyInt)
            {
                // This is only sent by the server
                return(packet);
            }
            else if (packet is PyString)
            {
                // This is only sent by the server
                return(packet);
            }
            else if (packet is PyDict)
            {
                // Packet sent by the client(HandshakeAck)
                // We need to modify it in order to put our own client address, as it isnt the same as the address that the server sends
                PyDict handshake = packet as PyDict;

                PyDict session = handshake.Get("session_init") as PyDict;

                session.Set("address", new PyString(socket.GetAddress()));

                handshake.Set("session_init", session);

                return(handshake);
            }
            else if (packet is PyObjectEx) // Exceptions... just check the type and decide what to do
            {
                PyException exception = new PyException();

                if (exception.Decode(packet) == true) // Ignore the error
                {
                    Log.Debug("Exceptions", "Got exception of type " + exception.exception_type);
                }

                return(packet);
            }
            else // Normal packets
            {
                PyPacket p = new PyPacket();
                if (p.Decode(packet) == false)
                {
                    // Big problem here, we dont know who to send this
                    Log.Error("Client", "Cannot decode PyPacket");
                }
                else
                {
                    return(HandlePyPacket(p));
                }

                return(packet);
            }
        }
Exemplo n.º 15
0
        /// <summary>
        /// Prepares and sends a session change notification to this client
        /// </summary>
        public void SendSessionChange()
        {
            // build the session change
            PyPacket sessionChangeNotification = this.CreateEmptySessionChange(this.Container);

            // and finally send the client the required data
            this.ClusterConnection.Send(sessionChangeNotification);
        }
Exemplo n.º 16
0
 public void NotifyAllNodes(PyPacket packet)
 {
     lock (this.Nodes)
     {
         foreach ((long _, NodeConnection connection) in this.Nodes)
         {
             connection.Socket.Send(packet);
         }
     }
 }
Exemplo n.º 17
0
 public void NotifyAllNodes(PyPacket packet)
 {
     lock (this.Nodes)
     {
         foreach (KeyValuePair <long, NodeConnection> entry in this.Nodes)
         {
             entry.Value.Socket.Send(packet);
         }
     }
 }
Exemplo n.º 18
0
        private void HandleNotification(PyPacket packet, Client client)
        {
            if (packet.Source is PyAddressAny)
            {
                this.HandleBroadcastNotification(packet);
                return;
            }

            PyTuple callInfo = ((packet.Payload[0] as PyTuple)[1] as PySubStream).Stream as PyTuple;

            PyList objectIDs = callInfo[0] as PyList;
            string call      = callInfo[1] as PyString;

            if (call != "ClientHasReleasedTheseObjects")
            {
                Log.Error($"Received notification from client with unknown method {call}");
                return;
            }

            // search for the given objects in the bound service
            // and sure they're freed
            foreach (PyTuple objectID in objectIDs.GetEnumerable <PyTuple>())
            {
                if (objectID[0] is PyString == false)
                {
                    Log.Fatal("Expected bound call with bound string, but got something different");
                    return;
                }

                string boundString = objectID[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 a ClientHasReleasedTheseObjects call for an object ID that doesn't belong to us");
                    // 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;
                }

                this.BoundServiceManager.FreeBoundService(boundID);
            }
        }
Exemplo n.º 19
0
        private void HandleSessionChangeNotification(PyPacket packet, Client client)
        {
            Log.Debug($"Updating session for client {packet.UserID}");

            // ensure the client is registered in the node and store his session
            if (this.ClientManager.Contains(packet.UserID) == false)
            {
                this.ClientManager.Add(packet.UserID, this.DependencyInjector.GetInstance <Client>());
            }

            this.ClientManager.Get(packet.UserID).UpdateSession(packet);
        }
Exemplo n.º 20
0
        public PyObject SetSessionChangeDestination(PyPacket p)
        {
            p.source.type   = PyAddress.AddrType.Node;
            p.source.typeID = (ulong)nodeID;
            p.source.callID = 0;

            p.dest.type   = PyAddress.AddrType.Client;
            p.dest.typeID = (ulong)ClientManager.GetClientID(this);
            p.dest.callID = 0;

            return(p.Encode());
        }
Exemplo n.º 21
0
        public PyObject SetSessionChangeDestination(PyPacket p, int node)
        {
            // The session change info should never come from the client
            p.source.type   = PyAddress.AddrType.Node;
            p.source.typeID = (ulong)1;
            p.source.callID = 0;

            p.dest.type   = PyAddress.AddrType.Node;
            p.dest.typeID = (ulong)node;
            p.dest.callID = 0;

            return(p.Encode());
        }
Exemplo n.º 22
0
        public void UpdateSession(PyPacket packet)
        {
            if (packet.Payload.TryGetValue(0, out PyTuple sessionData) == false)
            {
                throw new InvalidDataException("SessionChangeNotification expected a payload of size 1");
            }
            if (sessionData.TryGetValue(1, out PyDictionary differences) == false)
            {
                throw new InvalidDataException("SessionChangeNotification expected a differences collection");
            }

            this.Session.LoadChanges(differences);
        }
Exemplo n.º 23
0
        public void SendSessionChange()
        {
            PyPacket sc = CreateEmptySessionChange();

            PyObject client = SetSessionChangeDestination(sc);
            PyObject node   = SetSessionChangeDestination(sc, NodeID);

            if (sc != null)
            {
                Send(client);
                ConnectionManager.NotifyConnection(NodeID, node);
            }
        }
Exemplo n.º 24
0
        // TODO: MOVE THIS CODE TO THE SESSION HANDLER INSTEAD

        public void SendSessionChange()
        {
            PyPacket packet = CreateEmptySessionChange();

            if (packet is null)
            {
                return;
            }

            PyDataType client = SetSessionChangeDestination(packet);

            this.Socket.Send(client);
            this.ConnectionManager.NotifyAllNodes(packet);
        }
Exemplo n.º 25
0
        public void UpdateSession(PyPacket from)
        {
            Log.Debug("Client", "Updating session for client");

            // We should add a Decode method to SessionChangeNotification...
            PyTuple payload = from.payload;

            PyDict changes = payload[0].As <PyTuple>()[1].As <PyTuple>()[0].As <PyDict>();

            // Update our local session
            foreach (PyString key in changes.Dictionary.Keys)
            {
                session.Set(key.Value, changes[key.Value].As <PyTuple>()[1]);
            }
        }
Exemplo n.º 26
0
        public void NotifyNode(long nodeID, string type, PyTuple data)
        {
            PyPacket notification = new PyPacket(PyPacket.PacketType.NOTIFICATION);

            notification.Source      = new PyAddressAny(0);
            notification.Destination = new PyAddressNode(nodeID);
            notification.Payload     = new PyTuple(2)
            {
                [0] = type, [1] = data
            };
            notification.OutOfBounds = new PyDictionary();
            notification.UserID      = 0;

            lock (this.Nodes)
                this.Nodes[nodeID].Socket.Send(notification);
        }
Exemplo n.º 27
0
        public void SendCallResult(CallInformation answerTo, PyDataType content)
        {
            PyPacket result = new PyPacket(PyPacket.PacketType.CALL_RSP);

            // ensure destination has clientID in it
            PyAddressClient source = answerTo.From as PyAddressClient;

            source.ClientID = answerTo.Client.AccountID;
            // switch source and dest
            result.Source      = answerTo.To;
            result.Destination = source;

            result.UserID  = source.ClientID;
            result.Payload = new PyTuple(new PyDataType[] { new PySubStream(content) });

            this.Socket.Send(result);
        }
Exemplo n.º 28
0
        private void HandleSessionChangeNotification(PyPacket packet, Client client)
        {
            Log.Debug($"Updating session for client {packet.UserID}");

            // ensure the client is registered in the node and store his session
            if (client == null)
            {
                this.ClientManager.Add(
                    packet.UserID,
                    client = new Client(
                        this.Container, this.ClusterConnection, this.ServiceManager, this.TimerManager,
                        this.ItemFactory, this.CharacterManager, this.SystemManager, this.NotificationManager, this
                        )
                    );
            }

            client.UpdateSession(packet);
        }
Exemplo n.º 29
0
        public PyObject CreateSessionChange()
        {
            PyPacket p = CreateEmptySessionChange();

            if (p == null)
            {
                return(null);
            }

            p.source.type   = PyAddress.AddrType.Node;
            p.source.typeID = (ulong)nodeID;
            p.source.callID = 0;

            p.dest.type   = PyAddress.AddrType.Client;
            p.dest.typeID = (ulong)GetAccountID();
            p.dest.callID = 0;

            return(p.Encode());
        }
Exemplo n.º 30
0
        private void RelayPacket(PyPacket packet)
        {
            switch (packet.Destination)
            {
            case PyAddressClient _:
                Log.Trace($"Sending packet to client {packet.UserID}");
                this.ConnectionManager.NotifyClient((int)(packet.UserID), packet);
                break;

            case PyAddressNode address:
                Log.Trace($"Sending packet to node {address.NodeID}");
                this.ConnectionManager.NotifyNode((int)(address.NodeID), packet);
                break;

            case PyAddressBroadcast _:
                Log.Error("Broadcast packets not supported yet");
                break;
            }
        }