/// <summary> /// Serializes a NetMessage to the reliable stream. /// If there is no current stream, one is prepared. /// If the current stream cannot fit the message, it is sent and a new stream is prepared. /// </summary> internal void SerializeReliableMessage(NetMessage message) { if (sendWindow.Count >= 512) { return; } if (sendStream == null) { InitializeStream(); } if (!NetSerializer.TryWriteMessage(sendStream, message)) { if (retryingSerialization) { NetLog.Warning("SerializeReliableMessage failed."); retryingSerialization = false; return; } retryingSerialization = true; FlushStream(); SerializeReliableMessage(message); } if (retryingSerialization) { retryingSerialization = false; } }
private void ReceiveCreateView(NetMessage message, NetConnection server) { if (!server.IsServer && !server.IsPeer) { return; } int viewId = (int)message.Parameters[0]; int group = (int)message.Parameters[1]; string prefabRoot = (string)message.Parameters[2]; var stream = (NetStream)message.Parameters[3]; NetView.Relation relation = default(NetView.Relation); NetConnection controller = null; switch (message.MessageId) { case (int)ViewCmd.CreateOwnerView: controller = Socket.Self; relation = NetView.Relation.Owner; break; case (int)ViewCmd.CreatePeerView: relation = NetView.Relation.Peer; break; case (int)ViewCmd.CreateCreatorView: server = Socket.Self; relation = NetView.Relation.Creator; break; case (int)ViewCmd.CreateProxyView: relation = NetView.Relation.Proxy; break; } if (relation == NetView.Relation.Creator || relation == NetView.Relation.Peer) { var ipendpoint = (IPEndPoint)message.Parameters[4]; if (ipendpoint != null) { if (Socket.EndpointConnected(ipendpoint)) { controller = Socket.EndpointToConnection(ipendpoint); } else { NetLog.Error("Failed to create view, controller endpoint not connected: " + ipendpoint); } } } var view = CreateView(controller, server, viewId, group, prefabRoot, relation); view.TriggerReadInstantiateData(stream); if (OnNetViewCreated != null) { OnNetViewCreated(view); } }
public IEnumerator SetServer(NetConnection server, NetZone zone) { zone.Assigned = true; if (server != Socket.Self) { var setServerRequest = Socket.Request.Send <string>("AssignZone", server, zone); yield return(setServerRequest.WaitUntilDone); if (!setServerRequest.IsSuccessful) { zone.Assigned = false; yield break; } zone.PublicEndpoint = setServerRequest.Result; } else { NetZoneServer zoneServ = GetComponent <NetZoneServer>(); zoneServ.AssignZoneSelf(zone); } zone.Server = server; zone.ServerEndpoint = zone.Server.Endpoint; if (string.IsNullOrEmpty(zone.PublicEndpoint)) { zone.PublicEndpoint = zone.Server.Endpoint.ToString(); } ZoneAssigned(zone); NetLog.Info("Server assigned to zone. Endpoint: " + server.Endpoint); zone.Available = true; }
/// <summary> /// Sets request result and removes request from queue. /// </summary> internal void SetResponse(NetMessage message, NetConnection connection) { if (message.Parameters.Length < 2 || !(message.Parameters[0] is ushort)) { NetLog.Error("Received malformed request response. Discarding."); return; } ushort requestId = (ushort)message.Parameters[0]; uint key = CreateKey(message.ViewId, requestId); if (!requests.ContainsKey(key)) { //NetLog.Trace("Active request doesn't exist for response. Discarding."); return; } object requestObj = requests[key]; requests.Remove(key); if ((bool)message.Parameters[1]) { MethodInfo setResponse = requestObj.GetType().GetMethod("SetResponse"); setResponse.Invoke(requestObj, message.Parameters); } else { MethodInfo failureResponse = requestObj.GetType().GetMethod("FailureResponse", BindingFlags.NonPublic); failureResponse.Invoke(requestObj, null); } }
/// <summary> /// When an RPC is received, the targeted NetView is identified and DispatchRPC is called for that /// particular NetView object. DispatchRPC then identifies the targeted method and invokes it with /// the supplied parameters. /// </summary> internal void DispatchRpc(string methodName, NetMessage message, NetConnection connection) { if (!CachedRpcObjects.ContainsKey(methodName)) { NetLog.Error(string.Format("Can't find RPC method \"{0}\" for View {1}.", methodName, Id)); return; } Socket.Rpc.Invoke(CachedRpcObjects[methodName], methodName, message, connection); }
internal void Register(ushort commandId, Action <NetStream, NetConnection> target) { if (paramTypes.ContainsKey(commandId)) { NetLog.Error("Command Id already in use. Cannot add command."); return; } streamTargets.Add(commandId, target); paramTypes.Add(commandId, streamTypes); }
internal void Register(ushort commandId, Action <NetMessage, NetConnection> target, List <Type> types) { if (paramTypes.ContainsKey(commandId)) { NetLog.Error("Command Id already in use. Cannot add command."); return; } paramTypes.Add(commandId, types); targets.Add(commandId, target); }
/// <summary> Sends a reliable RPC that does not target a specific view. </summary> public void Send(string methodName, NetConnection target, params object[] parameters) { if (!Rpc.HasId(methodName)) { NetLog.Error("Remote RPC does not have an assigned ID: " + methodName); return; } var message = NetMessage.Create(Rpc.NameToId(methodName), 0, parameters, true); target.Send(message); }
/// <summary> Send overload that creates the NetMessage for the RPC. </summary> internal void Send(int viewId, bool reliable, string methodName, NetConnection target, params object[] parameters) { if (!Socket.Rpc.HasId(methodName)) { NetLog.Error("Send failed: RPC method name has not been assigned an ID."); return; } var netMessage = NetMessage.Create(Socket.Rpc.NameToId(methodName), (uint)viewId, parameters, reliable); target.Send(netMessage); }
private void PeerDisconnected(NetConnection connection) { NetLog.Info("ZoneManager: Peer Disconnected: " + connection.Endpoint); if (peers.Contains(connection)) { peers.Remove(connection); } if (Authority) { RemoveServer(connection); } }
private void ReceivePeerConnectionRequest(IPEndPoint endpoint, NetStream readStream) { if (!AcceptConnections || Connections.Count >= MaxConnections || !Events.PeerApproval(endpoint, readStream)) { NetLog.Info("Refused peer connection: " + endpoint); TrySend(new[] { (byte)ByteCmd.RefuseConnection }, 1, endpoint); } else { CreateConnection(endpoint, false, true); } }
/// <summary> /// Passes parameters from an incoming network message to the method associated with the RPC. /// </summary> internal void DispatchRpc(NetMessage message, NetConnection connection) { string methodName = Rpc.IdToName(message.MessageId); if (!rpcObjectInstances.ContainsKey(methodName)) { NetLog.Error(string.Format("Can't find method \"{0}\" for Viewless RPC.", methodName)); return; } Rpc.Invoke(rpcObjectInstances[methodName], methodName, message, connection); }
internal void RegisterParams(ushort commandId, List <Type> paramTypes) { if (this.paramTypes.ContainsKey(commandId)) { NetLog.Error("Command Id already in use. Cannot add command types."); return; } if (commandId < 1800 || commandId > 2047) { throw new Exception("Cannot register Command - Range: 1800-2047 - Provided: " + commandId); } this.paramTypes.Add(commandId, paramTypes); }
internal void AssignZoneSelf(NetZone zone) { if (ViewManager.GenerateViewId == null) { ViewManager.GenerateViewId += AllocateViewId; } NetLog.Info("Assigned to zone."); self = zone; if (OnAssignment != null) { OnAssignment(); } }
/// <summary> /// Returns the connection that matches the supplied target. /// Returns the server for Server or the first controller for Controllers. /// </summary> internal NetConnection GetTarget(RpcTarget target, NetView view) { switch (target) { case RpcTarget.Server: return(view.Server); case RpcTarget.Controllers: return(view.Controllers[0]); } NetLog.Error("Invalid RpcTarget for GetTarget. Only RpcTarget.Server or RpcTarget.Controllers can be used."); return(null); }
internal static NetMessage ReadNetMessage(NetStream stream) { List <Type> paramTypes; ushort messageId = stream.ReadUShort(11); uint viewId = 0; if (stream.ReadBool()) { viewId = stream.ReadUInt(20); } if (messageId == (int)Cmd.RequestResponse) { return(CreateResponseMessage(stream, messageId, viewId)); } if (messageId > 1800) { if (!stream.Socket.Command.Exists(messageId)) { NetLog.Error("Cannot deserialize message, Command ID not found: " + messageId); return(null); } paramTypes = stream.Socket.Command.ParamTypes(messageId); } else { if (!stream.Socket.Rpc.Exists(messageId)) { NetLog.Error("Cannot deserialize message, RPC ID not found: " + messageId); return(null); } paramTypes = stream.Socket.Rpc.ParamTypes(messageId); } NetMessage netMessage = NetMessage.Create(messageId, viewId, paramTypes.Count, false); if (stream.Socket.Rpc.TakesRequests(messageId)) { return(CreateRequestMessage(stream, netMessage, paramTypes)); } for (int i = 0; i < paramTypes.Count; i++) { netMessage.Parameters[i] = ReadParam(stream, paramTypes[i]); } return(netMessage); }
private void PeerConnected(NetConnection connection) { if (!peerLookup.ContainsKey(connection.Endpoint)) { return; } NetZone peer = peerLookup[connection.Endpoint]; NetLog.Info("Connection is Zone Peer: " + peer); peer.Server = connection; connection.InternalScope = new NetScope(); connection.InternalScope.Position = peer.Position; connection.InternalScope.OutScopeDist = (int)(peer.HandoverMaxDistance * 1.25); connection.InternalScope.InScopeDist = peer.HandoverMaxDistance; }
/// <summary> Send overload that creates the NetMessage for the RPC. </summary> internal void Send(int viewId, bool reliable, string methodName, List <NetConnection> targets, params object[] parameters) { if (!Socket.Rpc.HasId(methodName)) { NetLog.Error("Send failed: RPC method name has not been assigned an ID."); return; } var message = NetMessage.Create(Socket.Rpc.NameToId(methodName), (uint)viewId, parameters, reliable); for (int i = 0; i < targets.Count; i++) { targets[i].Send(message); } }
/// <summary> Sends a message to this connection. </summary> internal void Send(NetMessage message) { if (this == Socket.Self) { NetLog.Warning("Trying to send message to self."); } if (!message.Reliable) { Unreliable.SerializeMessage(message); } else { Reliable.SerializeReliableMessage(message); } }
/// <summary> Adds a new NetConnection to the connection list. </summary> internal NetConnection CreateConnection(IPEndPoint ep, bool isServer, bool isPeer) { bool wasServer = false; // Connection cannot be both server and peer: if (isPeer) { isServer = false; wasServer = true; } var connection = new NetConnection(isServer, isPeer, this, ep); Connections.Add(connection); endpointToConnection.Add(ep, connection); if (isPeer) { NetLog.Info("Peer connection created: " + ep); } else if (isServer) { NetLog.Info("Server connection created: " + ep); } else { NetLog.Info("Client connection created: " + ep); } if (ProtocolAuthority && !isServer && !wasServer) { SendConnectionRequirements(connection); Rpc.SendLocalAssignments(connection); } else if (connection.IsPeer && Rpc.IdCount == RpcInfoCache.Count) { Events.PeerConnected(connection); } else if (isServer && Rpc.IdCount == RpcInfoCache.Count) { Events.ConnectedToServer(connection); } else if (!isServer && !isPeer) { Events.ClientConnected(connection); } return(connection); }
/// <summary> Send overload that creates the NetMessage for the RPC. </summary> internal void Send(int viewId, bool reliable, string methodName, RpcTarget target, params object[] parameters) { if (!Socket.Rpc.HasId(methodName)) { NetLog.Error("Send failed: RPC method name has not been assigned an ID."); return; } if (!ViewLookup.ContainsKey(viewId)) { return; } NetView view = ViewLookup[viewId]; var netMessage = NetMessage.Create(Socket.Rpc.NameToId(methodName), (uint)viewId, parameters, reliable); Send(view, netMessage, target); }
private void ReceiveConnectionResponse(IPEndPoint endpoint, int bytesReceived, NetStream readStream) { bool isPeer = RemoveFromConnecting(endpoint, true); if (bytesReceived == 1 && readStream.Data[0] == (byte)ByteCmd.RefuseConnection) { NetLog.Info("Connection refused by: " + endpoint); return; } var connection = CreateConnection(endpoint, true, isPeer); if (bytesReceived > 1) { connection.ReceiveStream(readStream); } }
/// <summary> /// Starts the socket using the supplied endpoint. /// If the port is taken, the given port will be incremented to a free port. /// </summary> public void StartSocket(IPEndPoint endpoint) { Self = new NetConnection(false, false, this, endpoint); socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); try { const uint IOC_IN = 0x80000000; const uint IOC_VENDOR = 0x18000000; uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12; socket.IOControl((int)SIO_UDP_CONNRESET, new[] { Convert.ToByte(false) }, null); } catch { NetLog.Warning("Failed to set control code for ignoring ICMP port unreachable."); } socket.ReceiveBufferSize = 4194304; if (socket.ReceiveBufferSize != 4194304) { NetLog.Warning("ReceiveBufferSize restricted by OS."); } socket.SendBufferSize = 1048576; socket.Blocking = false; try { socket.Bind(endpoint); } catch (SocketException e) { if (e.ErrorCode == 10048) { var newEp = new IPEndPoint(endpoint.Address, endpoint.Port + 1); NetLog.Warning("Port in use. Incrementing and retrying..."); StartSocket(newEp); } else { NetLog.Error(e.Message); } return; } NetLog.Info(NetTime.StartDateTime() + " | Socket Started. Bound to: " + endpoint); NetTime.Milliseconds(); if (ProtocolAuthority) { Rpc.AssignLocalRpcs(); } Events.SocketStart(); }
/// <summary> Performs end-frame tasks such as flushing stream & checking timeouts. </summary> internal void EndOfFrame(uint currentTime) { if (ShouldDisconnect(currentTime)) { NetLog.Info("Disconnecting connection due to overflow or timeout: " + Endpoint); Disconnect(); return; } if (!Reliable.FlushStream() && Reliable.ShouldForceAck(currentTime)) { Reliable.ForceAck(); } if (!Unreliable.FlushStream() && ShouldSendHeartbeat(currentTime)) { Unreliable.SendHeartbeat(); } Reliable.CheckTimeouts(currentTime); }
private void DeliverSyncStream(NetMessage message, NetConnection connection) { if (!ViewLookup.ContainsKey((int)message.ViewId)) { return; } var view = ViewLookup[(int)message.ViewId]; if (!view.IsController(connection) && connection != view.Server) { if (!connection.IsServer) { NetLog.Warning("Connection attempting to send to unauthorized View: " + connection.Endpoint); return; } view.Server = connection; } view.TriggerReadSync((NetStream)message.Parameters[0]); }
/// <summary> Deserializes incoming reliable stream into NetMessages, forwards them to the NetSocket, releases the stream, /// increments the remote sequence, and retries the out-of-order buffer when needed. </summary> private void DeliverStream(NetStream strm) { // Deserialize stream into individual messages and pass them to the socket: while (NetSerializer.CanReadMessage(strm)) { var message = NetSerializer.ReadNetMessage(strm); if (message == null) { NetLog.Error("Failed to parse reliable message from: " + Connection.Endpoint + " Pos: " + strm.Pos + " Size: " + strm.Size); break; } Connection.Socket.ReceiveMessage(message, Connection); } // Return stream to pool and update receive buffer distances: strm.Release(); LastAcceptedRemoteSequence++; if (recvBuffer.Count > 0) { DecrementReceiveBuffer(); } }
private void ReceiveMessage(NetMessage message, NetConnection connection) { if (!ViewLookup.ContainsKey((int)message.ViewId)) { return; } string methodName = Socket.Rpc.IdToName(message.MessageId); var view = ViewLookup[(int)message.ViewId]; if (!view.IsController(connection) && connection != view.Server) { if (!connection.IsServer) { NetLog.Warning("Connection attempting to send to unauthorized View: " + connection.Endpoint); return; } view.Server = connection; } view.DispatchRpc(methodName, message, connection); }
internal void RemovePeerSelf(NetZone zone) { NetLog.Info("Removing zone"); if (peerLookup.ContainsKey(zone.ServerEndpoint)) { peerLookup.Remove(zone.ServerEndpoint); } else if (peerLookup.ContainsValue(zone)) { NetLog.Warning("RemovePeer: Zone endpoint mismatch."); } if (peers.Contains(zone)) { peers.Remove(zone); } else { NetLog.Info("RemovePeer: Zone not in peer list."); } }
/// <summary> Cleans up a connection attempt and returns true if it is a peer connection. </summary> internal bool RemoveFromConnecting(IPEndPoint ep, bool successful) { bool isPeer = false; if (!successful) { NetLog.Info("Failed to connect to: " + ep); Events.FailedToConnect(ep); } int index = connectingEndpoints.IndexOf(ep); connectingTimes.RemoveAt(index); connectingRetriesRemaining.RemoveAt(index); connectingEndpoints.Remove(ep); if (connectingData[index].Data[0] == (byte)ByteCmd.ConnectToPeer) { isPeer = true; } connectingData[index].Release(); connectingData.RemoveAt(index); return(isPeer); }
/// <summary> Sends an RPC to connections that are in-scope for the provided view. </summary> internal void Send(NetView view, NetMessage netMessage, RpcTarget target) { switch (target) { case (RpcTarget.All): for (int i = 0; i < Socket.Connections.Count; i++) { var connection = Socket.Connections[i]; if (!connection.HasScope) { continue; } if (view.Group != 0 && !connection.InGroup(view.Group)) { continue; } if ((netMessage.Reliable && connection.Scope.In(view.Id)) || connection.Scope.In(view.Id, syncFrame) || view.IsController(connection)) { connection.Send(netMessage); } } break; case (RpcTarget.Controllers): foreach (NetConnection controller in view.Controllers) { if (controller == Socket.Self) { continue; } controller.Send(netMessage); } break; case (RpcTarget.NonControllers): for (int i = 0; i < Socket.Connections.Count; i++) { var connection = Socket.Connections[i]; if (connection.IsServer || !connection.HasScope) { continue; } if (view.IsController(connection)) { continue; } if (view.Group != 0 && !connection.InGroup(view.Group)) { continue; } if ((netMessage.Reliable && connection.Scope.In(view.Id)) || connection.Scope.In(view.Id, syncFrame)) { connection.Send(netMessage); } } break; case (RpcTarget.Server): if (view.Server != Socket.Self) { view.Server.Send(netMessage); } else { NetLog.Warning("Trying to send message to self."); } break; case (RpcTarget.AllInclOutOfScope): for (int i = 0; i < Socket.Connections.Count; i++) { var connection = Socket.Connections[i]; if (view.Group != 0 && !connection.InGroup(view.Group)) { continue; } connection.Send(netMessage); } break; } }