/// <summary> /// Handles the deserialization of the <see cref="Query" /> and <see cref="Response" /> /// messages from the blob data. /// </summary> /// <param name="es">The enhanced stream holding the payload data.</param> protected override void ReadFrom(EnhancedStream es) { // Let the base message class load the properties and the data blob. base.ReadFrom(es); // Now parse the query and (optional) response messages from the blob es = new EnhancedBlockStream(base._Data); try { query = Msg.Load(es); if (es.Eof) { response = null; } else { response = Msg.Load(es); } } finally { es.Close(); } }
/// <summary> /// Handles message packets received on the socket. /// </summary> /// <param name="ar">The async result.</param> private void OnSocketReceive(IAsyncResult ar) { int cb; Msg msg = null; byte[] msgBuf; int cbMsg; IPEndPoint fromEP = NetworkBinding.Any; using (TimedLock.Lock(router.SyncRoot)) { if (!isOpen) { return; } try { cb = sock.EndReceiveFrom(ar, ref recvEP); if (cb > 0) { msgBuf = router.DecryptFrame(recvBuf, cb, out cbMsg); msg = Msg.Load(new EnhancedMemoryStream(msgBuf)); fromEP = (IPEndPoint)recvEP; msg._SetFromChannel(new ChannelEP(transport, fromEP)); } } catch (MsgException) { // Ignore messages that can't be parsed } catch (Exception e) { SysLog.LogException(e); } // Initiate the receive of the next message if (sock.IsOpen) { try { sock.BeginReceiveFrom(recvBuf, 0, recvBuf.Length, SocketFlags.None, ref recvEP, onSocketReceive, null); } catch (Exception e) { SysLog.LogException(e, "LillTek UDP message channel is no longer able to receive messages."); } } } if (msg != null) { msg._Trace(router, 2, "UDP: Recv", string.Format("From: {0}", fromEP)); msg._Trace(router, 0, "Receive", string.Empty); router.OnReceive(this, msg); } }
/// <summary> /// Generates a clone of this message instance, generating a new /// <see cref="_MsgID" /> property if the original ID is /// not empty. /// </summary> /// <returns>Returns a clone of the message.</returns> /// <remarks> /// <para> /// This base method works by serializing and then deseralizing a new copy of /// the message to a buffer and then generating a new <see cref="_MsgID" /> GUID. This /// implementation will be relatively costly in terms of processor and /// memory resources. /// </para> /// <para> /// Derived messages can choose to override this and implement a shallow /// clone instead, using the <see cref="CopyBaseFields" /> method. Note that /// the <see cref="CopyBaseFields" /> method ensures that a new <see cref="_MsgID" /> /// property is regenerated if the original ID field is not empty. /// </para> /// </remarks> public virtual Msg Clone() { var es = new EnhancedBlockStream(1024, 1024); Msg clone; Msg.Save(es, this); es.Position = 0; clone = Msg.Load(es); if (this.msgID != Guid.Empty) { clone.msgID = Helper.NewGuid(); } return(clone); }
/// <summary> /// Handles messages received from the UdpBroadcast client. /// </summary> /// <param name="sender">The UDP broadcast client.</param> /// <param name="args">Event arguments.</param> private void OnBroadcastReceive(object sender, UdpBroadcastEventArgs args) { Msg msg = null; byte[] msgBuf; int cbMsg; int cb; using (TimedLock.Lock(router.SyncRoot)) { if (!isOpen) { return; } try { cb = args.Payload.Length; if (cb > 0) { msgBuf = router.DecryptFrame(args.Payload, cb, out cbMsg); msg = Msg.Load(new EnhancedMemoryStream(msgBuf)); msg._SetFromChannel(new ChannelEP(transport, new IPEndPoint(args.SourceAddress, 0))); } } catch (MsgException) { // Ignore messages that can't be parsed } catch (Exception e) { SysLog.LogException(e); } } if (msg != null) { msg._Trace(router, 2, "UDP: Broadcast Recv", string.Format("From: {0}", args.SourceAddress)); msg._Trace(router, 0, "Receive", string.Empty); router.OnReceive(this, msg); } }
/// <summary> /// Handles receive completions on the socket. /// </summary> /// <param name="ar">The async result.</param> private void OnReceive(IAsyncResult ar) { int cbRecv; try { using (TimedLock.Lock(router.SyncRoot)) { if (sock == null || recvBuf == null) { return; } try { cbRecv = sock.EndReceive(ar); } catch (SocketException e2) { if (e2.SocketErrorCode == SocketError.ConnectionReset) { cbRecv = 0; // Treat connection resets as connection closure } else { throw; } } if (cbRecv == 0) { sock.ShutdownAndClose(); return; } SetLastAccess(); recvPos += cbRecv; if (recvPos < recvBuf.Length) { // Continue the reception sock.BeginReceive(recvBuf, recvPos, recvBuf.Length - recvPos, SocketFlags.None, onReceive, null); return; } if (recvHeader) { // Initiate reception of the frame payload int pos = 0; int cbFrame; byte[] buf; cbFrame = Helper.ReadInt32(recvBuf, ref pos); buf = new byte[MsgRouter.FrameHeaderSize + cbFrame]; Array.Copy(recvBuf, 0, buf, 0, MsgRouter.FrameHeaderSize); recvHeader = false; recvBuf = buf; recvPos = MsgRouter.FrameHeaderSize; cbRecv = cbFrame; sock.BeginReceive(recvBuf, recvPos, cbFrame, SocketFlags.None, onReceive, null); } else { // We've completed the reception of a message Msg msg; byte[] msgBuf; int cbMsg; msgBuf = router.DecryptFrame(recvBuf, recvBuf.Length, out cbMsg); msg = Msg.Load(new EnhancedMemoryStream(msgBuf)); msgBuf = null; // Handle initialization messages locally and queue a // notification for all other messages so that router.OnReceive() // will be called on a worker thread. if (!initProcessed) { TcpInitMsg initMsg; Exception e; initMsg = msg as TcpInitMsg; if (initMsg == null) { e = new MsgException("Invalid TCP channel protocol: TcpInitMsg expected."); SysLog.LogException(e); Helper.Rethrow(e); } initMsg._Trace(router, 2, "Receive", null); // If the sender indicates that it is an uplink then we're going // to use the actual remote port for the remoteEP rather than // ListenPort (which should be 0). The reason for this is that // intervening routers and NATs may translate the port number // reported by the child router. routerEP = initMsg.RouterEP; remoteEP.NetEP.Port = initMsg.IsUplink ? ((IPEndPoint)sock.RemoteEndPoint).Port : initMsg.ListenPort; isDownlink = initMsg.IsUplink; isP2P = initMsg.RouterInfo.IsP2P; initProcessed = true; router.OnTcpInit(this); } else { msg._SetFromChannel(remoteEP); msg._Trace(router, 2, "TCP: Recv", null); msg._Trace(router, 0, "Receive", string.Empty); router.OnReceive(this, msg); } // Initiate reception of the next message BeginReceive(); } } } catch (SocketException e) { // Don't log connection resets because we see these all the // time when a router stops. We're not going to consider // this to be an error. if (e.SocketErrorCode != SocketError.ConnectionReset) { TraceException(e); SysLog.LogException(e); } router.OnTcpClose(this); Close(); } catch (Exception e) { TraceException(e); SysLog.LogException(e); router.OnTcpClose(this); Close(); } }