/// <summary> /// Transmits the message via the UDP broadcast client. /// </summary> /// <param name="toEP">The target endpoint.</param> /// <param name="msg">The message.</param> private void TransmitViaUdpBroadcast(ChannelEP toEP, Msg msg) { byte[] sendBuf; int cbSend; int cbMsg; msg._SetToChannel(toEP); msg._SetFromChannel(localEP); msg._Trace(router, 2, "UDP: Send", null); using (TimedLock.Lock(router.SyncRoot)) { // Initiate transmission of the message cbMsg = Msg.Save(new EnhancedMemoryStream(msgBuf), msg); sendBuf = router.EncryptFrame(msgBuf, cbMsg); cbSend = sendBuf.Length; Assertion.Validate(cbSend <= TcpConst.MTU - UdpBroadcastClient.MessageEnvelopeSize, "Message larger than UDP MTU."); try { broadcastClient.Broadcast(sendBuf); } catch { } } }
/// <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> /// Initiates a network connection to the message router at the /// specified network endpoint and then initiates the transmission /// of the message once the connection is established. /// </summary> /// <param name="ep">The remote router's endpoint.</param> /// <param name="msg">The message to be sent (or <c>null</c>).</param> public void Connect(IPEndPoint ep, Msg msg) { using (TimedLock.Lock(router.SyncRoot)) { Assertion.Test(sock == null); sock = new EnhancedSocket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); localEP = new ChannelEP(Transport.Tcp, router.NormalizeEP(router.TcpEP)); sock.NoDelay = !router.TcpDelay; sock.SendBufferSize = router.TcpSockConfig.SendBufferSize; sock.ReceiveBufferSize = router.TcpSockConfig.ReceiveBufferSize; if (router.FragmentTcp) { sock.SendMax = 1; sock.ReceiveMax = 1; } // Queue the channel initialization message and the message passed Msg initMsg; initMsg = new TcpInitMsg(router.RouterEP, new MsgRouterInfo(router), isUplink, router.TcpEP.Port); initMsg._TTL = 1; Serialize(initMsg); Enqueue(initMsg); try { SetLastAccess(); remoteEP = new ChannelEP(Transport.Tcp, router.NormalizeEP(ep)); if (msg != null) { msg._SetToChannel(remoteEP); msg._SetFromChannel(localEP); msg._Trace(router, 2, "TCP: Queue", null); Serialize(msg); Enqueue(msg); } router.Trace(2, "TCP: Outbound", "LocalEP=" + localEP.NetEP.ToString() + " remoteEP=" + remoteEP.NetEP.ToString(), null); sock.BeginConnect(remoteEP.NetEP, new AsyncCallback(OnConnect), null); } catch (Exception e) { router.Trace(string.Format(null, "TCP: Connect Failed [{0}]", ep), e); router.OnTcpClose(this); Close(); } } }
/// <summary> /// Private implementation of the Transmit() method that implements an /// option that disables queuing for the message passed. /// </summary> /// <param name="toEP">The target endpoint.</param> /// <param name="msg">The message.</param> /// <param name="queue">Indicates whether queuing should be enabled for this message.</param> private void Transmit(ChannelEP toEP, Msg msg, bool queue) { msg._SetToChannel(toEP); msg._SetFromChannel(localEP); msg._Trace(router, 2, "TCP: Send", null); // Serialize the message here rather than within the lock // below for better multiprocessor performance. Serialize(msg); // Initiate transmission of the message or queue it if other // messages are awaiting transmission (if queuing is enabled). try { using (TimedLock.Lock(router.SyncRoot)) { if (!connected || sending) { Enqueue(msg); return; } // If there are already messages in the queue then add this // message to the end of the queue and then dequeue a message // from the front of the queue and send it. if (queue && sendQueue.Count > 0) { Enqueue(msg); msg = Dequeue(); } // Initiate message transmission sendBuf = msg._MsgFrame; sending = true; sendPos = 0; cbSend = sendBuf.Length; sock.BeginSend(sendBuf, sendPos, cbSend, SocketFlags.None, onSend, null); } } catch (Exception e) { TraceException(e); router.OnTcpClose(this); Close(); } }
/// <summary> /// Queues the message passed rather than initiating an /// immediate transmission. /// </summary> /// <param name="toEP">The target endpoint.</param> /// <param name="msg">The message to queue.</param> internal void QueueTo(ChannelEP toEP, Msg msg) { msg._SetToChannel(toEP); msg._SetFromChannel(localEP); msg._Trace(router, 2, "TCP: Queue", null); Serialize(msg); using (TimedLock.Lock(router.SyncRoot)) { msg._SetToChannel(toEP); Enqueue(msg); } }
/// <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 message packet send completions on the socket. /// </summary> /// <param name="ar">The async result.</param> private void OnSend(IAsyncResult ar) { ChannelEP toEP; int cb; int cbMsg; using (TimedLock.Lock(router.SyncRoot)) { if (!isOpen || sendMsg == null) { return; } Assertion.Test(sendMsg != null); sendMsg = null; try { cb = sock.EndSendTo(ar); Assertion.Test(cb == cbSend); if (sendQueue.Count > 0) { sendMsg = sendQueue.Dequeue(); toEP = sendMsg._ToEP.ChannelEP; sendMsg._SetFromChannel(localEP); cbMsg = Msg.Save(new EnhancedMemoryStream(msgBuf), sendMsg); sendBuf = router.EncryptFrame(msgBuf, cbMsg); cbSend = sendBuf.Length; Assertion.Validate(cbSend <= TcpConst.MTU, "Message larger than UDP MTU."); sock.BeginSendTo(sendBuf, 0, cbSend, SocketFlags.None, router.NormalizeEP(toEP.NetEP), onSend, null); } } catch { } } }
/// <summary> /// Transmits the message via the socket. /// </summary> /// <param name="toEP">The target endpoint.</param> /// <param name="msg">The message.</param> private void TransmitViaSocket(ChannelEP toEP, Msg msg) { int cbMsg; if (cloudEP != null && !multicastInit) { // Retry adding the socket to the multicast group if this didn't // work earlier. try { this.sock.MulticastGroup = cloudEP.Address; this.multicastInit = true; } catch { this.multicastInit = false; } } msg._SetToChannel(toEP); msg._SetFromChannel(localEP); msg._Trace(router, 2, "UDP: Send", null); using (TimedLock.Lock(router.SyncRoot)) { if (sendMsg != null) { // We're already in the process of transmitting // a message so queue this one. Enqueue(msg); return; } // If there are already messages in the queue then queue // this one and then setup to transmit the first message // waiting in the queue. if (sendQueue.Count > 0) { Enqueue(msg); msg = sendQueue.Dequeue(); } // Initiate transmission of the message sendMsg = msg; cbMsg = Msg.Save(new EnhancedMemoryStream(msgBuf), sendMsg); sendBuf = router.EncryptFrame(msgBuf, cbMsg); cbSend = sendBuf.Length; Assertion.Validate(cbSend <= TcpConst.MTU, "Message larger than UDP MTU."); try { sock.BeginSendTo(sendBuf, 0, cbSend, SocketFlags.None, router.NormalizeEP(toEP.NetEP), onSend, null); } catch { // Ignoring } } }