private void OnUdpReceive(IAsyncResult ar) { try { var cbRecv = udpSock.EndReceiveFrom(ar, ref udpRemoteEP); var remoteEP = (IPEndPoint)udpRemoteEP; var prefix = PadPrefix(string.Format("UDP[{0}:{1}]:", remoteEP.Address, remoteEP.Port)); lock (syncLock) { Debug.WriteLine(string.Format("{0} Echoing [{1}] bytes", prefix, cbRecv)); } var udpSendBuf = Helper.Extract(udpRecvBuf, 0, cbRecv); udpSock.BeginSendTo(udpSendBuf, 0, cbRecv, SocketFlags.None, remoteEP, ar2 => { try { udpSock.EndSendTo(ar2); } catch (SocketClosedException) { return; } catch { // Ignore } }, null); if (UdpReceived != null) { UdpReceived(this, new NetReflectorEventArgs() { Endpoint = remoteEP, Data = udpSendBuf }); } udpSock.BeginReceiveFrom(udpRecvBuf, 0, udpRecvBuf.Length, SocketFlags.None, ref udpRemoteEP, onUdpReceive, null); } catch (SocketClosedException) { return; } catch (Exception e) { lock (syncLock) { Debug.WriteLine(string.Format("*** {0}: {1}", e.GetType().Name, e.Message)); } } }
/// <summary> /// Initiates the transmission of bytes from a buffer to the remote side of the connection. /// </summary> /// <param name="buffer">The source buffer.</param> /// <param name="offset">Index of the first byte to be transmitted.</param> /// <param name="count">Number of bytes to be transmitted.</param> /// <param name="callback">The delegate to be called when the operation completes (or <c>null</c>).</param> /// <param name="state">Application specific state.</param> /// <returns> /// An <see cref="IAsyncResult" /> instance to be used to track the progress of the /// operation and to eventually be passed to the <see cref="EndSend" /> method. /// </returns> /// <exception cref="InvalidOperationException">Thrown if the socket is not connected or if another send operation is already pending for TCP connections.</exception> /// <exception cref="ArgumentNullException">Thrown if <paramref name="buffer" /> is <c>null</c>.</exception> /// <exception cref="IndexOutOfRangeException">Thrown if <paramref name="offset" /> and <paramref name="count" /> specify bytes outside of the <paramref name="buffer" />.</exception> /// <remarks> /// <note> /// Only one send operation may be outstanding at a time for any TCP connections. Multiple sends /// may be in progress for UDP connections. /// </note> /// <note> /// For TCP connections, the send operation will continue until all bytes have been transmitted to the /// remote endpoint. For UDP connections, only a single packet with as many bytes as may be delivered /// by the underlying infrastructure will be send. /// </note> /// <note> /// All successful calls to <see cref="BeginSend" /> must eventually be followed by a call to <see cref="EndSend" />. /// </note> /// </remarks> public IAsyncResult BeginSend(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { if (buffer == null) { throw new ArgumentNullException("buffer"); } if (offset < 0 || count < 0 || offset + count > buffer.Length + 1) { throw new IndexOutOfRangeException(string.Format("[LiteSocket.Send: offset={0}] and [count={1}] is not valid for buffer of length [{2}].", offset, count, buffer.Length)); } lock (syncLock) { if (isTcp) { if (!Connected) { throw new InvalidOperationException("Socket is not connected."); } if (tcpSendPending) { throw new InvalidOperationException("LiteSocket.Send: Another send operation is already pending on this TCP socket."); } try { tcpSendPending = true; return(sock.BeginSend(buffer, offset, count, SocketFlags.None, callback, state)); } catch { tcpSendPending = false; throw; } } else { return(sock.BeginSendTo(buffer, offset, count, SocketFlags.None, udpRemoteEndPoint, callback, state)); } } }
/// <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 } } }